ETH Price: $2,423.66 (+7.61%)

Transaction Decoder

Block:
19296149 at Feb-24-2024 08:07:23 AM +UTC
Transaction Fee:
0.016884116217901217 ETH $40.92
Gas Used:
592,859 Gas / 28.479142963 Gwei

Emitted Events:

212 TransparentUpgradeableProxy.0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e( 0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 0000000000000000000000001c0720b124e7251e881a0fbcfe259d085c59f205 )
213 TransparentUpgradeableProxy.0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e( 0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 0000000000000000000000004bc16662a2ce381e7bb54dc577c05619c5e67526 )
214 TransparentUpgradeableProxy.0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e( 0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 0000000000000000000000004ca2191cde585d65eb6afc09d23d60b8a0ab677d )
215 TransparentUpgradeableProxy.0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e( 0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 00000000000000000000000059ce95b8955f0e7be128d5af77161b36f6084214 )
216 TransparentUpgradeableProxy.0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e( 0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 0000000000000000000000006436bbca322b8cd0c56d8b9ad7837b13960da426 )
217 TransparentUpgradeableProxy.0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e( 0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 00000000000000000000000083f81e7f9e284aaffeded797008663595f7342bf )
218 TransparentUpgradeableProxy.0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e( 0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 000000000000000000000000874f46124c1daad4749b94f82ed142754826240e )
219 TransparentUpgradeableProxy.0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e( 0xd4964a7cd99f5c1fa8f2420fb5e1d3bd26eadf16e2658cf2e29a67dfda38601e, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 000000000000000000000000bcf516826ed7f3b0e487c7ca6a87b3b4eccdd4dc )
220 TransparentUpgradeableProxy.0x2a6b4960c287d4d53a338f9c9a9f830f37e7b66e67a0a958f68be89a4eeb939d( 0x2a6b4960c287d4d53a338f9c9a9f830f37e7b66e67a0a958f68be89a4eeb939d, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875 )
221 DeBridgeTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000006d7a3177f3500bea64914642a49d0b5c0a7dae6d, 0000000000000000000000000000000000000000000000000053aea119096c00 )
222 DeBridgeTokenProxy.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x0000000000000000000000008a0c79f5532f3b2a16ad1e4282a5daf81928a824, 0x000000000000000000000000ef4fb24ad0916217251f553c0596f8edc630eb66, 0000000000000000000000000000000000000000000000000000000000000000 )
223 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, 0a7698f7b90ad7d4e822b7a666e417a2a510775dafc6f5a30ef392baa4bbe177, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 00000000000000000000000000000000000000000000000004b43de90a4b1b3c, 0000000000000000000000000000000000000000000000000000000000000000 )
224 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, 4bc53bb061111787c8ff1badb206a22c4da67f0e5cafb12e1715031cdb1f65dc, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 00000000000000000000000000000000000000000000000002c6422e477f0000, 0000000000000000000000000000000000000000000000000000000000000000 )
225 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, 4bc1dec96aec1b0f7eee3604ea6e8500200aef954747cb6b7f4f4c2ab59a6cb2, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 000000000000000000000000000000000000000000000000012d322b96b82954, 0000000000000000000000000000000000000000000000000000000000000000 )
226 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, 9ad74689f854ef85beab3ccdbefc76bad7762468fa804a24cad05bd95f8d34f7, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 000000000000000000000000000000000000000000000000006fc5afeff6f907, 0000000000000000000000000000000000000000000000000000000000000000 )
227 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, d14e7e53b356a632709afb89855c04384019b9cf407d507d18e87394b1dd362e, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 000000000000000000000000000000000000000000000000043554605d6ce7df, 0000000000000000000000000000000000000000000000000000000000000000 )
228 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, 3fa7b497b8d9880d51cf573912022793d72c7603e4763c9e91f1136be84d0a31, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 000000000000000000000000000000000000000000000000006ed86532fed15c, 0000000000000000000000000000000000000000000000000000000000000000 )
229 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, 32622083a570da8bacfd0ffddccc107fb6306d6e19a4c15c2f5dc939c7f5bf32, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 00000000000000000000000000000000000000000000000000d5de5fcffd3cad, 0000000000000000000000000000000000000000000000000000000000000000 )
230 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, 8e2484f8006172989280f2b9a966c70ccca31774a3914d5c5a48ab8d3c5a237f, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 000000000000000000000000000000000000000000000000003bcd49ac3dc94d, 0000000000000000000000000000000000000000000000000000000000000000 )
231 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, 141640bdf5dd16f9cd34b276a8817885b28417b993b648d93c0691802a5b359d, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 0000000000000000000000000000000000000000000000000de876d9c0eb18b4, 0000000000000000000000000000000000000000000000000000000000000000 )
232 TransparentUpgradeableProxy.0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f( 0x33fff3d864e92b6e1ef9e830196fc019c946104ea621b833aaebd3c3e84b2f6f, c2e4fdc05d183de74d00f4f381fdc8814a4b7a80ce191462de0f6a2554d35bf7, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 000000000000000000000000000000000000000000000000456eafa1a4932693, 0000000000000000000000000000000000000000000000000000000000000000 )
233 DeBridgeTokenProxy.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x0000000000000000000000008a0c79f5532f3b2a16ad1e4282a5daf81928a824, 0x000000000000000000000000ef4fb24ad0916217251f553c0596f8edc630eb66, 0000000000000000000000000000000000000000000000000000000000000000 )
234 TransparentUpgradeableProxy.0xb5fadd70c6860131059f49f37dff63a2b25d1df54e62d75c8327d896c0f7a0ad( 0xb5fadd70c6860131059f49f37dff63a2b25d1df54e62d75c8327d896c0f7a0ad, 0x0000000000000000000000000000000000000000000000000000000000000001, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 0000000000000000000000008a0c79f5532f3b2a16ad1e4282a5daf81928a824 )
235 TransparentUpgradeableProxy.0xe16b3d616e66789124fb71bf745a9a969a79906489c299e52e09686696152ef1( 0xe16b3d616e66789124fb71bf745a9a969a79906489c299e52e09686696152ef1, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 00000000000000000000000000000000000000000000000014b9063ca5d47a00, 00000000000000000000000000000000000000000000000014b9063ca5d47a00 )
236 TransparentUpgradeableProxy.0xfee5cae6d86f128037e90fc8d24296e73ad402bd6f6f09098589d528c2e14ad2( 0xfee5cae6d86f128037e90fc8d24296e73ad402bd6f6f09098589d528c2e14ad2, 0xa27dbcd48527b17bca5d7f0de61a0325212d9244c0286b2d8a2e33f844f69812, 0x000000000000000000000000ef4fb24ad0916217251f553c0596f8edc630eb66, 0x000000000000000000000000000000000000000000000000000000000000000a, 1d17bac8db371247b2dbc001e6879cb1d991ad80beda76df60030b8f76bb5875, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000001a45, 00000000000000000000000000000000000000000000000000000000000000a0, 0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000000000000000002e0, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000053aea119096c00, 0000000000000000000000000000000000000000000000000000000000000006, 000000000000000000000000555ce236c0220695b68341bc48c68d52210cc35b, 00000000000000000000000000000000000000000000000000000000000000a0, 0000000000000000000000000000000000000000000000000000000000000280, 00000000000000000000000000000000000000000000000000000000000001a4, 6abd4ea700000000000000000000000000000000000000000000000000000000, 00000040000000000000000000000000555ce236c0220695b68341bc48c68d52, 210cc35b00000000000000000000000000000000000000000000000000000000, 0000000a0a7698f7b90ad7d4e822b7a666e417a2a510775dafc6f5a30ef392ba, a4bbe1774bc53bb061111787c8ff1badb206a22c4da67f0e5cafb12e1715031c, db1f65dc4bc1dec96aec1b0f7eee3604ea6e8500200aef954747cb6b7f4f4c2a, b59a6cb29ad74689f854ef85beab3ccdbefc76bad7762468fa804a24cad05bd9, 5f8d34f7d14e7e53b356a632709afb89855c04384019b9cf407d507d18e87394, b1dd362e3fa7b497b8d9880d51cf573912022793d72c7603e4763c9e91f1136b, e84d0a3132622083a570da8bacfd0ffddccc107fb6306d6e19a4c15c2f5dc939, c7f5bf328e2484f8006172989280f2b9a966c70ccca31774a3914d5c5a48ab8d, 3c5a237f141640bdf5dd16f9cd34b276a8817885b28417b993b648d93c069180, 2a5b359dc2e4fdc05d183de74d00f4f381fdc8814a4b7a80ce191462de0f6a25, 54d35bf700000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000014, e7351fd770a37282b91d153ee690b63579d6dd7f000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x43dE2d77...4f38398aA
(deBridgeGate)
0x4CEe4082...72CF053ff
0x555CE236...2210cC35b 11.544950111772588544 Eth18.616858119462843923 Eth7.071908007690255379
0x949b3B3c...46d9C8A8c
(beaverbuild)
10.365453086588445811 Eth10.365571658388445811 Eth0.0001185718
0xDe5CE22A...18399FEB7
0.227058312670024201 Eth
Nonce: 9342
0.210174196452122984 Eth
Nonce: 9343
0.016884116217901217
0xeF4fB24a...dc630EB66
(deBridge: DlnSource)
65.62355552993863611 Eth58.551647522248380731 Eth7.071908007690255379

Execution Trace

TransparentUpgradeableProxy.247e6dd3( )
  • 0x7800adc2bb17c2c2451dac4af24ca77f8a264ed7.247e6dd3( )
    • TransparentUpgradeableProxy.c280c905( )
      • DeBridgeGate.claim( _debridgeId=A27DBCD48527B17BCA5D7F0DE61A0325212D9244C0286B2D8A2E33F844F69812, _amount=0, _chainIdFrom=10, _receiver=0xeF4fB24aD0916217251F553c0596F8Edc630EB66, _nonce=6725, _signatures=0x2DAAA4BBF5A17AAB2B45EC0C188E430B774C4FE30293A11C326C3D63474B7AE86EB280376C981C6B7F5DE67B82B7F83F9B5E3C609B881D06A6B5254D27E520511BB77565DB0FD9A6B4F7B541C4F14CF061F75A0886C99E8280EDCB10A6F9E13FAE2FC18113422FFEF0A41E36CA5907B187D5DAC90EA0AA4F803A6C9B395F714C311C45424464369525E5C612D2561B4E42EA1064925D8C59C682032E777CCF132C253306FEF1375E8926EA11947628DF1AFC3E3C5A6EAC2BA5E774A9D3DC672A803F1B349C19F39CAA926B3C5B8DCE327333902A681F1C8D858F6F7046DB1162EA9B0978D0E05D4F11B7B5ED99A735B1BB1E58DA256486CB4D557F755FE8A12D01DB441B98BD67C2A3D2BA66FB5B8E03DD11C1AA7DA47641274D3E28B5408F7BBDDC4A5176561637C3C4F76C3BB9D9F0AE78E589F66CBFB4B9DB3FBE380EA4E953CDC1311BC173CA7F33A28F2D6E6E14CCF8A532C5D1E3B7FBDEE930025BEE6407B9E86F072E9F72378C9F70CD125529415EA3AFF1566CF9BE10A6A47DB569C184759928E71CB55D635C203EF2DB3445B22B3B8B4C823E40805A7DFBDC8EF8C82A13B3665F145125FBEAFB772F162D4DA7A66D225E0DE6D5D3E2A35D67DCB6F2EA68DECB96CC1BB976D63E40AD917D824C547CECBDC062B9B97F3ADCE2C0AB46A7999C1948B7FA45073A2D3DEAD2B9A186262ACCED478533A5137F29427959C8185EA65509C4481C566E41C498CAC34478A16C6722DE36B7361C71272D0D09901312C6F9D30DFB02287906C56FD749B120CEEFD61174D9A4616CC4F8563C88BDC5ACDB958C78E1E61CE441339D313CCAF45CB9CD8F057162966C0835739FBA1C9028C46E14EB0E60976D66E24CA0D891C1C70769D21BE95446EBDA1B1645D2043FDD700A66F33F2FFF1C178E10BD957D495FD9D810DBF42C5046622A3321C5599AE6F1C4D62C17F2C7480E89E2757C30F8AC89A33AFBF41910D01AAB95BA57371BA6A24CB61E32E5D9501B, _autoParams=0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000053AEA119096C000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000555CE236C0220695B68341BC48C68D52210CC35B00000000000000000000000000000000000000000000000000000000000000A0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000001A46ABD4EA70000000000000000000000000000000000000000000000000000000000000040000000000000000000000000555CE236C0220695B68341BC48C68D52210CC35B000000000000000000000000000000000000000000000000000000000000000A0A7698F7B90AD7D4E822B7A666E417A2A510775DAFC6F5A30EF392BAA4BBE1774BC53BB061111787C8FF1BADB206A22C4DA67F0E5CAFB12E1715031CDB1F65DC4BC1DEC96AEC1B0F7EEE3604EA6E8500200AEF954747CB6B7F4F4C2AB59A6CB29AD74689F854EF85BEAB3CCDBEFC76BAD7762468FA804A24CAD05BD95F8D34F7D14E7E53B356A632709AFB89855C04384019B9CF407D507D18E87394B1DD362E3FA7B497B8D9880D51CF573912022793D72C7603E4763C9E91F1136BE84D0A3132622083A570DA8BACFD0FFDDCCC107FB6306D6E19A4C15C2F5DC939C7F5BF328E2484F8006172989280F2B9A966C70CCCA31774A3914D5C5A48AB8D3C5A237F141640BDF5DD16F9CD34B276A8817885B28417B993B648D93C0691802A5B359DC2E4FDC05D183DE74D00F4F381FDC8814A4B7A80CE191462DE0F6A2554D35BF7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014E7351FD770A37282B91D153EE690B63579D6DD7F000000000000000000000000 )
        • TransparentUpgradeableProxy.965d0a64( )
          • SignatureVerifier.submit( _submissionId=1D17BAC8DB371247B2DBC001E6879CB1D991AD80BEDA76DF60030B8F76BB5875, _signatures=0x2DAAA4BBF5A17AAB2B45EC0C188E430B774C4FE30293A11C326C3D63474B7AE86EB280376C981C6B7F5DE67B82B7F83F9B5E3C609B881D06A6B5254D27E520511BB77565DB0FD9A6B4F7B541C4F14CF061F75A0886C99E8280EDCB10A6F9E13FAE2FC18113422FFEF0A41E36CA5907B187D5DAC90EA0AA4F803A6C9B395F714C311C45424464369525E5C612D2561B4E42EA1064925D8C59C682032E777CCF132C253306FEF1375E8926EA11947628DF1AFC3E3C5A6EAC2BA5E774A9D3DC672A803F1B349C19F39CAA926B3C5B8DCE327333902A681F1C8D858F6F7046DB1162EA9B0978D0E05D4F11B7B5ED99A735B1BB1E58DA256486CB4D557F755FE8A12D01DB441B98BD67C2A3D2BA66FB5B8E03DD11C1AA7DA47641274D3E28B5408F7BBDDC4A5176561637C3C4F76C3BB9D9F0AE78E589F66CBFB4B9DB3FBE380EA4E953CDC1311BC173CA7F33A28F2D6E6E14CCF8A532C5D1E3B7FBDEE930025BEE6407B9E86F072E9F72378C9F70CD125529415EA3AFF1566CF9BE10A6A47DB569C184759928E71CB55D635C203EF2DB3445B22B3B8B4C823E40805A7DFBDC8EF8C82A13B3665F145125FBEAFB772F162D4DA7A66D225E0DE6D5D3E2A35D67DCB6F2EA68DECB96CC1BB976D63E40AD917D824C547CECBDC062B9B97F3ADCE2C0AB46A7999C1948B7FA45073A2D3DEAD2B9A186262ACCED478533A5137F29427959C8185EA65509C4481C566E41C498CAC34478A16C6722DE36B7361C71272D0D09901312C6F9D30DFB02287906C56FD749B120CEEFD61174D9A4616CC4F8563C88BDC5ACDB958C78E1E61CE441339D313CCAF45CB9CD8F057162966C0835739FBA1C9028C46E14EB0E60976D66E24CA0D891C1C70769D21BE95446EBDA1B1645D2043FDD700A66F33F2FFF1C178E10BD957D495FD9D810DBF42C5046622A3321C5599AE6F1C4D62C17F2C7480E89E2757C30F8AC89A33AFBF41910D01AAB95BA57371BA6A24CB61E32E5D9501B, _excessConfirmations=0 )
            • Null: 0x000...001.43468f2a( )
            • Null: 0x000...001.43468f2a( )
            • Null: 0x000...001.43468f2a( )
            • Null: 0x000...001.43468f2a( )
            • Null: 0x000...001.43468f2a( )
            • Null: 0x000...001.43468f2a( )
            • Null: 0x000...001.43468f2a( )
            • Null: 0x000...001.43468f2a( )
            • DeBridgeTokenProxy.40c10f19( )
              • TransparentUpgradeableProxy.STATICCALL( )
                • DeBridgeTokenDeployer.DELEGATECALL( )
                • DeBridgeToken.mint( _receiver=0x6D7A3177f3500BEA64914642a49D0B5C0a7Dae6D, _amount=23554430000000000 )
                • TransparentUpgradeableProxy.b88c998b( )
                  • CallProxy.callERC20( _token=0x4CEe40827418A50A93c49940db8bF3472CF053ff, _reserveAddress=0x555CE236C0220695b68341bc48C68d52210cC35b, _receiver=0xeF4fB24aD0916217251F553c0596F8Edc630EB66, _data=0x6ABD4EA70000000000000000000000000000000000000000000000000000000000000040000000000000000000000000555CE236C0220695B68341BC48C68D52210CC35B000000000000000000000000000000000000000000000000000000000000000A0A7698F7B90AD7D4E822B7A666E417A2A510775DAFC6F5A30EF392BAA4BBE1774BC53BB061111787C8FF1BADB206A22C4DA67F0E5CAFB12E1715031CDB1F65DC4BC1DEC96AEC1B0F7EEE3604EA6E8500200AEF954747CB6B7F4F4C2AB59A6CB29AD74689F854EF85BEAB3CCDBEFC76BAD7762468FA804A24CAD05BD95F8D34F7D14E7E53B356A632709AFB89855C04384019B9CF407D507D18E87394B1DD362E3FA7B497B8D9880D51CF573912022793D72C7603E4763C9E91F1136BE84D0A3132622083A570DA8BACFD0FFDDCCC107FB6306D6E19A4C15C2F5DC939C7F5BF328E2484F8006172989280F2B9A966C70CCCA31774A3914D5C5A48AB8D3C5A237F141640BDF5DD16F9CD34B276A8817885B28417B993B648D93C0691802A5B359DC2E4FDC05D183DE74D00F4F381FDC8814A4B7A80CE191462DE0F6A2554D35BF7, _flags=6, _nativeSender=0xE7351FD770A37282B91D153EE690B63579D6DD7F, _chainIdFrom=10 ) => ( _result=True )
                    • DeBridgeTokenProxy.70a08231( )
                    • DeBridgeTokenProxy.095ea7b3( )
                    • TransparentUpgradeableProxy.6abd4ea7( )
                    • DeBridgeTokenProxy.70a08231( )
                    • DeBridgeTokenProxy.095ea7b3( )
                    • DeBridgeTokenProxy.STATICCALL( )
                      • TransparentUpgradeableProxy.STATICCALL( )
                        • DeBridgeTokenDeployer.DELEGATECALL( )
                        • DeBridgeToken.DELEGATECALL( )
                          File 1 of 12: TransparentUpgradeableProxy
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
                          // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
                          contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
                              constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../Proxy.sol";
                          import "./ERC1967Upgrade.sol";
                          /**
                           * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                           * implementation address that can be changed. This address is stored in storage in the location specified by
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                           * implementation behind the proxy.
                           */
                          contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                              /**
                               * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                               *
                               * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                               * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                               */
                              constructor(address _logic, bytes memory _data) payable {
                                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                                  _upgradeToAndCall(_logic, _data, false);
                              }
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _implementation() internal view virtual override returns (address impl) {
                                  return ERC1967Upgrade._getImplementation();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Proxy.sol";
                          /**
                           * @dev This contract implements a proxy that is upgradeable by an admin.
                           *
                           * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
                           * clashing], which can potentially be used in an attack, this contract uses the
                           * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
                           * things that go hand in hand:
                           *
                           * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
                           * that call matches one of the admin functions exposed by the proxy itself.
                           * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
                           * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
                           * "admin cannot fallback to proxy target".
                           *
                           * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
                           * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
                           * to sudden errors when trying to call a function from the proxy implementation.
                           *
                           * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
                           * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
                           */
                          contract TransparentUpgradeableProxy is ERC1967Proxy {
                              /**
                               * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                               * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                               */
                              constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                                  assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                                  _changeAdmin(admin_);
                              }
                              /**
                               * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                               */
                              modifier ifAdmin() {
                                  if (msg.sender == _getAdmin()) {
                                      _;
                                  } else {
                                      _fallback();
                                  }
                              }
                              /**
                               * @dev Returns the current admin.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                               */
                              function admin() external ifAdmin returns (address admin_) {
                                  admin_ = _getAdmin();
                              }
                              /**
                               * @dev Returns the current implementation.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                               */
                              function implementation() external ifAdmin returns (address implementation_) {
                                  implementation_ = _implementation();
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                               */
                              function changeAdmin(address newAdmin) external virtual ifAdmin {
                                  _changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                               */
                              function upgradeTo(address newImplementation) external ifAdmin {
                                  _upgradeToAndCall(newImplementation, bytes(""), false);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                               * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                               * proxied contract.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                               */
                              function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                                  _upgradeToAndCall(newImplementation, data, true);
                              }
                              /**
                               * @dev Returns the current admin.
                               */
                              function _admin() internal view virtual returns (address) {
                                  return _getAdmin();
                              }
                              /**
                               * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                               */
                              function _beforeFallback() internal virtual override {
                                  require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                                  super._beforeFallback();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./TransparentUpgradeableProxy.sol";
                          import "../../access/Ownable.sol";
                          /**
                           * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
                           * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
                           */
                          contract ProxyAdmin is Ownable {
                              /**
                               * @dev Returns the current implementation of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("implementation()")) == 0x5c60da1b
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Returns the current admin of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("admin()")) == 0xf851a440
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Changes the admin of `proxy` to `newAdmin`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the current admin of `proxy`.
                               */
                              function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                                  proxy.changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                                  proxy.upgradeTo(implementation);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
                               * {TransparentUpgradeableProxy-upgradeToAndCall}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                                  proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                           * be specified by overriding the virtual {_implementation} function.
                           *
                           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                           * different contract through the {_delegate} function.
                           *
                           * The success and return data of the delegated call will be returned back to the caller of the proxy.
                           */
                          abstract contract Proxy {
                              /**
                               * @dev Delegates the current call to `implementation`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _delegate(address implementation) internal virtual {
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly {
                                      // Copy msg.data. We take full control of memory in this inline assembly
                                      // block because it will not return to Solidity code. We overwrite the
                                      // Solidity scratch pad at memory position 0.
                                      calldatacopy(0, 0, calldatasize())
                                      // Call the implementation.
                                      // out and outsize are 0 because we don't know the size yet.
                                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                      // Copy the returned data.
                                      returndatacopy(0, 0, returndatasize())
                                      switch result
                                      // delegatecall returns 0 on error.
                                      case 0 { revert(0, returndatasize()) }
                                      default { return(0, returndatasize()) }
                                  }
                              }
                              /**
                               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                               * and {_fallback} should delegate.
                               */
                              function _implementation() internal view virtual returns (address);
                              /**
                               * @dev Delegates the current call to the address returned by `_implementation()`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _fallback() internal virtual {
                                  _beforeFallback();
                                  _delegate(_implementation());
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                               * function in the contract matches the call data.
                               */
                              fallback () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                               * is empty.
                               */
                              receive () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                               * call, or as part of the Solidity `fallback` or `receive` functions.
                               *
                               * If overriden should call `super._beforeFallback()`.
                               */
                              function _beforeFallback() internal virtual {
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "../beacon/IBeacon.sol";
                          import "../../utils/Address.sol";
                          import "../../utils/StorageSlot.sol";
                          /**
                           * @dev This abstract contract provides getters and event emitting update functions for
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                           *
                           * _Available since v4.1._
                           *
                           * @custom:oz-upgrades-unsafe-allow delegatecall
                           */
                          abstract contract ERC1967Upgrade {
                              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                              /**
                               * @dev Storage slot with the address of the current implementation.
                               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                              /**
                               * @dev Emitted when the implementation is upgraded.
                               */
                              event Upgraded(address indexed implementation);
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _getImplementation() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 implementation slot.
                               */
                              function _setImplementation(address newImplementation) private {
                                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                              }
                              /**
                               * @dev Perform implementation upgrade
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeTo(address newImplementation) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                              /**
                               * @dev Perform implementation upgrade with additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                              }
                              /**
                               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                                  address oldImplementation = _getImplementation();
                                  // Initial upgrade and setup call
                                  _setImplementation(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                                  // Perform rollback test if not already in progress
                                  StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                                  if (!rollbackTesting.value) {
                                      // Trigger rollback using upgradeTo from the new implementation
                                      rollbackTesting.value = true;
                                      Address.functionDelegateCall(
                                          newImplementation,
                                          abi.encodeWithSignature(
                                              "upgradeTo(address)",
                                              oldImplementation
                                          )
                                      );
                                      rollbackTesting.value = false;
                                      // Check rollback was effective
                                      require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                      // Finally reset to the new implementation and log the upgrade
                                      _setImplementation(newImplementation);
                                      emit Upgraded(newImplementation);
                                  }
                              }
                              /**
                               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                               *
                               * Emits a {BeaconUpgraded} event.
                               */
                              function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                                  _setBeacon(newBeacon);
                                  emit BeaconUpgraded(newBeacon);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                                  }
                              }
                              /**
                               * @dev Storage slot with the admin of the contract.
                               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                              /**
                               * @dev Emitted when the admin account has changed.
                               */
                              event AdminChanged(address previousAdmin, address newAdmin);
                              /**
                               * @dev Returns the current admin.
                               */
                              function _getAdmin() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 admin slot.
                               */
                              function _setAdmin(address newAdmin) private {
                                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               */
                              function _changeAdmin(address newAdmin) internal {
                                  emit AdminChanged(_getAdmin(), newAdmin);
                                  _setAdmin(newAdmin);
                              }
                              /**
                               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                               */
                              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                              /**
                               * @dev Emitted when the beacon is upgraded.
                               */
                              event BeaconUpgraded(address indexed beacon);
                              /**
                               * @dev Returns the current beacon.
                               */
                              function _getBeacon() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                              }
                              /**
                               * @dev Stores a new beacon in the EIP1967 beacon slot.
                               */
                              function _setBeacon(address newBeacon) private {
                                  require(
                                      Address.isContract(newBeacon),
                                      "ERC1967: new beacon is not a contract"
                                  );
                                  require(
                                      Address.isContract(IBeacon(newBeacon).implementation()),
                                      "ERC1967: beacon implementation is not a contract"
                                  );
                                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is the interface that {BeaconProxy} expects of its beacon.
                           */
                          interface IBeacon {
                              /**
                               * @dev Must return an address that can be used as a delegate call target.
                               *
                               * {BeaconProxy} will check that this address is a contract.
                               */
                              function implementation() external view returns (address);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library Address {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly { size := extcodesize(account) }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                                  (bool success, ) = recipient.call{ value: amount }("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain`call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  require(isContract(target), "Address: delegate call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.delegatecall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          // solhint-disable-next-line no-inline-assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Library for reading and writing primitive types to specific storage slots.
                           *
                           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                           * This library helps with reading and writing to such slots without the need for inline assembly.
                           *
                           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                           *
                           * Example usage to set ERC1967 implementation slot:
                           * ```
                           * contract ERC1967 {
                           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                           *
                           *     function _getImplementation() internal view returns (address) {
                           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                           *     }
                           *
                           *     function _setImplementation(address newImplementation) internal {
                           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                           *     }
                           * }
                           * ```
                           *
                           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                           */
                          library StorageSlot {
                              struct AddressSlot {
                                  address value;
                              }
                              struct BooleanSlot {
                                  bool value;
                              }
                              struct Bytes32Slot {
                                  bytes32 value;
                              }
                              struct Uint256Slot {
                                  uint256 value;
                              }
                              /**
                               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                               */
                              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                               */
                              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                               */
                              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                               */
                              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../utils/Context.sol";
                          /**
                           * @dev Contract module which provides a basic access control mechanism, where
                           * there is an account (an owner) that can be granted exclusive access to
                           * specific functions.
                           *
                           * By default, the owner account will be the one that deploys the contract. This
                           * can later be changed with {transferOwnership}.
                           *
                           * This module is used through inheritance. It will make available the modifier
                           * `onlyOwner`, which can be applied to your functions to restrict their use to
                           * the owner.
                           */
                          abstract contract Ownable is Context {
                              address private _owner;
                              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                              /**
                               * @dev Initializes the contract setting the deployer as the initial owner.
                               */
                              constructor () {
                                  address msgSender = _msgSender();
                                  _owner = msgSender;
                                  emit OwnershipTransferred(address(0), msgSender);
                              }
                              /**
                               * @dev Returns the address of the current owner.
                               */
                              function owner() public view virtual returns (address) {
                                  return _owner;
                              }
                              /**
                               * @dev Throws if called by any account other than the owner.
                               */
                              modifier onlyOwner() {
                                  require(owner() == _msgSender(), "Ownable: caller is not the owner");
                                  _;
                              }
                              /**
                               * @dev 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.
                               */
                              function renounceOwnership() public virtual onlyOwner {
                                  emit OwnershipTransferred(_owner, address(0));
                                  _owner = address(0);
                              }
                              /**
                               * @dev Transfers ownership of the contract to a new account (`newOwner`).
                               * Can only be called by the current owner.
                               */
                              function transferOwnership(address newOwner) public virtual onlyOwner {
                                  require(newOwner != address(0), "Ownable: new owner is the zero address");
                                  emit OwnershipTransferred(_owner, newOwner);
                                  _owner = newOwner;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /*
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract Context {
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                                  return msg.data;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Upgrade.sol";
                          /**
                           * @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes
                           * publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify
                           * continuation of the upgradability.
                           *
                           * The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism.
                           *
                           * _Available since v4.1._
                           */
                          abstract contract UUPSUpgradeable is ERC1967Upgrade {
                              function upgradeTo(address newImplementation) external virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, bytes(""), false);
                              }
                              function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, data, true);
                              }
                              function _authorizeUpgrade(address newImplementation) internal virtual;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
                          abstract contract Proxiable is UUPSUpgradeable {
                              function _authorizeUpgrade(address newImplementation) internal override {
                                  _beforeUpgrade(newImplementation);
                              }
                              function _beforeUpgrade(address newImplementation) internal virtual;
                          }
                          contract ChildOfProxiable is Proxiable {
                              function _beforeUpgrade(address newImplementation) internal virtual override {}
                          }
                          

                          File 2 of 12: TransparentUpgradeableProxy
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
                          // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
                          contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
                              constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../Proxy.sol";
                          import "./ERC1967Upgrade.sol";
                          /**
                           * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                           * implementation address that can be changed. This address is stored in storage in the location specified by
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                           * implementation behind the proxy.
                           */
                          contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                              /**
                               * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                               *
                               * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                               * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                               */
                              constructor(address _logic, bytes memory _data) payable {
                                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                                  _upgradeToAndCall(_logic, _data, false);
                              }
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _implementation() internal view virtual override returns (address impl) {
                                  return ERC1967Upgrade._getImplementation();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Proxy.sol";
                          /**
                           * @dev This contract implements a proxy that is upgradeable by an admin.
                           *
                           * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
                           * clashing], which can potentially be used in an attack, this contract uses the
                           * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
                           * things that go hand in hand:
                           *
                           * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
                           * that call matches one of the admin functions exposed by the proxy itself.
                           * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
                           * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
                           * "admin cannot fallback to proxy target".
                           *
                           * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
                           * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
                           * to sudden errors when trying to call a function from the proxy implementation.
                           *
                           * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
                           * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
                           */
                          contract TransparentUpgradeableProxy is ERC1967Proxy {
                              /**
                               * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                               * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                               */
                              constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                                  assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                                  _changeAdmin(admin_);
                              }
                              /**
                               * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                               */
                              modifier ifAdmin() {
                                  if (msg.sender == _getAdmin()) {
                                      _;
                                  } else {
                                      _fallback();
                                  }
                              }
                              /**
                               * @dev Returns the current admin.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                               */
                              function admin() external ifAdmin returns (address admin_) {
                                  admin_ = _getAdmin();
                              }
                              /**
                               * @dev Returns the current implementation.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                               */
                              function implementation() external ifAdmin returns (address implementation_) {
                                  implementation_ = _implementation();
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                               */
                              function changeAdmin(address newAdmin) external virtual ifAdmin {
                                  _changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                               */
                              function upgradeTo(address newImplementation) external ifAdmin {
                                  _upgradeToAndCall(newImplementation, bytes(""), false);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                               * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                               * proxied contract.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                               */
                              function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                                  _upgradeToAndCall(newImplementation, data, true);
                              }
                              /**
                               * @dev Returns the current admin.
                               */
                              function _admin() internal view virtual returns (address) {
                                  return _getAdmin();
                              }
                              /**
                               * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                               */
                              function _beforeFallback() internal virtual override {
                                  require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                                  super._beforeFallback();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./TransparentUpgradeableProxy.sol";
                          import "../../access/Ownable.sol";
                          /**
                           * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
                           * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
                           */
                          contract ProxyAdmin is Ownable {
                              /**
                               * @dev Returns the current implementation of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("implementation()")) == 0x5c60da1b
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Returns the current admin of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("admin()")) == 0xf851a440
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Changes the admin of `proxy` to `newAdmin`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the current admin of `proxy`.
                               */
                              function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                                  proxy.changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                                  proxy.upgradeTo(implementation);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
                               * {TransparentUpgradeableProxy-upgradeToAndCall}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                                  proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                           * be specified by overriding the virtual {_implementation} function.
                           *
                           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                           * different contract through the {_delegate} function.
                           *
                           * The success and return data of the delegated call will be returned back to the caller of the proxy.
                           */
                          abstract contract Proxy {
                              /**
                               * @dev Delegates the current call to `implementation`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _delegate(address implementation) internal virtual {
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly {
                                      // Copy msg.data. We take full control of memory in this inline assembly
                                      // block because it will not return to Solidity code. We overwrite the
                                      // Solidity scratch pad at memory position 0.
                                      calldatacopy(0, 0, calldatasize())
                                      // Call the implementation.
                                      // out and outsize are 0 because we don't know the size yet.
                                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                      // Copy the returned data.
                                      returndatacopy(0, 0, returndatasize())
                                      switch result
                                      // delegatecall returns 0 on error.
                                      case 0 { revert(0, returndatasize()) }
                                      default { return(0, returndatasize()) }
                                  }
                              }
                              /**
                               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                               * and {_fallback} should delegate.
                               */
                              function _implementation() internal view virtual returns (address);
                              /**
                               * @dev Delegates the current call to the address returned by `_implementation()`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _fallback() internal virtual {
                                  _beforeFallback();
                                  _delegate(_implementation());
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                               * function in the contract matches the call data.
                               */
                              fallback () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                               * is empty.
                               */
                              receive () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                               * call, or as part of the Solidity `fallback` or `receive` functions.
                               *
                               * If overriden should call `super._beforeFallback()`.
                               */
                              function _beforeFallback() internal virtual {
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "../beacon/IBeacon.sol";
                          import "../../utils/Address.sol";
                          import "../../utils/StorageSlot.sol";
                          /**
                           * @dev This abstract contract provides getters and event emitting update functions for
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                           *
                           * _Available since v4.1._
                           *
                           * @custom:oz-upgrades-unsafe-allow delegatecall
                           */
                          abstract contract ERC1967Upgrade {
                              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                              /**
                               * @dev Storage slot with the address of the current implementation.
                               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                              /**
                               * @dev Emitted when the implementation is upgraded.
                               */
                              event Upgraded(address indexed implementation);
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _getImplementation() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 implementation slot.
                               */
                              function _setImplementation(address newImplementation) private {
                                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                              }
                              /**
                               * @dev Perform implementation upgrade
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeTo(address newImplementation) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                              /**
                               * @dev Perform implementation upgrade with additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                              }
                              /**
                               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                                  address oldImplementation = _getImplementation();
                                  // Initial upgrade and setup call
                                  _setImplementation(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                                  // Perform rollback test if not already in progress
                                  StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                                  if (!rollbackTesting.value) {
                                      // Trigger rollback using upgradeTo from the new implementation
                                      rollbackTesting.value = true;
                                      Address.functionDelegateCall(
                                          newImplementation,
                                          abi.encodeWithSignature(
                                              "upgradeTo(address)",
                                              oldImplementation
                                          )
                                      );
                                      rollbackTesting.value = false;
                                      // Check rollback was effective
                                      require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                      // Finally reset to the new implementation and log the upgrade
                                      _setImplementation(newImplementation);
                                      emit Upgraded(newImplementation);
                                  }
                              }
                              /**
                               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                               *
                               * Emits a {BeaconUpgraded} event.
                               */
                              function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                                  _setBeacon(newBeacon);
                                  emit BeaconUpgraded(newBeacon);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                                  }
                              }
                              /**
                               * @dev Storage slot with the admin of the contract.
                               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                              /**
                               * @dev Emitted when the admin account has changed.
                               */
                              event AdminChanged(address previousAdmin, address newAdmin);
                              /**
                               * @dev Returns the current admin.
                               */
                              function _getAdmin() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 admin slot.
                               */
                              function _setAdmin(address newAdmin) private {
                                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               */
                              function _changeAdmin(address newAdmin) internal {
                                  emit AdminChanged(_getAdmin(), newAdmin);
                                  _setAdmin(newAdmin);
                              }
                              /**
                               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                               */
                              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                              /**
                               * @dev Emitted when the beacon is upgraded.
                               */
                              event BeaconUpgraded(address indexed beacon);
                              /**
                               * @dev Returns the current beacon.
                               */
                              function _getBeacon() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                              }
                              /**
                               * @dev Stores a new beacon in the EIP1967 beacon slot.
                               */
                              function _setBeacon(address newBeacon) private {
                                  require(
                                      Address.isContract(newBeacon),
                                      "ERC1967: new beacon is not a contract"
                                  );
                                  require(
                                      Address.isContract(IBeacon(newBeacon).implementation()),
                                      "ERC1967: beacon implementation is not a contract"
                                  );
                                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is the interface that {BeaconProxy} expects of its beacon.
                           */
                          interface IBeacon {
                              /**
                               * @dev Must return an address that can be used as a delegate call target.
                               *
                               * {BeaconProxy} will check that this address is a contract.
                               */
                              function implementation() external view returns (address);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library Address {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly { size := extcodesize(account) }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                                  (bool success, ) = recipient.call{ value: amount }("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain`call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  require(isContract(target), "Address: delegate call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.delegatecall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          // solhint-disable-next-line no-inline-assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Library for reading and writing primitive types to specific storage slots.
                           *
                           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                           * This library helps with reading and writing to such slots without the need for inline assembly.
                           *
                           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                           *
                           * Example usage to set ERC1967 implementation slot:
                           * ```
                           * contract ERC1967 {
                           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                           *
                           *     function _getImplementation() internal view returns (address) {
                           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                           *     }
                           *
                           *     function _setImplementation(address newImplementation) internal {
                           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                           *     }
                           * }
                           * ```
                           *
                           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                           */
                          library StorageSlot {
                              struct AddressSlot {
                                  address value;
                              }
                              struct BooleanSlot {
                                  bool value;
                              }
                              struct Bytes32Slot {
                                  bytes32 value;
                              }
                              struct Uint256Slot {
                                  uint256 value;
                              }
                              /**
                               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                               */
                              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                               */
                              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                               */
                              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                               */
                              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../utils/Context.sol";
                          /**
                           * @dev Contract module which provides a basic access control mechanism, where
                           * there is an account (an owner) that can be granted exclusive access to
                           * specific functions.
                           *
                           * By default, the owner account will be the one that deploys the contract. This
                           * can later be changed with {transferOwnership}.
                           *
                           * This module is used through inheritance. It will make available the modifier
                           * `onlyOwner`, which can be applied to your functions to restrict their use to
                           * the owner.
                           */
                          abstract contract Ownable is Context {
                              address private _owner;
                              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                              /**
                               * @dev Initializes the contract setting the deployer as the initial owner.
                               */
                              constructor () {
                                  address msgSender = _msgSender();
                                  _owner = msgSender;
                                  emit OwnershipTransferred(address(0), msgSender);
                              }
                              /**
                               * @dev Returns the address of the current owner.
                               */
                              function owner() public view virtual returns (address) {
                                  return _owner;
                              }
                              /**
                               * @dev Throws if called by any account other than the owner.
                               */
                              modifier onlyOwner() {
                                  require(owner() == _msgSender(), "Ownable: caller is not the owner");
                                  _;
                              }
                              /**
                               * @dev 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.
                               */
                              function renounceOwnership() public virtual onlyOwner {
                                  emit OwnershipTransferred(_owner, address(0));
                                  _owner = address(0);
                              }
                              /**
                               * @dev Transfers ownership of the contract to a new account (`newOwner`).
                               * Can only be called by the current owner.
                               */
                              function transferOwnership(address newOwner) public virtual onlyOwner {
                                  require(newOwner != address(0), "Ownable: new owner is the zero address");
                                  emit OwnershipTransferred(_owner, newOwner);
                                  _owner = newOwner;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /*
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract Context {
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                                  return msg.data;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Upgrade.sol";
                          /**
                           * @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes
                           * publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify
                           * continuation of the upgradability.
                           *
                           * The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism.
                           *
                           * _Available since v4.1._
                           */
                          abstract contract UUPSUpgradeable is ERC1967Upgrade {
                              function upgradeTo(address newImplementation) external virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, bytes(""), false);
                              }
                              function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, data, true);
                              }
                              function _authorizeUpgrade(address newImplementation) internal virtual;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
                          abstract contract Proxiable is UUPSUpgradeable {
                              function _authorizeUpgrade(address newImplementation) internal override {
                                  _beforeUpgrade(newImplementation);
                              }
                              function _beforeUpgrade(address newImplementation) internal virtual;
                          }
                          contract ChildOfProxiable is Proxiable {
                              function _beforeUpgrade(address newImplementation) internal virtual override {}
                          }
                          

                          File 3 of 12: DeBridgeTokenProxy
                          // SPDX-License-Identifier: BUSL-1.1
                          pragma solidity 0.8.7;
                          import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
                          /// @dev This contract implements a proxy that gets the implementation address for each call
                          /// from DeBridgeTokenDeployer. It's deployed by DeBridgeTokenDeployer.
                          /// Implementation is DeBridgeToken.
                          contract DeBridgeTokenProxy is BeaconProxy {
                              constructor(address beacon, bytes memory data) BeaconProxy(beacon, data) {
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (proxy/beacon/BeaconProxy.sol)
                          pragma solidity ^0.8.0;
                          import "./IBeacon.sol";
                          import "../Proxy.sol";
                          import "../ERC1967/ERC1967Upgrade.sol";
                          /**
                           * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}.
                           *
                           * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
                           * conflict with the storage layout of the implementation behind the proxy.
                           *
                           * _Available since v3.4._
                           */
                          contract BeaconProxy is Proxy, ERC1967Upgrade {
                              /**
                               * @dev Initializes the proxy with `beacon`.
                               *
                               * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
                               * will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity
                               * constructor.
                               *
                               * Requirements:
                               *
                               * - `beacon` must be a contract with the interface {IBeacon}.
                               */
                              constructor(address beacon, bytes memory data) payable {
                                  assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1));
                                  _upgradeBeaconToAndCall(beacon, data, false);
                              }
                              /**
                               * @dev Returns the current beacon address.
                               */
                              function _beacon() internal view virtual returns (address) {
                                  return _getBeacon();
                              }
                              /**
                               * @dev Returns the current implementation address of the associated beacon.
                               */
                              function _implementation() internal view virtual override returns (address) {
                                  return IBeacon(_getBeacon()).implementation();
                              }
                              /**
                               * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.
                               *
                               * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
                               *
                               * Requirements:
                               *
                               * - `beacon` must be a contract.
                               * - The implementation returned by `beacon` must be a contract.
                               */
                              function _setBeacon(address beacon, bytes memory data) internal virtual {
                                  _upgradeBeaconToAndCall(beacon, data, false);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (proxy/beacon/IBeacon.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is the interface that {BeaconProxy} expects of its beacon.
                           */
                          interface IBeacon {
                              /**
                               * @dev Must return an address that can be used as a delegate call target.
                               *
                               * {BeaconProxy} will check that this address is a contract.
                               */
                              function implementation() external view returns (address);
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (proxy/Proxy.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                           * be specified by overriding the virtual {_implementation} function.
                           *
                           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                           * different contract through the {_delegate} function.
                           *
                           * The success and return data of the delegated call will be returned back to the caller of the proxy.
                           */
                          abstract contract Proxy {
                              /**
                               * @dev Delegates the current call to `implementation`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _delegate(address implementation) internal virtual {
                                  assembly {
                                      // Copy msg.data. We take full control of memory in this inline assembly
                                      // block because it will not return to Solidity code. We overwrite the
                                      // Solidity scratch pad at memory position 0.
                                      calldatacopy(0, 0, calldatasize())
                                      // Call the implementation.
                                      // out and outsize are 0 because we don't know the size yet.
                                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                      // Copy the returned data.
                                      returndatacopy(0, 0, returndatasize())
                                      switch result
                                      // delegatecall returns 0 on error.
                                      case 0 {
                                          revert(0, returndatasize())
                                      }
                                      default {
                                          return(0, returndatasize())
                                      }
                                  }
                              }
                              /**
                               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                               * and {_fallback} should delegate.
                               */
                              function _implementation() internal view virtual returns (address);
                              /**
                               * @dev Delegates the current call to the address returned by `_implementation()`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _fallback() internal virtual {
                                  _beforeFallback();
                                  _delegate(_implementation());
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                               * function in the contract matches the call data.
                               */
                              fallback() external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                               * is empty.
                               */
                              receive() external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                               * call, or as part of the Solidity `fallback` or `receive` functions.
                               *
                               * If overriden should call `super._beforeFallback()`.
                               */
                              function _beforeFallback() internal virtual {}
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (proxy/ERC1967/ERC1967Upgrade.sol)
                          pragma solidity ^0.8.2;
                          import "../beacon/IBeacon.sol";
                          import "../../utils/Address.sol";
                          import "../../utils/StorageSlot.sol";
                          /**
                           * @dev This abstract contract provides getters and event emitting update functions for
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                           *
                           * _Available since v4.1._
                           *
                           * @custom:oz-upgrades-unsafe-allow delegatecall
                           */
                          abstract contract ERC1967Upgrade {
                              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                              /**
                               * @dev Storage slot with the address of the current implementation.
                               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                              /**
                               * @dev Emitted when the implementation is upgraded.
                               */
                              event Upgraded(address indexed implementation);
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _getImplementation() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 implementation slot.
                               */
                              function _setImplementation(address newImplementation) private {
                                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                              }
                              /**
                               * @dev Perform implementation upgrade
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeTo(address newImplementation) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                              /**
                               * @dev Perform implementation upgrade with additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCall(
                                  address newImplementation,
                                  bytes memory data,
                                  bool forceCall
                              ) internal {
                                  _upgradeTo(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                              }
                              /**
                               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCallSecure(
                                  address newImplementation,
                                  bytes memory data,
                                  bool forceCall
                              ) internal {
                                  address oldImplementation = _getImplementation();
                                  // Initial upgrade and setup call
                                  _setImplementation(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                                  // Perform rollback test if not already in progress
                                  StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                                  if (!rollbackTesting.value) {
                                      // Trigger rollback using upgradeTo from the new implementation
                                      rollbackTesting.value = true;
                                      Address.functionDelegateCall(
                                          newImplementation,
                                          abi.encodeWithSignature("upgradeTo(address)", oldImplementation)
                                      );
                                      rollbackTesting.value = false;
                                      // Check rollback was effective
                                      require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                      // Finally reset to the new implementation and log the upgrade
                                      _upgradeTo(newImplementation);
                                  }
                              }
                              /**
                               * @dev Storage slot with the admin of the contract.
                               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                              /**
                               * @dev Emitted when the admin account has changed.
                               */
                              event AdminChanged(address previousAdmin, address newAdmin);
                              /**
                               * @dev Returns the current admin.
                               */
                              function _getAdmin() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 admin slot.
                               */
                              function _setAdmin(address newAdmin) private {
                                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               */
                              function _changeAdmin(address newAdmin) internal {
                                  emit AdminChanged(_getAdmin(), newAdmin);
                                  _setAdmin(newAdmin);
                              }
                              /**
                               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                               */
                              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                              /**
                               * @dev Emitted when the beacon is upgraded.
                               */
                              event BeaconUpgraded(address indexed beacon);
                              /**
                               * @dev Returns the current beacon.
                               */
                              function _getBeacon() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                              }
                              /**
                               * @dev Stores a new beacon in the EIP1967 beacon slot.
                               */
                              function _setBeacon(address newBeacon) private {
                                  require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                                  require(
                                      Address.isContract(IBeacon(newBeacon).implementation()),
                                      "ERC1967: beacon implementation is not a contract"
                                  );
                                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                              }
                              /**
                               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                               *
                               * Emits a {BeaconUpgraded} event.
                               */
                              function _upgradeBeaconToAndCall(
                                  address newBeacon,
                                  bytes memory data,
                                  bool forceCall
                              ) internal {
                                  _setBeacon(newBeacon);
                                  emit BeaconUpgraded(newBeacon);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Address.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library Address {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  assembly {
                                      size := extcodesize(account)
                                  }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  (bool success, ) = recipient.call{value: amount}("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain `call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(
                                  address target,
                                  bytes memory data,
                                  uint256 value
                              ) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(
                                  address target,
                                  bytes memory data,
                                  uint256 value,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  (bool success, bytes memory returndata) = target.call{value: value}(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  require(isContract(target), "Address: delegate call to non-contract");
                                  (bool success, bytes memory returndata) = target.delegatecall(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                               * revert reason using the provided one.
                               *
                               * _Available since v4.3._
                               */
                              function verifyCallResult(
                                  bool success,
                                  bytes memory returndata,
                                  string memory errorMessage
                              ) internal pure returns (bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/StorageSlot.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Library for reading and writing primitive types to specific storage slots.
                           *
                           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                           * This library helps with reading and writing to such slots without the need for inline assembly.
                           *
                           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                           *
                           * Example usage to set ERC1967 implementation slot:
                           * ```
                           * contract ERC1967 {
                           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                           *
                           *     function _getImplementation() internal view returns (address) {
                           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                           *     }
                           *
                           *     function _setImplementation(address newImplementation) internal {
                           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                           *     }
                           * }
                           * ```
                           *
                           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                           */
                          library StorageSlot {
                              struct AddressSlot {
                                  address value;
                              }
                              struct BooleanSlot {
                                  bool value;
                              }
                              struct Bytes32Slot {
                                  bytes32 value;
                              }
                              struct Uint256Slot {
                                  uint256 value;
                              }
                              /**
                               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                               */
                              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                               */
                              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                               */
                              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                               */
                              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                          }
                          

                          File 4 of 12: TransparentUpgradeableProxy
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
                          import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
                          import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
                          // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
                          contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
                              constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./IBeacon.sol";
                          import "../Proxy.sol";
                          import "../ERC1967/ERC1967Upgrade.sol";
                          /**
                           * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}.
                           *
                           * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
                           * conflict with the storage layout of the implementation behind the proxy.
                           *
                           * _Available since v3.4._
                           */
                          contract BeaconProxy is Proxy, ERC1967Upgrade {
                              /**
                               * @dev Initializes the proxy with `beacon`.
                               *
                               * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
                               * will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity
                               * constructor.
                               *
                               * Requirements:
                               *
                               * - `beacon` must be a contract with the interface {IBeacon}.
                               */
                              constructor(address beacon, bytes memory data) payable {
                                  assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1));
                                  _upgradeBeaconToAndCall(beacon, data, false);
                              }
                              /**
                               * @dev Returns the current beacon address.
                               */
                              function _beacon() internal view virtual returns (address) {
                                  return _getBeacon();
                              }
                              /**
                               * @dev Returns the current implementation address of the associated beacon.
                               */
                              function _implementation() internal view virtual override returns (address) {
                                  return IBeacon(_getBeacon()).implementation();
                              }
                              /**
                               * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.
                               *
                               * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
                               *
                               * Requirements:
                               *
                               * - `beacon` must be a contract.
                               * - The implementation returned by `beacon` must be a contract.
                               */
                              function _setBeacon(address beacon, bytes memory data) internal virtual {
                                  _upgradeBeaconToAndCall(beacon, data, false);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./IBeacon.sol";
                          import "../../access/Ownable.sol";
                          import "../../utils/Address.sol";
                          /**
                           * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
                           * implementation contract, which is where they will delegate all function calls.
                           *
                           * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
                           */
                          contract UpgradeableBeacon is IBeacon, Ownable {
                              address private _implementation;
                              /**
                               * @dev Emitted when the implementation returned by the beacon is changed.
                               */
                              event Upgraded(address indexed implementation);
                              /**
                               * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the
                               * beacon.
                               */
                              constructor(address implementation_) {
                                  _setImplementation(implementation_);
                              }
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function implementation() public view virtual override returns (address) {
                                  return _implementation;
                              }
                              /**
                               * @dev Upgrades the beacon to a new implementation.
                               *
                               * Emits an {Upgraded} event.
                               *
                               * Requirements:
                               *
                               * - msg.sender must be the owner of the contract.
                               * - `newImplementation` must be a contract.
                               */
                              function upgradeTo(address newImplementation) public virtual onlyOwner {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                              /**
                               * @dev Sets the implementation contract address for this beacon
                               *
                               * Requirements:
                               *
                               * - `newImplementation` must be a contract.
                               */
                              function _setImplementation(address newImplementation) private {
                                  require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract");
                                  _implementation = newImplementation;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../Proxy.sol";
                          import "./ERC1967Upgrade.sol";
                          /**
                           * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                           * implementation address that can be changed. This address is stored in storage in the location specified by
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                           * implementation behind the proxy.
                           */
                          contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                              /**
                               * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                               *
                               * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                               * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                               */
                              constructor(address _logic, bytes memory _data) payable {
                                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                                  _upgradeToAndCall(_logic, _data, false);
                              }
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _implementation() internal view virtual override returns (address impl) {
                                  return ERC1967Upgrade._getImplementation();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Proxy.sol";
                          /**
                           * @dev This contract implements a proxy that is upgradeable by an admin.
                           *
                           * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
                           * clashing], which can potentially be used in an attack, this contract uses the
                           * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
                           * things that go hand in hand:
                           *
                           * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
                           * that call matches one of the admin functions exposed by the proxy itself.
                           * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
                           * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
                           * "admin cannot fallback to proxy target".
                           *
                           * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
                           * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
                           * to sudden errors when trying to call a function from the proxy implementation.
                           *
                           * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
                           * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
                           */
                          contract TransparentUpgradeableProxy is ERC1967Proxy {
                              /**
                               * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                               * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                               */
                              constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                                  assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                                  _changeAdmin(admin_);
                              }
                              /**
                               * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                               */
                              modifier ifAdmin() {
                                  if (msg.sender == _getAdmin()) {
                                      _;
                                  } else {
                                      _fallback();
                                  }
                              }
                              /**
                               * @dev Returns the current admin.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                               */
                              function admin() external ifAdmin returns (address admin_) {
                                  admin_ = _getAdmin();
                              }
                              /**
                               * @dev Returns the current implementation.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                               */
                              function implementation() external ifAdmin returns (address implementation_) {
                                  implementation_ = _implementation();
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                               */
                              function changeAdmin(address newAdmin) external virtual ifAdmin {
                                  _changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                               */
                              function upgradeTo(address newImplementation) external ifAdmin {
                                  _upgradeToAndCall(newImplementation, bytes(""), false);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                               * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                               * proxied contract.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                               */
                              function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                                  _upgradeToAndCall(newImplementation, data, true);
                              }
                              /**
                               * @dev Returns the current admin.
                               */
                              function _admin() internal view virtual returns (address) {
                                  return _getAdmin();
                              }
                              /**
                               * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                               */
                              function _beforeFallback() internal virtual override {
                                  require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                                  super._beforeFallback();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./TransparentUpgradeableProxy.sol";
                          import "../../access/Ownable.sol";
                          /**
                           * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
                           * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
                           */
                          contract ProxyAdmin is Ownable {
                              /**
                               * @dev Returns the current implementation of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("implementation()")) == 0x5c60da1b
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Returns the current admin of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("admin()")) == 0xf851a440
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Changes the admin of `proxy` to `newAdmin`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the current admin of `proxy`.
                               */
                              function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                                  proxy.changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                                  proxy.upgradeTo(implementation);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
                               * {TransparentUpgradeableProxy-upgradeToAndCall}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                                  proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is the interface that {BeaconProxy} expects of its beacon.
                           */
                          interface IBeacon {
                              /**
                               * @dev Must return an address that can be used as a delegate call target.
                               *
                               * {BeaconProxy} will check that this address is a contract.
                               */
                              function implementation() external view returns (address);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                           * be specified by overriding the virtual {_implementation} function.
                           *
                           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                           * different contract through the {_delegate} function.
                           *
                           * The success and return data of the delegated call will be returned back to the caller of the proxy.
                           */
                          abstract contract Proxy {
                              /**
                               * @dev Delegates the current call to `implementation`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _delegate(address implementation) internal virtual {
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly {
                                      // Copy msg.data. We take full control of memory in this inline assembly
                                      // block because it will not return to Solidity code. We overwrite the
                                      // Solidity scratch pad at memory position 0.
                                      calldatacopy(0, 0, calldatasize())
                                      // Call the implementation.
                                      // out and outsize are 0 because we don't know the size yet.
                                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                      // Copy the returned data.
                                      returndatacopy(0, 0, returndatasize())
                                      switch result
                                      // delegatecall returns 0 on error.
                                      case 0 { revert(0, returndatasize()) }
                                      default { return(0, returndatasize()) }
                                  }
                              }
                              /**
                               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                               * and {_fallback} should delegate.
                               */
                              function _implementation() internal view virtual returns (address);
                              /**
                               * @dev Delegates the current call to the address returned by `_implementation()`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _fallback() internal virtual {
                                  _beforeFallback();
                                  _delegate(_implementation());
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                               * function in the contract matches the call data.
                               */
                              fallback () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                               * is empty.
                               */
                              receive () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                               * call, or as part of the Solidity `fallback` or `receive` functions.
                               *
                               * If overriden should call `super._beforeFallback()`.
                               */
                              function _beforeFallback() internal virtual {
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "../beacon/IBeacon.sol";
                          import "../../utils/Address.sol";
                          import "../../utils/StorageSlot.sol";
                          /**
                           * @dev This abstract contract provides getters and event emitting update functions for
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                           *
                           * _Available since v4.1._
                           *
                           * @custom:oz-upgrades-unsafe-allow delegatecall
                           */
                          abstract contract ERC1967Upgrade {
                              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                              /**
                               * @dev Storage slot with the address of the current implementation.
                               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                              /**
                               * @dev Emitted when the implementation is upgraded.
                               */
                              event Upgraded(address indexed implementation);
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _getImplementation() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 implementation slot.
                               */
                              function _setImplementation(address newImplementation) private {
                                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                              }
                              /**
                               * @dev Perform implementation upgrade
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeTo(address newImplementation) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                              /**
                               * @dev Perform implementation upgrade with additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                              }
                              /**
                               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                                  address oldImplementation = _getImplementation();
                                  // Initial upgrade and setup call
                                  _setImplementation(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                                  // Perform rollback test if not already in progress
                                  StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                                  if (!rollbackTesting.value) {
                                      // Trigger rollback using upgradeTo from the new implementation
                                      rollbackTesting.value = true;
                                      Address.functionDelegateCall(
                                          newImplementation,
                                          abi.encodeWithSignature(
                                              "upgradeTo(address)",
                                              oldImplementation
                                          )
                                      );
                                      rollbackTesting.value = false;
                                      // Check rollback was effective
                                      require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                      // Finally reset to the new implementation and log the upgrade
                                      _setImplementation(newImplementation);
                                      emit Upgraded(newImplementation);
                                  }
                              }
                              /**
                               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                               *
                               * Emits a {BeaconUpgraded} event.
                               */
                              function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                                  _setBeacon(newBeacon);
                                  emit BeaconUpgraded(newBeacon);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                                  }
                              }
                              /**
                               * @dev Storage slot with the admin of the contract.
                               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                              /**
                               * @dev Emitted when the admin account has changed.
                               */
                              event AdminChanged(address previousAdmin, address newAdmin);
                              /**
                               * @dev Returns the current admin.
                               */
                              function _getAdmin() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 admin slot.
                               */
                              function _setAdmin(address newAdmin) private {
                                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               */
                              function _changeAdmin(address newAdmin) internal {
                                  emit AdminChanged(_getAdmin(), newAdmin);
                                  _setAdmin(newAdmin);
                              }
                              /**
                               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                               */
                              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                              /**
                               * @dev Emitted when the beacon is upgraded.
                               */
                              event BeaconUpgraded(address indexed beacon);
                              /**
                               * @dev Returns the current beacon.
                               */
                              function _getBeacon() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                              }
                              /**
                               * @dev Stores a new beacon in the EIP1967 beacon slot.
                               */
                              function _setBeacon(address newBeacon) private {
                                  require(
                                      Address.isContract(newBeacon),
                                      "ERC1967: new beacon is not a contract"
                                  );
                                  require(
                                      Address.isContract(IBeacon(newBeacon).implementation()),
                                      "ERC1967: beacon implementation is not a contract"
                                  );
                                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library Address {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly { size := extcodesize(account) }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                                  (bool success, ) = recipient.call{ value: amount }("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain`call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  require(isContract(target), "Address: delegate call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.delegatecall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          // solhint-disable-next-line no-inline-assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Library for reading and writing primitive types to specific storage slots.
                           *
                           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                           * This library helps with reading and writing to such slots without the need for inline assembly.
                           *
                           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                           *
                           * Example usage to set ERC1967 implementation slot:
                           * ```
                           * contract ERC1967 {
                           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                           *
                           *     function _getImplementation() internal view returns (address) {
                           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                           *     }
                           *
                           *     function _setImplementation(address newImplementation) internal {
                           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                           *     }
                           * }
                           * ```
                           *
                           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                           */
                          library StorageSlot {
                              struct AddressSlot {
                                  address value;
                              }
                              struct BooleanSlot {
                                  bool value;
                              }
                              struct Bytes32Slot {
                                  bytes32 value;
                              }
                              struct Uint256Slot {
                                  uint256 value;
                              }
                              /**
                               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                               */
                              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                               */
                              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                               */
                              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                               */
                              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../utils/Context.sol";
                          /**
                           * @dev Contract module which provides a basic access control mechanism, where
                           * there is an account (an owner) that can be granted exclusive access to
                           * specific functions.
                           *
                           * By default, the owner account will be the one that deploys the contract. This
                           * can later be changed with {transferOwnership}.
                           *
                           * This module is used through inheritance. It will make available the modifier
                           * `onlyOwner`, which can be applied to your functions to restrict their use to
                           * the owner.
                           */
                          abstract contract Ownable is Context {
                              address private _owner;
                              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                              /**
                               * @dev Initializes the contract setting the deployer as the initial owner.
                               */
                              constructor () {
                                  address msgSender = _msgSender();
                                  _owner = msgSender;
                                  emit OwnershipTransferred(address(0), msgSender);
                              }
                              /**
                               * @dev Returns the address of the current owner.
                               */
                              function owner() public view virtual returns (address) {
                                  return _owner;
                              }
                              /**
                               * @dev Throws if called by any account other than the owner.
                               */
                              modifier onlyOwner() {
                                  require(owner() == _msgSender(), "Ownable: caller is not the owner");
                                  _;
                              }
                              /**
                               * @dev 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.
                               */
                              function renounceOwnership() public virtual onlyOwner {
                                  emit OwnershipTransferred(_owner, address(0));
                                  _owner = address(0);
                              }
                              /**
                               * @dev Transfers ownership of the contract to a new account (`newOwner`).
                               * Can only be called by the current owner.
                               */
                              function transferOwnership(address newOwner) public virtual onlyOwner {
                                  require(newOwner != address(0), "Ownable: new owner is the zero address");
                                  emit OwnershipTransferred(_owner, newOwner);
                                  _owner = newOwner;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /*
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract Context {
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                                  return msg.data;
                              }
                          }
                          

                          File 5 of 12: TransparentUpgradeableProxy
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
                          // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
                          contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
                              constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../Proxy.sol";
                          import "./ERC1967Upgrade.sol";
                          /**
                           * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                           * implementation address that can be changed. This address is stored in storage in the location specified by
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                           * implementation behind the proxy.
                           */
                          contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                              /**
                               * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                               *
                               * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                               * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                               */
                              constructor(address _logic, bytes memory _data) payable {
                                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                                  _upgradeToAndCall(_logic, _data, false);
                              }
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _implementation() internal view virtual override returns (address impl) {
                                  return ERC1967Upgrade._getImplementation();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Proxy.sol";
                          /**
                           * @dev This contract implements a proxy that is upgradeable by an admin.
                           *
                           * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
                           * clashing], which can potentially be used in an attack, this contract uses the
                           * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
                           * things that go hand in hand:
                           *
                           * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
                           * that call matches one of the admin functions exposed by the proxy itself.
                           * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
                           * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
                           * "admin cannot fallback to proxy target".
                           *
                           * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
                           * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
                           * to sudden errors when trying to call a function from the proxy implementation.
                           *
                           * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
                           * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
                           */
                          contract TransparentUpgradeableProxy is ERC1967Proxy {
                              /**
                               * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                               * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                               */
                              constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                                  assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                                  _changeAdmin(admin_);
                              }
                              /**
                               * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                               */
                              modifier ifAdmin() {
                                  if (msg.sender == _getAdmin()) {
                                      _;
                                  } else {
                                      _fallback();
                                  }
                              }
                              /**
                               * @dev Returns the current admin.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                               */
                              function admin() external ifAdmin returns (address admin_) {
                                  admin_ = _getAdmin();
                              }
                              /**
                               * @dev Returns the current implementation.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                               */
                              function implementation() external ifAdmin returns (address implementation_) {
                                  implementation_ = _implementation();
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                               */
                              function changeAdmin(address newAdmin) external virtual ifAdmin {
                                  _changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                               */
                              function upgradeTo(address newImplementation) external ifAdmin {
                                  _upgradeToAndCall(newImplementation, bytes(""), false);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                               * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                               * proxied contract.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                               */
                              function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                                  _upgradeToAndCall(newImplementation, data, true);
                              }
                              /**
                               * @dev Returns the current admin.
                               */
                              function _admin() internal view virtual returns (address) {
                                  return _getAdmin();
                              }
                              /**
                               * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                               */
                              function _beforeFallback() internal virtual override {
                                  require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                                  super._beforeFallback();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./TransparentUpgradeableProxy.sol";
                          import "../../access/Ownable.sol";
                          /**
                           * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
                           * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
                           */
                          contract ProxyAdmin is Ownable {
                              /**
                               * @dev Returns the current implementation of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("implementation()")) == 0x5c60da1b
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Returns the current admin of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("admin()")) == 0xf851a440
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Changes the admin of `proxy` to `newAdmin`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the current admin of `proxy`.
                               */
                              function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                                  proxy.changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                                  proxy.upgradeTo(implementation);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
                               * {TransparentUpgradeableProxy-upgradeToAndCall}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                                  proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                           * be specified by overriding the virtual {_implementation} function.
                           *
                           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                           * different contract through the {_delegate} function.
                           *
                           * The success and return data of the delegated call will be returned back to the caller of the proxy.
                           */
                          abstract contract Proxy {
                              /**
                               * @dev Delegates the current call to `implementation`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _delegate(address implementation) internal virtual {
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly {
                                      // Copy msg.data. We take full control of memory in this inline assembly
                                      // block because it will not return to Solidity code. We overwrite the
                                      // Solidity scratch pad at memory position 0.
                                      calldatacopy(0, 0, calldatasize())
                                      // Call the implementation.
                                      // out and outsize are 0 because we don't know the size yet.
                                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                      // Copy the returned data.
                                      returndatacopy(0, 0, returndatasize())
                                      switch result
                                      // delegatecall returns 0 on error.
                                      case 0 { revert(0, returndatasize()) }
                                      default { return(0, returndatasize()) }
                                  }
                              }
                              /**
                               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                               * and {_fallback} should delegate.
                               */
                              function _implementation() internal view virtual returns (address);
                              /**
                               * @dev Delegates the current call to the address returned by `_implementation()`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _fallback() internal virtual {
                                  _beforeFallback();
                                  _delegate(_implementation());
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                               * function in the contract matches the call data.
                               */
                              fallback () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                               * is empty.
                               */
                              receive () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                               * call, or as part of the Solidity `fallback` or `receive` functions.
                               *
                               * If overriden should call `super._beforeFallback()`.
                               */
                              function _beforeFallback() internal virtual {
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "../beacon/IBeacon.sol";
                          import "../../utils/Address.sol";
                          import "../../utils/StorageSlot.sol";
                          /**
                           * @dev This abstract contract provides getters and event emitting update functions for
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                           *
                           * _Available since v4.1._
                           *
                           * @custom:oz-upgrades-unsafe-allow delegatecall
                           */
                          abstract contract ERC1967Upgrade {
                              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                              /**
                               * @dev Storage slot with the address of the current implementation.
                               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                              /**
                               * @dev Emitted when the implementation is upgraded.
                               */
                              event Upgraded(address indexed implementation);
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _getImplementation() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 implementation slot.
                               */
                              function _setImplementation(address newImplementation) private {
                                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                              }
                              /**
                               * @dev Perform implementation upgrade
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeTo(address newImplementation) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                              /**
                               * @dev Perform implementation upgrade with additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                              }
                              /**
                               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                                  address oldImplementation = _getImplementation();
                                  // Initial upgrade and setup call
                                  _setImplementation(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                                  // Perform rollback test if not already in progress
                                  StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                                  if (!rollbackTesting.value) {
                                      // Trigger rollback using upgradeTo from the new implementation
                                      rollbackTesting.value = true;
                                      Address.functionDelegateCall(
                                          newImplementation,
                                          abi.encodeWithSignature(
                                              "upgradeTo(address)",
                                              oldImplementation
                                          )
                                      );
                                      rollbackTesting.value = false;
                                      // Check rollback was effective
                                      require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                      // Finally reset to the new implementation and log the upgrade
                                      _setImplementation(newImplementation);
                                      emit Upgraded(newImplementation);
                                  }
                              }
                              /**
                               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                               *
                               * Emits a {BeaconUpgraded} event.
                               */
                              function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                                  _setBeacon(newBeacon);
                                  emit BeaconUpgraded(newBeacon);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                                  }
                              }
                              /**
                               * @dev Storage slot with the admin of the contract.
                               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                              /**
                               * @dev Emitted when the admin account has changed.
                               */
                              event AdminChanged(address previousAdmin, address newAdmin);
                              /**
                               * @dev Returns the current admin.
                               */
                              function _getAdmin() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 admin slot.
                               */
                              function _setAdmin(address newAdmin) private {
                                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               */
                              function _changeAdmin(address newAdmin) internal {
                                  emit AdminChanged(_getAdmin(), newAdmin);
                                  _setAdmin(newAdmin);
                              }
                              /**
                               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                               */
                              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                              /**
                               * @dev Emitted when the beacon is upgraded.
                               */
                              event BeaconUpgraded(address indexed beacon);
                              /**
                               * @dev Returns the current beacon.
                               */
                              function _getBeacon() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                              }
                              /**
                               * @dev Stores a new beacon in the EIP1967 beacon slot.
                               */
                              function _setBeacon(address newBeacon) private {
                                  require(
                                      Address.isContract(newBeacon),
                                      "ERC1967: new beacon is not a contract"
                                  );
                                  require(
                                      Address.isContract(IBeacon(newBeacon).implementation()),
                                      "ERC1967: beacon implementation is not a contract"
                                  );
                                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is the interface that {BeaconProxy} expects of its beacon.
                           */
                          interface IBeacon {
                              /**
                               * @dev Must return an address that can be used as a delegate call target.
                               *
                               * {BeaconProxy} will check that this address is a contract.
                               */
                              function implementation() external view returns (address);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library Address {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly { size := extcodesize(account) }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                                  (bool success, ) = recipient.call{ value: amount }("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain`call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  require(isContract(target), "Address: delegate call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.delegatecall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          // solhint-disable-next-line no-inline-assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Library for reading and writing primitive types to specific storage slots.
                           *
                           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                           * This library helps with reading and writing to such slots without the need for inline assembly.
                           *
                           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                           *
                           * Example usage to set ERC1967 implementation slot:
                           * ```
                           * contract ERC1967 {
                           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                           *
                           *     function _getImplementation() internal view returns (address) {
                           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                           *     }
                           *
                           *     function _setImplementation(address newImplementation) internal {
                           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                           *     }
                           * }
                           * ```
                           *
                           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                           */
                          library StorageSlot {
                              struct AddressSlot {
                                  address value;
                              }
                              struct BooleanSlot {
                                  bool value;
                              }
                              struct Bytes32Slot {
                                  bytes32 value;
                              }
                              struct Uint256Slot {
                                  uint256 value;
                              }
                              /**
                               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                               */
                              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                               */
                              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                               */
                              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                               */
                              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../utils/Context.sol";
                          /**
                           * @dev Contract module which provides a basic access control mechanism, where
                           * there is an account (an owner) that can be granted exclusive access to
                           * specific functions.
                           *
                           * By default, the owner account will be the one that deploys the contract. This
                           * can later be changed with {transferOwnership}.
                           *
                           * This module is used through inheritance. It will make available the modifier
                           * `onlyOwner`, which can be applied to your functions to restrict their use to
                           * the owner.
                           */
                          abstract contract Ownable is Context {
                              address private _owner;
                              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                              /**
                               * @dev Initializes the contract setting the deployer as the initial owner.
                               */
                              constructor () {
                                  address msgSender = _msgSender();
                                  _owner = msgSender;
                                  emit OwnershipTransferred(address(0), msgSender);
                              }
                              /**
                               * @dev Returns the address of the current owner.
                               */
                              function owner() public view virtual returns (address) {
                                  return _owner;
                              }
                              /**
                               * @dev Throws if called by any account other than the owner.
                               */
                              modifier onlyOwner() {
                                  require(owner() == _msgSender(), "Ownable: caller is not the owner");
                                  _;
                              }
                              /**
                               * @dev 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.
                               */
                              function renounceOwnership() public virtual onlyOwner {
                                  emit OwnershipTransferred(_owner, address(0));
                                  _owner = address(0);
                              }
                              /**
                               * @dev Transfers ownership of the contract to a new account (`newOwner`).
                               * Can only be called by the current owner.
                               */
                              function transferOwnership(address newOwner) public virtual onlyOwner {
                                  require(newOwner != address(0), "Ownable: new owner is the zero address");
                                  emit OwnershipTransferred(_owner, newOwner);
                                  _owner = newOwner;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /*
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract Context {
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                                  return msg.data;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Upgrade.sol";
                          /**
                           * @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes
                           * publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify
                           * continuation of the upgradability.
                           *
                           * The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism.
                           *
                           * _Available since v4.1._
                           */
                          abstract contract UUPSUpgradeable is ERC1967Upgrade {
                              function upgradeTo(address newImplementation) external virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, bytes(""), false);
                              }
                              function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, data, true);
                              }
                              function _authorizeUpgrade(address newImplementation) internal virtual;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
                          abstract contract Proxiable is UUPSUpgradeable {
                              function _authorizeUpgrade(address newImplementation) internal override {
                                  _beforeUpgrade(newImplementation);
                              }
                              function _beforeUpgrade(address newImplementation) internal virtual;
                          }
                          contract ChildOfProxiable is Proxiable {
                              function _beforeUpgrade(address newImplementation) internal virtual override {}
                          }
                          

                          File 6 of 12: DeBridgeGate
                          // SPDX-License-Identifier: BUSL-1.1
                          pragma solidity ^0.8.7;
                          import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
                          import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
                          import "../interfaces/IERC20Permit.sol";
                          import "../interfaces/IDeBridgeToken.sol";
                          import "../interfaces/IDeBridgeTokenDeployer.sol";
                          import "../interfaces/ISignatureVerifier.sol";
                          import "../interfaces/IWETH.sol";
                          import "../interfaces/IDeBridgeGate.sol";
                          import "../interfaces/ICallProxy.sol";
                          import "../libraries/SignatureUtil.sol";
                          import "../libraries/Flags.sol";
                          import "../interfaces/IWethGate.sol";
                          /// @dev Contract for assets transfers. The user can transfer the asset to any of the approved chains.
                          /// The admin manages the assets, fees and other important protocol parameters.
                          contract DeBridgeGate is
                              Initializable,
                              AccessControlUpgradeable,
                              PausableUpgradeable,
                              ReentrancyGuardUpgradeable,
                              IDeBridgeGate
                          {
                              using SafeERC20Upgradeable for IERC20Upgradeable;
                              using SignatureUtil for bytes;
                              using Flags for uint256;
                              /* ========== STATE VARIABLES ========== */
                              /// @dev Basis points or bps, set to 10 000 (equal to 1/10000). Used to express relative values (fees)
                              uint256 public constant BPS_DENOMINATOR = 10000;
                              /// @dev Role allowed to stop transfers
                              bytes32 public constant GOVMONITORING_ROLE = keccak256("GOVMONITORING_ROLE");
                              /// @dev prefix to calculation submissionId
                              uint256 public constant SUBMISSION_PREFIX = 1;
                              /// @dev prefix to calculation deployId
                              uint256 public constant DEPLOY_PREFIX = 2;
                              /// @dev Address of IDeBridgeTokenDeployer contract
                              address public deBridgeTokenDeployer;
                              /// @dev Current signature verifier address to verify signatures.
                              address public signatureVerifier;
                              /// @dev Minimal required confirmations in case sent amount is big, have no effect if less than SignatureVerifier.minConfirmations
                              uint8 public excessConfirmations;
                              /// @dev *obsolete flashFeeBps
                              uint256 public gap0;
                              /// @dev outgoing submissions count
                              uint256 public nonce;
                              /// @dev Maps debridgeId (see getDebridgeId) => bridge-specific information.
                              mapping(bytes32 => DebridgeInfo) public getDebridge;
                              /// @dev Maps debridgeId (see getDebridgeId) => fee information
                              mapping(bytes32 => DebridgeFeeInfo) public getDebridgeFeeInfo;
                              /// @dev Returns whether the transfer with the submissionId was claimed.
                              /// submissionId is generated in getSubmissionIdFrom
                              mapping(bytes32 => bool) public override isSubmissionUsed;
                              /// @dev Returns whether the transfer with the submissionId is blocked.
                              mapping(bytes32 => bool) public isBlockedSubmission;
                              /// @dev Maps debridgeId (see getDebridgeId) to threshold amount after which
                              /// Math.max(excessConfirmations,SignatureVerifier.minConfirmations) is used instead of
                              /// SignatureVerifier.minConfirmations
                              mapping(bytes32 => uint256) public getAmountThreshold;
                              /// @dev Whether the chain for the asset is supported to send
                              mapping(uint256 => ChainSupportInfo) public getChainToConfig;
                              /// @dev Whether the chain for the asset is supported to claim
                              mapping(uint256 => ChainSupportInfo) public getChainFromConfig;
                              /// @dev Fee discount for address
                              mapping(address => DiscountInfo) public feeDiscount;
                              /// @dev Returns native token info by wrapped token address
                              mapping(address => TokenInfo) public override getNativeInfo;
                              /// @dev *obsolete defiController
                              address public gap1;
                              /// @dev Returns proxy to convert the collected fees and transfer to Ethereum network to treasury
                              address public feeProxy;
                              /// @dev Returns address of the proxy to execute user's calls.
                              address public override callProxy;
                              /// @dev Returns contract for wrapped native token.
                              IWETH public weth;
                              /// @dev Contract address that can override globalFixedNativeFee
                              address public feeContractUpdater;
                              /// @dev Fallback fixed fee in native asset, used if a chain fixed fee is set to 0
                              uint256 public override globalFixedNativeFee;
                              /// @dev Fallback transfer fee in BPS, used if a chain transfer fee is set to 0
                              uint16 public override globalTransferFeeBps;
                              /// @dev WethGate contract, that is used for weth withdraws affected by EIP1884
                              IWethGate public wethGate;
                              /// @dev Locker for claim method
                              uint256 public lockedClaim;
                              /* ========== ERRORS ========== */
                              error FeeProxyBadRole();
                              error FeeContractUpdaterBadRole();
                              error AdminBadRole();
                              error GovMonitoringBadRole();
                              error DebridgeNotFound();
                              error WrongChainTo();
                              error WrongChainFrom();
                              error WrongArgument();
                              error WrongAutoArgument();
                              error TransferAmountTooHigh();
                              error NotSupportedFixedFee();
                              error TransferAmountNotCoverFees();
                              error InvalidTokenToSend();
                              error SubmissionUsed();
                              error SubmissionBlocked();
                              error AssetAlreadyExist();
                              error ZeroAddress();
                              error ProposedFeeTooHigh();
                              error NotEnoughReserves();
                              error EthTransferFailed();
                              /* ========== MODIFIERS ========== */
                              modifier onlyFeeProxy() {
                                  if (feeProxy != msg.sender) revert FeeProxyBadRole();
                                  _;
                              }
                              modifier onlyFeeContractUpdater() {
                                  if (feeContractUpdater != msg.sender) revert FeeContractUpdaterBadRole();
                                  _;
                              }
                              modifier onlyAdmin() {
                                  if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert AdminBadRole();
                                  _;
                              }
                              modifier onlyGovMonitoring() {
                                  if (!hasRole(GOVMONITORING_ROLE, msg.sender)) revert GovMonitoringBadRole();
                                  _;
                              }
                              /* ========== CONSTRUCTOR  ========== */
                              /// @custom:oz-upgrades-unsafe-allow constructor
                              constructor() initializer {
                              }
                              /// @dev Constructor that initializes the most important configurations.
                              /// @param _excessConfirmations minimal required confirmations in case of too many confirmations
                              /// @param _weth wrapped native token contract
                              function initialize(
                                  uint8 _excessConfirmations,
                                  IWETH _weth
                              ) public initializer {
                                  excessConfirmations = _excessConfirmations;
                                  weth = _weth;
                                  _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
                                  __ReentrancyGuard_init();
                              }
                              /* ========== send, claim ========== */
                              /// @inheritdoc IDeBridgeGate
                              function sendMessage(
                                  uint256 _chainIdTo,
                                  bytes memory _targetContractAddress,
                                  bytes memory _targetContractCalldata
                              ) external payable override returns (bytes32 submissionId) {
                                  uint flags = uint(0)
                                      .setFlag(Flags.REVERT_IF_EXTERNAL_FAIL, true)
                                      .setFlag(Flags.PROXY_WITH_SENDER, true);
                                  return sendMessage(_chainIdTo, _targetContractAddress, _targetContractCalldata, flags, 0);
                              }
                              /// @inheritdoc IDeBridgeGate
                              function sendMessage(
                                  uint256 _chainIdTo,
                                  bytes memory _targetContractAddress,
                                  bytes memory _targetContractCalldata,
                                  uint256 _flags,
                                  uint32 _referralCode
                              ) public payable override nonReentrant whenNotPaused
                                returns (bytes32 submissionId) {
                                  if (_targetContractAddress.length == 0 || _targetContractCalldata.length == 0) {
                                      revert WrongAutoArgument();
                                  }
                                  (uint256 amountAfterFee, bytes32 debridgeId, FeeParams memory feeParams) = _send(
                                      "", // _permitEnvelope
                                      address(0), // _token: we use native currency
                                      0, // _amount to be bridged is set to zero because all amount goes to the claimer as the execution fee
                                      _chainIdTo,
                                      false // useAssetFee
                                  );
                                  SubmissionAutoParamsTo memory autoParams;
                                  autoParams.executionFee = _normalizeTokenAmount(address(0), amountAfterFee);
                                  autoParams.flags = _flags;
                                  autoParams.fallbackAddress = _targetContractAddress;
                                  autoParams.data = _targetContractCalldata;
                                  return _publishSubmission(
                                      debridgeId,
                                      _chainIdTo,
                                      0, // _amount to be bridged is set to zero because all amount goes to the claimer as the execution fee
                                      _targetContractAddress,
                                      feeParams,
                                      _referralCode,
                                      autoParams,
                                      true // _hasAutoParams
                                  );
                              }
                              /// @inheritdoc IDeBridgeGate
                              function send(
                                  address _tokenAddress,
                                  uint256 _amount,
                                  uint256 _chainIdTo,
                                  bytes memory _receiver,
                                  bytes memory _permitEnvelope,
                                  bool _useAssetFee,
                                  uint32 _referralCode,
                                  bytes calldata _autoParams
                              ) external payable override nonReentrant whenNotPaused
                                returns (bytes32 submissionId) {
                                  bytes32 debridgeId;
                                  FeeParams memory feeParams;
                                  uint256 amountAfterFee;
                                  // the amount will be reduced by the protocol fee
                                  (amountAfterFee, debridgeId, feeParams) = _send(
                                      _permitEnvelope,
                                      _tokenAddress,
                                      _amount,
                                      _chainIdTo,
                                      _useAssetFee
                                  );
                                  SubmissionAutoParamsTo memory autoParams;
                                  // Validate Auto Params
                                  if (_autoParams.length > 0) {
                                      autoParams = abi.decode(_autoParams, (SubmissionAutoParamsTo));
                                      autoParams.executionFee = _normalizeTokenAmount(_tokenAddress, autoParams.executionFee);
                                      if (autoParams.executionFee > amountAfterFee) {
                                          autoParams.executionFee = _normalizeTokenAmount(_tokenAddress, amountAfterFee);
                                      }
                                      if (autoParams.data.length > 0 && autoParams.fallbackAddress.length == 0 ) revert WrongAutoArgument();
                                  }
                                  amountAfterFee -= autoParams.executionFee;
                                  // round down amount in order not to bridge dust
                                  amountAfterFee = _normalizeTokenAmount(_tokenAddress, amountAfterFee);
                                  return _publishSubmission(
                                      debridgeId,
                                      _chainIdTo,
                                      amountAfterFee,
                                      _receiver,
                                      feeParams,
                                      _referralCode,
                                      autoParams,
                                      _autoParams.length > 0
                                  );
                              }
                              /// @inheritdoc IDeBridgeGate
                              function claim(
                                  bytes32 _debridgeId,
                                  uint256 _amount,
                                  uint256 _chainIdFrom,
                                  address _receiver,
                                  uint256 _nonce,
                                  bytes calldata _signatures,
                                  bytes calldata _autoParams
                              ) external override whenNotPaused {
                                  if (!getChainFromConfig[_chainIdFrom].isSupported) revert WrongChainFrom();
                                  SubmissionAutoParamsFrom memory autoParams;
                                  if (_autoParams.length > 0) {
                                      autoParams = abi.decode(_autoParams, (SubmissionAutoParamsFrom));
                                  }
                                  bytes32 submissionId = getSubmissionIdFrom(
                                      _debridgeId,
                                      _chainIdFrom,
                                      _amount,
                                      _receiver,
                                      _nonce,
                                      autoParams,
                                      _autoParams.length > 0,
                                      msg.sender
                                  );
                                  // check if submission already claimed
                                  if (isSubmissionUsed[submissionId]) revert SubmissionUsed();
                                  isSubmissionUsed[submissionId] = true;
                                  _checkConfirmations(submissionId, _debridgeId, _amount, _signatures);
                                  bool isNativeToken =_claim(
                                      submissionId,
                                      _debridgeId,
                                      _receiver,
                                      _amount,
                                      _chainIdFrom,
                                      autoParams
                                  );
                                  emit Claimed(
                                      submissionId,
                                      _debridgeId,
                                      _amount,
                                      _receiver,
                                      _nonce,
                                      _chainIdFrom,
                                      _autoParams,
                                      isNativeToken
                                  );
                              }
                              /// @dev Deploy a deToken(DeBridgeTokenProxy) for an asset
                              /// @param _nativeTokenAddress A token address on a native chain
                              /// @param _nativeChainId The token native chain's id
                              /// @param _name The token's name
                              /// @param _symbol The token's symbol
                              /// @param _decimals The token's decimals
                              /// @param _signatures Validators' signatures
                              function deployNewAsset(
                                  bytes memory _nativeTokenAddress,
                                  uint256 _nativeChainId,
                                  string memory _name,
                                  string memory _symbol,
                                  uint8 _decimals,
                                  bytes memory _signatures
                              ) external nonReentrant whenNotPaused{
                                  bytes32 debridgeId = getbDebridgeId(_nativeChainId, _nativeTokenAddress);
                                  if (getDebridge[debridgeId].exist) revert AssetAlreadyExist();
                                  bytes32 deployId = getDeployId(debridgeId, _name, _symbol, _decimals);
                                  // verify signatures
                                  ISignatureVerifier(signatureVerifier).submit(deployId, _signatures, excessConfirmations);
                                  address deBridgeTokenAddress = IDeBridgeTokenDeployer(deBridgeTokenDeployer)
                                      .deployAsset(debridgeId, _name, _symbol, _decimals);
                                  _addAsset(debridgeId, deBridgeTokenAddress, _nativeTokenAddress, _nativeChainId);
                              }
                              /// @dev Update native fix fee. Called by our fee update contract
                              /// @param _globalFixedNativeFee  new value
                              function autoUpdateFixedNativeFee(
                                  uint256 _globalFixedNativeFee
                              ) external onlyFeeContractUpdater {
                                  globalFixedNativeFee = _globalFixedNativeFee;
                                  emit FixedNativeFeeAutoUpdated(_globalFixedNativeFee);
                              }
                              /* ========== ADMIN ========== */
                              /// @dev Update asset's fees.
                              /// @param _chainIds Chain identifiers.
                              /// @param _chainSupportInfo Chain support info.
                              /// @param _isChainFrom is true for editing getChainFromConfig.
                              function updateChainSupport(
                                  uint256[] memory _chainIds,
                                  ChainSupportInfo[] memory _chainSupportInfo,
                                  bool _isChainFrom
                              ) external onlyAdmin {
                                  if (_chainIds.length != _chainSupportInfo.length) revert WrongArgument();
                                  for (uint256 i = 0; i < _chainIds.length; i++) {
                                      if(_isChainFrom){
                                          getChainFromConfig[_chainIds[i]] = _chainSupportInfo[i];
                                      }
                                      else {
                                          getChainToConfig[_chainIds[i]] = _chainSupportInfo[i];
                                      }
                                      emit ChainsSupportUpdated(_chainIds[i], _chainSupportInfo[i], _isChainFrom);
                                  }
                              }
                              /// @dev Update fallbacks for fixed fee in native asset and transfer fee
                              /// @param _globalFixedNativeFee Fallback fixed fee in native asset, used if a chain fixed fee is set to 0
                              /// @param _globalTransferFeeBps Fallback transfer fee in BPS, used if a chain transfer fee is set to 0
                              function updateGlobalFee(
                                  uint256 _globalFixedNativeFee,
                                  uint16 _globalTransferFeeBps
                              ) external onlyAdmin {
                                  globalFixedNativeFee = _globalFixedNativeFee;
                                  globalTransferFeeBps = _globalTransferFeeBps;
                                  emit FixedNativeFeeUpdated(_globalFixedNativeFee, _globalTransferFeeBps);
                              }
                              /// @dev Update asset's fees.
                              /// @param _debridgeId Asset identifier.
                              /// @param _supportedChainIds Chain identifiers.
                              /// @param _assetFeesInfo Chain support info.
                              function updateAssetFixedFees(
                                  bytes32 _debridgeId,
                                  uint256[] memory _supportedChainIds,
                                  uint256[] memory _assetFeesInfo
                              ) external onlyAdmin {
                                  if (_supportedChainIds.length != _assetFeesInfo.length) revert WrongArgument();
                                  DebridgeFeeInfo storage debridgeFee = getDebridgeFeeInfo[_debridgeId];
                                  for (uint256 i = 0; i < _supportedChainIds.length; i++) {
                                      debridgeFee.getChainFee[_supportedChainIds[i]] = _assetFeesInfo[i];
                                  }
                              }
                              /// @dev Update minimal amount of required signatures, must be > SignatureVerifier.minConfirmations to have an effect
                              /// @param _excessConfirmations Minimal amount of required signatures
                              function updateExcessConfirmations(uint8 _excessConfirmations) external onlyAdmin {
                                  if (_excessConfirmations == 0) revert WrongArgument();
                                  excessConfirmations = _excessConfirmations;
                              }
                              /// @dev Set support for the chains where the token can be transferred.
                              /// @param _chainId Chain id where tokens are sent.
                              /// @param _isSupported Whether the token is transferable to the other chain.
                              /// @param _isChainFrom is true for editing getChainFromConfig.
                              function setChainSupport(uint256 _chainId, bool _isSupported, bool _isChainFrom) external onlyAdmin {
                                  if (_isChainFrom) {
                                      getChainFromConfig[_chainId].isSupported = _isSupported;
                                  }
                                  else {
                                      getChainToConfig[_chainId].isSupported = _isSupported;
                                  }
                                  emit ChainSupportUpdated(_chainId, _isSupported, _isChainFrom);
                              }
                              /// @dev Set address of the call proxy.
                              /// @param _callProxy Address of the proxy that executes external calls.
                              function setCallProxy(address _callProxy) external onlyAdmin {
                                  callProxy = _callProxy;
                                  emit CallProxyUpdated(_callProxy);
                              }
                              /// @dev Update specific asset's bridge parameters.
                              /// @param _debridgeId Asset identifier.
                              /// @param _maxAmount Maximum amount of current chain token to be wrapped.
                              /// @param _minReservesBps Minimal reserve ration in BPS.
                              /// @param _amountThreshold Threshold amount after which Math.max(excessConfirmations,SignatureVerifier.minConfirmations) is used instead of SignatureVerifier.minConfirmations
                              function updateAsset(
                                  bytes32 _debridgeId,
                                  uint256 _maxAmount,
                                  uint16 _minReservesBps,
                                  uint256 _amountThreshold
                              ) external onlyAdmin {
                                  if (_minReservesBps > BPS_DENOMINATOR) revert WrongArgument();
                                  DebridgeInfo storage debridge = getDebridge[_debridgeId];
                                  // don't check existence of debridge - it allows to setup asset before first transfer
                                  debridge.maxAmount = _maxAmount;
                                  debridge.minReservesBps = _minReservesBps;
                                  getAmountThreshold[_debridgeId] = _amountThreshold;
                              }
                              /// @dev Set signature verifier address.
                              /// @param _verifier Signature verifier address.
                              function setSignatureVerifier(address _verifier) external onlyAdmin {
                                  signatureVerifier = _verifier;
                              }
                              /// @dev Set asset deployer address.
                              /// @param _deBridgeTokenDeployer Asset deployer address.
                              function setDeBridgeTokenDeployer(address _deBridgeTokenDeployer) external onlyAdmin {
                                  deBridgeTokenDeployer = _deBridgeTokenDeployer;
                              }
                              /// @dev Set fee contract updater, that can update fix native fee
                              /// @param _value new contract address.
                              function setFeeContractUpdater(address _value) external onlyAdmin {
                                  feeContractUpdater = _value;
                              }
                              /// @dev Set wethGate contract, that uses for weth withdraws affected by EIP1884
                              /// @param _wethGate address of new wethGate contract.
                              function setWethGate(IWethGate _wethGate) external onlyAdmin {
                                  wethGate = _wethGate;
                              }
                              /// @dev Stop all transfers.
                              function pause() external onlyGovMonitoring {
                                  _pause();
                              }
                              /// @dev Allow transfers.
                              function unpause() external onlyAdmin {
                                  _unpause();
                              }
                              /// @inheritdoc IDeBridgeGate
                              function withdrawFee(bytes32 _debridgeId) external override nonReentrant onlyFeeProxy {
                                  DebridgeFeeInfo storage debridgeFee = getDebridgeFeeInfo[_debridgeId];
                                  // Amount for transfer to treasury
                                  uint256 amount = debridgeFee.collectedFees - debridgeFee.withdrawnFees;
                                  if (amount == 0) revert NotEnoughReserves();
                                  debridgeFee.withdrawnFees += amount;
                                  if (_debridgeId == getDebridgeId(getChainId(), address(0))) {
                                      _safeTransferETH(feeProxy, amount);
                                  } else {
                                      // don't need this check as we check that amount is not zero
                                      // if (!getDebridge[_debridgeId].exist) revert DebridgeNotFound();
                                      IERC20Upgradeable(getDebridge[_debridgeId].tokenAddress).safeTransfer(feeProxy, amount);
                                  }
                                  emit WithdrawnFee(_debridgeId, amount);
                              }
                              /// @dev Set fee converter proxy.
                              /// @param _feeProxy Fee proxy address.
                              function setFeeProxy(address _feeProxy) external onlyAdmin {
                                  feeProxy = _feeProxy;
                              }
                              /// @dev Block or unblock a list of submissions
                              /// @param _submissionIds Ids of submissions to block/unblock
                              /// @param isBlocked True to block, false to unblock
                              function blockSubmission(bytes32[] memory _submissionIds, bool isBlocked) external onlyAdmin {
                                  for (uint256 i = 0; i < _submissionIds.length; i++) {
                                      isBlockedSubmission[_submissionIds[i]] = isBlocked;
                                      if (isBlocked) {
                                          emit Blocked(_submissionIds[i]);
                                      } else {
                                          emit Unblocked(_submissionIds[i]);
                                      }
                                  }
                              }
                              /// @dev Update discount.
                              /// @param _address customer address
                              /// @param _discountFixBps  fix discount in BPS
                              /// @param _discountTransferBps transfer % discount in BPS
                              function updateFeeDiscount(
                                  address _address,
                                  uint16 _discountFixBps,
                                  uint16 _discountTransferBps
                              ) external onlyAdmin {
                                  if (_address == address(0) ||
                                      _discountFixBps > BPS_DENOMINATOR ||
                                      _discountTransferBps > BPS_DENOMINATOR
                                  ) revert WrongArgument();
                                  DiscountInfo storage discountInfo = feeDiscount[_address];
                                  discountInfo.discountFixBps = _discountFixBps;
                                  discountInfo.discountTransferBps = _discountTransferBps;
                              }
                              // we need to accept ETH sends to unwrap WETH
                              receive() external payable {
                                  // assert(msg.sender == address(weth)); // only accept ETH via fallback from the WETH contract
                              }
                              /* ========== INTERNAL ========== */
                              function _checkConfirmations(
                                  bytes32 _submissionId,
                                  bytes32 _debridgeId,
                                  uint256 _amount,
                                  bytes calldata _signatures
                              ) internal {
                                  if (isBlockedSubmission[_submissionId]) revert SubmissionBlocked();
                                  // inside check is confirmed
                                  ISignatureVerifier(signatureVerifier).submit(
                                      _submissionId,
                                      _signatures,
                                      _amount >= getAmountThreshold[_debridgeId] ? excessConfirmations : 0
                                  );
                              }
                              /// @dev Add support for the asset.
                              /// @param _debridgeId Asset identifier.
                              /// @param _tokenAddress Address of the asset on the current chain.
                              /// @param _nativeAddress Address of the asset on the native chain.
                              /// @param _nativeChainId Native chain id.
                              function _addAsset(
                                  bytes32 _debridgeId,
                                  address _tokenAddress,
                                  bytes memory _nativeAddress,
                                  uint256 _nativeChainId
                              ) internal {
                                  DebridgeInfo storage debridge = getDebridge[_debridgeId];
                                  if (debridge.exist) revert AssetAlreadyExist();
                                  if (_tokenAddress == address(0)) revert ZeroAddress();
                                  debridge.exist = true;
                                  debridge.tokenAddress = _tokenAddress;
                                  debridge.chainId = _nativeChainId;
                                  // Don't override if the admin already set maxAmount in updateAsset method before
                                  if (debridge.maxAmount == 0) {
                                      debridge.maxAmount = type(uint256).max;
                                  }
                                  // set minReservesBps to 100% to prevent using new asset by DeFiController by default
                                  debridge.minReservesBps = uint16(BPS_DENOMINATOR);
                                  if (getAmountThreshold[_debridgeId] == 0) {
                                      getAmountThreshold[_debridgeId] = type(uint256).max;
                                  }
                                  TokenInfo storage tokenInfo = getNativeInfo[_tokenAddress];
                                  tokenInfo.nativeChainId = _nativeChainId;
                                  tokenInfo.nativeAddress = _nativeAddress;
                                  emit PairAdded(
                                      _debridgeId,
                                      _tokenAddress,
                                      _nativeAddress,
                                      _nativeChainId,
                                      debridge.maxAmount,
                                      debridge.minReservesBps
                                  );
                              }
                              /// @dev Locks asset on the chain and enables minting on the other chain.
                              /// @param _amount Amount to be transferred (note: the fee can be applied).
                              /// @param _chainIdTo Chain id of the target chain.
                              /// @param _permitEnvelope Permit for approving the spender by signature. bytes (amount + deadline + signature)
                              function _send(
                                  bytes memory _permitEnvelope,
                                  address _tokenAddress,
                                  uint256 _amount,
                                  uint256 _chainIdTo,
                                  bool _useAssetFee
                              ) internal returns (
                                  uint256 amountAfterFee,
                                  bytes32 debridgeId,
                                  FeeParams memory feeParams
                              ) {
                                  _validateToken(_tokenAddress);
                                  // Run _permit first. Avoid Stack too deep
                                  if (_permitEnvelope.length > 0) {
                                      // call permit before transferring token
                                      uint256 permitAmount = _permitEnvelope.toUint256(0);
                                      uint256 deadline = _permitEnvelope.toUint256(32);
                                      (bytes32 r, bytes32 s, uint8 v) = _permitEnvelope.parseSignature(64);
                                      IERC20Permit(_tokenAddress).permit(
                                          msg.sender,
                                          address(this),
                                          permitAmount,
                                          deadline,
                                          v,
                                          r,
                                          s);
                                  }
                                  TokenInfo memory nativeTokenInfo = getNativeInfo[_tokenAddress];
                                  bool isNativeToken = nativeTokenInfo.nativeChainId  == 0
                                      ? true // token not in mapping
                                      : nativeTokenInfo.nativeChainId == getChainId(); // token native chain id the same
                                  if (isNativeToken) {
                                      //We use WETH debridgeId for transfer ETH
                                      debridgeId = getDebridgeId(
                                          getChainId(),
                                          _tokenAddress == address(0) ? address(weth) : _tokenAddress
                                      );
                                  }
                                  else {
                                      debridgeId = getbDebridgeId(
                                          nativeTokenInfo.nativeChainId,
                                          nativeTokenInfo.nativeAddress
                                      );
                                  }
                                  DebridgeInfo storage debridge = getDebridge[debridgeId];
                                  if (!debridge.exist) {
                                      if (isNativeToken) {
                                          // Use WETH as a token address for native tokens
                                          address assetAddress = _tokenAddress == address(0) ? address(weth) : _tokenAddress;
                                          _addAsset(
                                              debridgeId,
                                              assetAddress,
                                              abi.encodePacked(assetAddress),
                                              getChainId()
                                          );
                                      } else revert DebridgeNotFound();
                                  }
                                  ChainSupportInfo memory chainFees = getChainToConfig[_chainIdTo];
                                  if (!chainFees.isSupported) revert WrongChainTo();
                                  if (_tokenAddress == address(0)) {
                                      // use msg.value as amount for native tokens
                                      _amount = msg.value;
                                      weth.deposit{value: _amount}();
                                      _useAssetFee = true;
                                  } else {
                                      IERC20Upgradeable token = IERC20Upgradeable(_tokenAddress);
                                      uint256 balanceBefore = token.balanceOf(address(this));
                                      token.safeTransferFrom(msg.sender, address(this), _amount);
                                      // Received real amount
                                      _amount = token.balanceOf(address(this)) - balanceBefore;
                                  }
                                  if (_amount > debridge.maxAmount) revert TransferAmountTooHigh();
                                  //_processFeeForTransfer
                                  {
                                      DiscountInfo memory discountInfo = feeDiscount[msg.sender];
                                      DebridgeFeeInfo storage debridgeFee = getDebridgeFeeInfo[debridgeId];
                                      // calculate fixed fee
                                      uint256 assetsFixedFee;
                                      if (_useAssetFee) {
                                          if (_tokenAddress == address(0)) {
                                              // collect asset fixed fee (in weth) for native token transfers
                                              assetsFixedFee = chainFees.fixedNativeFee == 0 ? globalFixedNativeFee : chainFees.fixedNativeFee;
                                          } else {
                                              // collect asset fixed fee for non native token transfers
                                              assetsFixedFee = debridgeFee.getChainFee[_chainIdTo];
                                              if (assetsFixedFee == 0) revert NotSupportedFixedFee();
                                          }
                                          // Apply discount for a asset fixed fee
                                          assetsFixedFee = _applyDiscount(assetsFixedFee, discountInfo.discountFixBps);
                                          if (_amount < assetsFixedFee) revert TransferAmountNotCoverFees();
                                          feeParams.fixFee = assetsFixedFee;
                                      } else {
                                          // collect fixed native fee for non native token transfers
                                          // use globalFixedNativeFee if value for chain is not set
                                          uint256 nativeFee = chainFees.fixedNativeFee == 0 ? globalFixedNativeFee : chainFees.fixedNativeFee;
                                          // Apply discount for a native fixed fee
                                          nativeFee = _applyDiscount(nativeFee, discountInfo.discountFixBps);
                                          if (msg.value < nativeFee) revert TransferAmountNotCoverFees();
                                          else if (msg.value > nativeFee) {
                                              // refund extra fee eth
                                               _safeTransferETH(msg.sender, msg.value - nativeFee);
                                          }
                                          bytes32 nativeDebridgeId = getDebridgeId(getChainId(), address(0));
                                          getDebridgeFeeInfo[nativeDebridgeId].collectedFees += nativeFee;
                                          feeParams.fixFee = nativeFee;
                                      }
                                      // Calculate transfer fee
                                      // use globalTransferFeeBps if value for chain is not set
                                      uint256 transferFee = (chainFees.transferFeeBps == 0
                                          ? globalTransferFeeBps : chainFees.transferFeeBps)
                                          * (_amount - assetsFixedFee) / BPS_DENOMINATOR;
                                      // apply discount for a transfer fee
                                      transferFee = _applyDiscount(transferFee, discountInfo.discountTransferBps);
                                      uint256 totalFee = transferFee + assetsFixedFee;
                                      if (_amount < totalFee) revert TransferAmountNotCoverFees();
                                      debridgeFee.collectedFees += totalFee;
                                      amountAfterFee = _amount - totalFee;
                                      // initialize feeParams
                                      feeParams.transferFee = transferFee;
                                      feeParams.useAssetFee = _useAssetFee;
                                      feeParams.receivedAmount = _amount;
                                      feeParams.isNativeToken = isNativeToken;
                                  }
                                  if (isNativeToken) {
                                      debridge.balance += amountAfterFee;
                                  }
                                  else {
                                      debridge.balance -= amountAfterFee;
                                      IDeBridgeToken(debridge.tokenAddress).burn(amountAfterFee);
                                  }
                                  return (amountAfterFee, debridgeId, feeParams);
                              }
                              function _publishSubmission(
                                  bytes32 _debridgeId,
                                  uint256 _chainIdTo,
                                  uint256 _amount,
                                  bytes memory _receiver,
                                  FeeParams memory feeParams,
                                  uint32 _referralCode,
                                  SubmissionAutoParamsTo memory autoParams,
                                  bool hasAutoParams
                              ) internal returns (bytes32 submissionId) {
                                  bytes memory packedSubmission = abi.encodePacked(
                                      SUBMISSION_PREFIX,
                                      _debridgeId,
                                      getChainId(),
                                      _chainIdTo,
                                      _amount,
                                      _receiver,
                                      nonce
                                  );
                                  if (hasAutoParams) {
                                      bool isHashedData = autoParams.flags.getFlag(Flags.SEND_HASHED_DATA);
                                      if (isHashedData && autoParams.data.length != 32) revert WrongAutoArgument();
                                      // auto submission
                                      submissionId = keccak256(
                                          abi.encodePacked(
                                              packedSubmission,
                                              autoParams.executionFee,
                                              autoParams.flags,
                                              keccak256(autoParams.fallbackAddress),
                                              isHashedData ? autoParams.data : abi.encodePacked(keccak256(autoParams.data)),
                                              keccak256(abi.encodePacked(msg.sender))
                                          )
                                      );
                                  }
                                  // regular submission
                                  else {
                                      submissionId = keccak256(packedSubmission);
                                  }
                                  emit Sent(
                                      submissionId,
                                      _debridgeId,
                                      _amount,
                                      _receiver,
                                      nonce,
                                      _chainIdTo,
                                      _referralCode,
                                      feeParams,
                                      hasAutoParams ? abi.encode(autoParams): bytes(""),
                                      msg.sender
                                  );
                                  {
                                      emit MonitoringSendEvent(
                                          submissionId,
                                          nonce,
                                          getDebridge[_debridgeId].balance,
                                          IERC20Upgradeable(getDebridge[_debridgeId].tokenAddress).totalSupply()
                                      );
                                  }
                                  nonce++;
                              }
                              function _applyDiscount(
                                  uint256 amount,
                                  uint16 discountBps
                              ) internal pure returns (uint256) {
                                  return amount - amount * discountBps / BPS_DENOMINATOR;
                              }
                              function _validateToken(address _token) internal {
                                  if (_token == address(0)) {
                                      // no validation for native tokens
                                      return;
                                  }
                                  // check existence of decimals method
                                  (bool success, ) = _token.call(abi.encodeWithSignature("decimals()"));
                                  if (!success) revert InvalidTokenToSend();
                                  // check existence of symbol method
                                  (success, ) = _token.call(abi.encodeWithSignature("symbol()"));
                                  if (!success) revert InvalidTokenToSend();
                              }
                              /// @dev Unlock the asset on the current chain and transfer to receiver.
                              /// @param _debridgeId Asset identifier.
                              /// @param _receiver Receiver address.
                              /// @param _amount Amount of the transfered asset (note: the fee can be applyed).
                              function _claim(
                                  bytes32 _submissionId,
                                  bytes32 _debridgeId,
                                  address _receiver,
                                  uint256 _amount,
                                  uint256 _chainIdFrom,
                                  SubmissionAutoParamsFrom memory _autoParams
                              ) internal returns (bool isNativeToken) {
                                  DebridgeInfo storage debridge = getDebridge[_debridgeId];
                                  if (!debridge.exist) revert DebridgeNotFound();
                                  isNativeToken = debridge.chainId == getChainId();
                                  if (isNativeToken) {
                                      debridge.balance -= _amount + _autoParams.executionFee;
                                  } else {
                                      debridge.balance += _amount + _autoParams.executionFee;
                                  }
                                  address _token = debridge.tokenAddress;
                                  bool unwrapETH = isNativeToken
                                      && _autoParams.flags.getFlag(Flags.UNWRAP_ETH)
                                      && _token == address(weth);
                                  if (_autoParams.executionFee > 0) {
                                      _mintOrTransfer(_token, msg.sender, _autoParams.executionFee, isNativeToken);
                                  }
                                  if (_autoParams.data.length > 0) {
                                      // use local variable to reduce gas usage
                                      address _callProxy = callProxy;
                                      bool status;
                                      if (unwrapETH) {
                                          // withdraw weth to callProxy directly
                                          _withdrawWeth(_callProxy, _amount);
                                          status = ICallProxy(_callProxy).call(
                                              _autoParams.fallbackAddress,
                                              _receiver,
                                              _autoParams.data,
                                              _autoParams.flags,
                                              _autoParams.nativeSender,
                                              _chainIdFrom
                                          );
                                      }
                                      else {
                                          _mintOrTransfer(_token, _callProxy, _amount, isNativeToken);
                                          status = ICallProxy(_callProxy).callERC20(
                                              _token,
                                              _autoParams.fallbackAddress,
                                              _receiver,
                                              _autoParams.data,
                                              _autoParams.flags,
                                              _autoParams.nativeSender,
                                              _chainIdFrom
                                          );
                                      }
                                      emit AutoRequestExecuted(_submissionId, status, _callProxy);
                                  } else if (unwrapETH) {
                                      // transferring WETH with unwrap flag
                                      _withdrawWeth(_receiver, _amount);
                                  } else {
                                      _mintOrTransfer(_token, _receiver, _amount, isNativeToken);
                                  }
                                  emit MonitoringClaimEvent(
                                      _submissionId,
                                      debridge.balance,
                                      IERC20Upgradeable(debridge.tokenAddress).totalSupply()
                                  );
                              }
                              function _mintOrTransfer(
                                  address _token,
                                  address _receiver,
                                  uint256 _amount,
                                  bool isNativeToken
                              ) internal {
                                  if (_amount > 0) {
                                      if (isNativeToken) {
                                          IERC20Upgradeable(_token).safeTransfer(_receiver, _amount);
                                      } else {
                                          IDeBridgeToken(_token).mint(_receiver, _amount);
                                      }
                                  }
                              }
                              /*
                              * @dev transfer ETH to an address, revert if it fails.
                              * @param to recipient of the transfer
                              * @param value the amount to send
                              */
                              function _safeTransferETH(address to, uint256 value) internal {
                                  (bool success, ) = to.call{value: value}(new bytes(0));
                                  if (!success) revert EthTransferFailed();
                              }
                              function _withdrawWeth(address _receiver, uint _amount) internal {
                                  if (address(wethGate) == address(0)) {
                                      // dealing with weth withdraw affected by EIP1884
                                      weth.withdraw(_amount);
                                      _safeTransferETH(_receiver, _amount);
                                  }
                                  else {
                                      IERC20Upgradeable(address(weth)).safeTransfer(address(wethGate), _amount);
                                      wethGate.withdraw(_receiver, _amount);
                                  }
                              }
                              /*
                              * @dev round down token amount
                              * @param _token address of token, zero for native tokens
                              * @param __amount amount for rounding
                              */
                              function _normalizeTokenAmount(
                                  address _token,
                                  uint256 _amount
                              ) internal view returns (uint256) {
                                  uint256 decimals = _token == address(0)
                                      ? 18
                                      : IERC20Metadata(_token).decimals();
                                  uint256 maxDecimals = 8;
                                  if (decimals > maxDecimals) {
                                      uint256 multiplier = 10 ** (decimals - maxDecimals);
                                      _amount = _amount / multiplier * multiplier;
                                  }
                                  return _amount;
                              }
                              /* VIEW */
                              /// @dev Calculates asset identifier.
                              /// @param _chainId Current chain id.
                              /// @param _tokenAddress Address of the asset on the other chain.
                              function getDebridgeId(uint256 _chainId, address _tokenAddress) public pure returns (bytes32) {
                                  return keccak256(abi.encodePacked(_chainId, _tokenAddress));
                              }
                              /// @dev Calculates asset identifier.
                              /// @param _chainId Current chain id.
                              /// @param _tokenAddress Address of the asset on the other chain.
                              function getbDebridgeId(uint256 _chainId, bytes memory _tokenAddress) public pure returns (bytes32) {
                                  return keccak256(abi.encodePacked(_chainId, _tokenAddress));
                              }
                              /// @inheritdoc IDeBridgeGate
                              function getDebridgeChainAssetFixedFee(
                                  bytes32 _debridgeId,
                                  uint256 _chainId
                              ) external view override returns (uint256) {
                                  // if (!getDebridge[_debridgeId].exist) revert DebridgeNotFound();
                                  return getDebridgeFeeInfo[_debridgeId].getChainFee[_chainId];
                              }
                              /// @dev Calculate submission id for auto claimable transfer.
                              /// @param _debridgeId Asset identifier.
                              /// @param _chainIdFrom Chain identifier of the chain where tokens are sent from.
                              /// @param _amount Amount of the transferred asset (note: the fee can be applied).
                              /// @param _receiver Receiver address.
                              /// @param _nonce Submission id.
                              /// @param _autoParams Auto params for external call
                              /// @param _hasAutoParams True if auto params are provided
                              /// @param _sender Address that will call claim
                              function getSubmissionIdFrom(
                                  bytes32 _debridgeId,
                                  uint256 _chainIdFrom,
                                  uint256 _amount,
                                  address _receiver,
                                  uint256 _nonce,
                                  SubmissionAutoParamsFrom memory _autoParams,
                                  bool _hasAutoParams,
                                  address _sender
                              ) public view returns (bytes32) {
                                  bytes memory packedSubmission = abi.encodePacked(
                                      SUBMISSION_PREFIX,
                                      _debridgeId,
                                      _chainIdFrom,
                                      getChainId(),
                                      _amount,
                                      _receiver,
                                      _nonce
                                  );
                                  if (_hasAutoParams) {
                                      // Needed to let fallback address claim tokens in case user lost call data and can't restore its' hash
                                      bool isHashedData = _autoParams.flags.getFlag(Flags.SEND_HASHED_DATA)
                                                       && _sender == _autoParams.fallbackAddress
                                                       && _autoParams.data.length == 32;
                                      // auto submission
                                      return keccak256(
                                          abi.encodePacked(
                                              packedSubmission,
                                              _autoParams.executionFee,
                                              _autoParams.flags,
                                              keccak256(abi.encodePacked(_autoParams.fallbackAddress)),
                                              isHashedData ? _autoParams.data : abi.encodePacked(keccak256(_autoParams.data)),
                                              keccak256(_autoParams.nativeSender)
                                          )
                                      );
                                  }
                                  // regular submission
                                  return keccak256(packedSubmission);
                              }
                              /// @dev Calculates asset identifier for deployment.
                              /// @param _debridgeId Id of an asset, see getDebridgeId.
                              /// @param _name Asset's name.
                              /// @param _symbol Asset's symbol.
                              /// @param _decimals Asset's decimals.
                              function getDeployId(
                                  bytes32 _debridgeId,
                                  string memory _name,
                                  string memory _symbol,
                                  uint8 _decimals
                              ) public pure returns (bytes32) {
                                  return keccak256(abi.encodePacked(
                                      DEPLOY_PREFIX,
                                      _debridgeId,
                                      keccak256(abi.encodePacked(_name)),
                                      keccak256(abi.encodePacked(_symbol)),
                                      _decimals));
                              }
                              /// @dev Get current chain id
                              function getChainId() public view virtual returns (uint256 cid) {
                                  assembly {
                                      cid := chainid()
                                  }
                              }
                              // ============ Version Control ============
                              /// @dev Get this contract's version
                              function version() external pure returns (uint256) {
                                  return 421; // 4.2.1
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/ERC20.sol)
                          pragma solidity ^0.8.0;
                          import "./IERC20.sol";
                          import "./extensions/IERC20Metadata.sol";
                          import "../../utils/Context.sol";
                          /**
                           * @dev Implementation of the {IERC20} interface.
                           *
                           * This implementation is agnostic to the way tokens are created. This means
                           * that a supply mechanism has to be added in a derived contract using {_mint}.
                           * For a generic mechanism see {ERC20PresetMinterPauser}.
                           *
                           * TIP: For a detailed writeup see our guide
                           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
                           * to implement supply mechanisms].
                           *
                           * We have followed general OpenZeppelin Contracts guidelines: functions revert
                           * instead returning `false` on failure. This behavior is nonetheless
                           * conventional and does not conflict with the expectations of ERC20
                           * applications.
                           *
                           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
                           * This allows applications to reconstruct the allowance for all accounts just
                           * by listening to said events. Other implementations of the EIP may not emit
                           * these events, as it isn't required by the specification.
                           *
                           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
                           * functions have been added to mitigate the well-known issues around setting
                           * allowances. See {IERC20-approve}.
                           */
                          contract ERC20 is Context, IERC20, IERC20Metadata {
                              mapping(address => uint256) private _balances;
                              mapping(address => mapping(address => uint256)) private _allowances;
                              uint256 private _totalSupply;
                              string private _name;
                              string private _symbol;
                              /**
                               * @dev Sets the values for {name} and {symbol}.
                               *
                               * The default value of {decimals} is 18. To select a different value for
                               * {decimals} you should overload it.
                               *
                               * All two of these values are immutable: they can only be set once during
                               * construction.
                               */
                              constructor(string memory name_, string memory symbol_) {
                                  _name = name_;
                                  _symbol = symbol_;
                              }
                              /**
                               * @dev Returns the name of the token.
                               */
                              function name() public view virtual override returns (string memory) {
                                  return _name;
                              }
                              /**
                               * @dev Returns the symbol of the token, usually a shorter version of the
                               * name.
                               */
                              function symbol() public view virtual override returns (string memory) {
                                  return _symbol;
                              }
                              /**
                               * @dev Returns the number of decimals used to get its user representation.
                               * For example, if `decimals` equals `2`, a balance of `505` tokens should
                               * be displayed to a user as `5.05` (`505 / 10 ** 2`).
                               *
                               * Tokens usually opt for a value of 18, imitating the relationship between
                               * Ether and Wei. This is the value {ERC20} uses, unless this function is
                               * overridden;
                               *
                               * NOTE: This information is only used for _display_ purposes: it in
                               * no way affects any of the arithmetic of the contract, including
                               * {IERC20-balanceOf} and {IERC20-transfer}.
                               */
                              function decimals() public view virtual override returns (uint8) {
                                  return 18;
                              }
                              /**
                               * @dev See {IERC20-totalSupply}.
                               */
                              function totalSupply() public view virtual override returns (uint256) {
                                  return _totalSupply;
                              }
                              /**
                               * @dev See {IERC20-balanceOf}.
                               */
                              function balanceOf(address account) public view virtual override returns (uint256) {
                                  return _balances[account];
                              }
                              /**
                               * @dev See {IERC20-transfer}.
                               *
                               * Requirements:
                               *
                               * - `recipient` cannot be the zero address.
                               * - the caller must have a balance of at least `amount`.
                               */
                              function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                                  _transfer(_msgSender(), recipient, amount);
                                  return true;
                              }
                              /**
                               * @dev See {IERC20-allowance}.
                               */
                              function allowance(address owner, address spender) public view virtual override returns (uint256) {
                                  return _allowances[owner][spender];
                              }
                              /**
                               * @dev See {IERC20-approve}.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               */
                              function approve(address spender, uint256 amount) public virtual override returns (bool) {
                                  _approve(_msgSender(), spender, amount);
                                  return true;
                              }
                              /**
                               * @dev See {IERC20-transferFrom}.
                               *
                               * Emits an {Approval} event indicating the updated allowance. This is not
                               * required by the EIP. See the note at the beginning of {ERC20}.
                               *
                               * Requirements:
                               *
                               * - `sender` and `recipient` cannot be the zero address.
                               * - `sender` must have a balance of at least `amount`.
                               * - the caller must have allowance for ``sender``'s tokens of at least
                               * `amount`.
                               */
                              function transferFrom(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) public virtual override returns (bool) {
                                  _transfer(sender, recipient, amount);
                                  uint256 currentAllowance = _allowances[sender][_msgSender()];
                                  require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
                                  unchecked {
                                      _approve(sender, _msgSender(), currentAllowance - amount);
                                  }
                                  return true;
                              }
                              /**
                               * @dev Atomically increases the allowance granted to `spender` by the caller.
                               *
                               * This is an alternative to {approve} that can be used as a mitigation for
                               * problems described in {IERC20-approve}.
                               *
                               * Emits an {Approval} event indicating the updated allowance.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               */
                              function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
                                  return true;
                              }
                              /**
                               * @dev Atomically decreases the allowance granted to `spender` by the caller.
                               *
                               * This is an alternative to {approve} that can be used as a mitigation for
                               * problems described in {IERC20-approve}.
                               *
                               * Emits an {Approval} event indicating the updated allowance.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               * - `spender` must have allowance for the caller of at least
                               * `subtractedValue`.
                               */
                              function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                                  uint256 currentAllowance = _allowances[_msgSender()][spender];
                                  require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
                                  unchecked {
                                      _approve(_msgSender(), spender, currentAllowance - subtractedValue);
                                  }
                                  return true;
                              }
                              /**
                               * @dev Moves `amount` of tokens from `sender` to `recipient`.
                               *
                               * This internal function is equivalent to {transfer}, and can be used to
                               * e.g. implement automatic token fees, slashing mechanisms, etc.
                               *
                               * Emits a {Transfer} event.
                               *
                               * Requirements:
                               *
                               * - `sender` cannot be the zero address.
                               * - `recipient` cannot be the zero address.
                               * - `sender` must have a balance of at least `amount`.
                               */
                              function _transfer(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) internal virtual {
                                  require(sender != address(0), "ERC20: transfer from the zero address");
                                  require(recipient != address(0), "ERC20: transfer to the zero address");
                                  _beforeTokenTransfer(sender, recipient, amount);
                                  uint256 senderBalance = _balances[sender];
                                  require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
                                  unchecked {
                                      _balances[sender] = senderBalance - amount;
                                  }
                                  _balances[recipient] += amount;
                                  emit Transfer(sender, recipient, amount);
                                  _afterTokenTransfer(sender, recipient, amount);
                              }
                              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                               * the total supply.
                               *
                               * Emits a {Transfer} event with `from` set to the zero address.
                               *
                               * Requirements:
                               *
                               * - `account` cannot be the zero address.
                               */
                              function _mint(address account, uint256 amount) internal virtual {
                                  require(account != address(0), "ERC20: mint to the zero address");
                                  _beforeTokenTransfer(address(0), account, amount);
                                  _totalSupply += amount;
                                  _balances[account] += amount;
                                  emit Transfer(address(0), account, amount);
                                  _afterTokenTransfer(address(0), account, amount);
                              }
                              /**
                               * @dev Destroys `amount` tokens from `account`, reducing the
                               * total supply.
                               *
                               * Emits a {Transfer} event with `to` set to the zero address.
                               *
                               * Requirements:
                               *
                               * - `account` cannot be the zero address.
                               * - `account` must have at least `amount` tokens.
                               */
                              function _burn(address account, uint256 amount) internal virtual {
                                  require(account != address(0), "ERC20: burn from the zero address");
                                  _beforeTokenTransfer(account, address(0), amount);
                                  uint256 accountBalance = _balances[account];
                                  require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                                  unchecked {
                                      _balances[account] = accountBalance - amount;
                                  }
                                  _totalSupply -= amount;
                                  emit Transfer(account, address(0), amount);
                                  _afterTokenTransfer(account, address(0), amount);
                              }
                              /**
                               * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                               *
                               * This internal function is equivalent to `approve`, and can be used to
                               * e.g. set automatic allowances for certain subsystems, etc.
                               *
                               * Emits an {Approval} event.
                               *
                               * Requirements:
                               *
                               * - `owner` cannot be the zero address.
                               * - `spender` cannot be the zero address.
                               */
                              function _approve(
                                  address owner,
                                  address spender,
                                  uint256 amount
                              ) internal virtual {
                                  require(owner != address(0), "ERC20: approve from the zero address");
                                  require(spender != address(0), "ERC20: approve to the zero address");
                                  _allowances[owner][spender] = amount;
                                  emit Approval(owner, spender, amount);
                              }
                              /**
                               * @dev Hook that is called before any transfer of tokens. This includes
                               * minting and burning.
                               *
                               * Calling conditions:
                               *
                               * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                               * will be transferred to `to`.
                               * - when `from` is zero, `amount` tokens will be minted for `to`.
                               * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                               * - `from` and `to` are never both zero.
                               *
                               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                               */
                              function _beforeTokenTransfer(
                                  address from,
                                  address to,
                                  uint256 amount
                              ) internal virtual {}
                              /**
                               * @dev Hook that is called after any transfer of tokens. This includes
                               * minting and burning.
                               *
                               * Calling conditions:
                               *
                               * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                               * has been transferred to `to`.
                               * - when `from` is zero, `amount` tokens have been minted for `to`.
                               * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
                               * - `from` and `to` are never both zero.
                               *
                               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                               */
                              function _afterTokenTransfer(
                                  address from,
                                  address to,
                                  uint256 amount
                              ) internal virtual {}
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/extensions/IERC20Metadata.sol)
                          pragma solidity ^0.8.0;
                          import "../IERC20Upgradeable.sol";
                          /**
                           * @dev Interface for the optional metadata functions from the ERC20 standard.
                           *
                           * _Available since v4.1._
                           */
                          interface IERC20MetadataUpgradeable is IERC20Upgradeable {
                              /**
                               * @dev Returns the name of the token.
                               */
                              function name() external view returns (string memory);
                              /**
                               * @dev Returns the symbol of the token.
                               */
                              function symbol() external view returns (string memory);
                              /**
                               * @dev Returns the decimals places of the token.
                               */
                              function decimals() external view returns (uint8);
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC20 standard as defined in the EIP.
                           */
                          interface IERC20Upgradeable {
                              /**
                               * @dev Returns the amount of tokens in existence.
                               */
                              function totalSupply() external view returns (uint256);
                              /**
                               * @dev Returns the amount of tokens owned by `account`.
                               */
                              function balanceOf(address account) external view returns (uint256);
                              /**
                               * @dev Moves `amount` tokens from the caller's account to `recipient`.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transfer(address recipient, uint256 amount) external returns (bool);
                              /**
                               * @dev Returns the remaining number of tokens that `spender` will be
                               * allowed to spend on behalf of `owner` through {transferFrom}. This is
                               * zero by default.
                               *
                               * This value changes when {approve} or {transferFrom} are called.
                               */
                              function allowance(address owner, address spender) external view returns (uint256);
                              /**
                               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * IMPORTANT: Beware that changing an allowance with this method brings the risk
                               * that someone may use both the old and the new allowance by unfortunate
                               * transaction ordering. One possible solution to mitigate this race
                               * condition is to first reduce the spender's allowance to 0 and set the
                               * desired value afterwards:
                               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                               *
                               * Emits an {Approval} event.
                               */
                              function approve(address spender, uint256 amount) external returns (bool);
                              /**
                               * @dev Moves `amount` tokens from `sender` to `recipient` using the
                               * allowance mechanism. `amount` is then deducted from the caller's
                               * allowance.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transferFrom(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) external returns (bool);
                              /**
                               * @dev Emitted when `value` tokens are moved from one account (`from`) to
                               * another (`to`).
                               *
                               * Note that `value` may be zero.
                               */
                              event Transfer(address indexed from, address indexed to, uint256 value);
                              /**
                               * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                               * a call to {approve}. `value` is the new allowance.
                               */
                              event Approval(address indexed owner, address indexed spender, uint256 value);
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/utils/SafeERC20.sol)
                          pragma solidity ^0.8.0;
                          import "../IERC20Upgradeable.sol";
                          import "../../../utils/AddressUpgradeable.sol";
                          /**
                           * @title SafeERC20
                           * @dev Wrappers around ERC20 operations that throw on failure (when the token
                           * contract returns false). Tokens that return no value (and instead revert or
                           * throw on failure) are also supported, non-reverting calls are assumed to be
                           * successful.
                           * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
                           * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
                           */
                          library SafeERC20Upgradeable {
                              using AddressUpgradeable for address;
                              function safeTransfer(
                                  IERC20Upgradeable token,
                                  address to,
                                  uint256 value
                              ) internal {
                                  _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                              }
                              function safeTransferFrom(
                                  IERC20Upgradeable token,
                                  address from,
                                  address to,
                                  uint256 value
                              ) internal {
                                  _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                              }
                              /**
                               * @dev Deprecated. This function has issues similar to the ones found in
                               * {IERC20-approve}, and its usage is discouraged.
                               *
                               * Whenever possible, use {safeIncreaseAllowance} and
                               * {safeDecreaseAllowance} instead.
                               */
                              function safeApprove(
                                  IERC20Upgradeable token,
                                  address spender,
                                  uint256 value
                              ) internal {
                                  // safeApprove should only be called when setting an initial allowance,
                                  // or when resetting it to zero. To increase and decrease it, use
                                  // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                                  require(
                                      (value == 0) || (token.allowance(address(this), spender) == 0),
                                      "SafeERC20: approve from non-zero to non-zero allowance"
                                  );
                                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                              }
                              function safeIncreaseAllowance(
                                  IERC20Upgradeable token,
                                  address spender,
                                  uint256 value
                              ) internal {
                                  uint256 newAllowance = token.allowance(address(this), spender) + value;
                                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                              }
                              function safeDecreaseAllowance(
                                  IERC20Upgradeable token,
                                  address spender,
                                  uint256 value
                              ) internal {
                                  unchecked {
                                      uint256 oldAllowance = token.allowance(address(this), spender);
                                      require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                                      uint256 newAllowance = oldAllowance - value;
                                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                                  }
                              }
                              /**
                               * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                               * on the return value: the return value is optional (but if data is returned, it must not be false).
                               * @param token The token targeted by the call.
                               * @param data The call data (encoded using abi.encode or one of its variants).
                               */
                              function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
                                  // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                                  // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                                  // the target address contains contract code and also asserts for success in the low-level call.
                                  bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                                  if (returndata.length > 0) {
                                      // Return data is optional
                                      require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (proxy/utils/Initializable.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                           * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
                           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                           *
                           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                           * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                           *
                           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                           *
                           * [CAUTION]
                           * ====
                           * Avoid leaving a contract uninitialized.
                           *
                           * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                           * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
                           * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
                           *
                           * [.hljs-theme-light.nopadding]
                           * ```
                           * /// @custom:oz-upgrades-unsafe-allow constructor
                           * constructor() initializer {}
                           * ```
                           * ====
                           */
                          abstract contract Initializable {
                              /**
                               * @dev Indicates that the contract has been initialized.
                               */
                              bool private _initialized;
                              /**
                               * @dev Indicates that the contract is in the process of being initialized.
                               */
                              bool private _initializing;
                              /**
                               * @dev Modifier to protect an initializer function from being invoked twice.
                               */
                              modifier initializer() {
                                  require(_initializing || !_initialized, "Initializable: contract is already initialized");
                                  bool isTopLevelCall = !_initializing;
                                  if (isTopLevelCall) {
                                      _initializing = true;
                                      _initialized = true;
                                  }
                                  _;
                                  if (isTopLevelCall) {
                                      _initializing = false;
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (access/AccessControl.sol)
                          pragma solidity ^0.8.0;
                          import "./IAccessControlUpgradeable.sol";
                          import "../utils/ContextUpgradeable.sol";
                          import "../utils/StringsUpgradeable.sol";
                          import "../utils/introspection/ERC165Upgradeable.sol";
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Contract module that allows children to implement role-based access
                           * control mechanisms. This is a lightweight version that doesn't allow enumerating role
                           * members except through off-chain means by accessing the contract event logs. Some
                           * applications may benefit from on-chain enumerability, for those cases see
                           * {AccessControlEnumerable}.
                           *
                           * Roles are referred to by their `bytes32` identifier. These should be exposed
                           * in the external API and be unique. The best way to achieve this is by
                           * using `public constant` hash digests:
                           *
                           * ```
                           * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
                           * ```
                           *
                           * Roles can be used to represent a set of permissions. To restrict access to a
                           * function call, use {hasRole}:
                           *
                           * ```
                           * function foo() public {
                           *     require(hasRole(MY_ROLE, msg.sender));
                           *     ...
                           * }
                           * ```
                           *
                           * Roles can be granted and revoked dynamically via the {grantRole} and
                           * {revokeRole} functions. Each role has an associated admin role, and only
                           * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
                           *
                           * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
                           * that only accounts with this role will be able to grant or revoke other
                           * roles. More complex role relationships can be created by using
                           * {_setRoleAdmin}.
                           *
                           * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
                           * grant and revoke this role. Extra precautions should be taken to secure
                           * accounts that have been granted it.
                           */
                          abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
                              function __AccessControl_init() internal initializer {
                                  __Context_init_unchained();
                                  __ERC165_init_unchained();
                                  __AccessControl_init_unchained();
                              }
                              function __AccessControl_init_unchained() internal initializer {
                              }
                              struct RoleData {
                                  mapping(address => bool) members;
                                  bytes32 adminRole;
                              }
                              mapping(bytes32 => RoleData) private _roles;
                              bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
                              /**
                               * @dev Modifier that checks that an account has a specific role. Reverts
                               * with a standardized message including the required role.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               *
                               * _Available since v4.1._
                               */
                              modifier onlyRole(bytes32 role) {
                                  _checkRole(role, _msgSender());
                                  _;
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
                              }
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) public view override returns (bool) {
                                  return _roles[role].members[account];
                              }
                              /**
                               * @dev Revert with a standard message if `account` is missing `role`.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               */
                              function _checkRole(bytes32 role, address account) internal view {
                                  if (!hasRole(role, account)) {
                                      revert(
                                          string(
                                              abi.encodePacked(
                                                  "AccessControl: account ",
                                                  StringsUpgradeable.toHexString(uint160(account), 20),
                                                  " is missing role ",
                                                  StringsUpgradeable.toHexString(uint256(role), 32)
                                              )
                                          )
                                      );
                                  }
                              }
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
                                  return _roles[role].adminRole;
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been revoked `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) public virtual override {
                                  require(account == _msgSender(), "AccessControl: can only renounce roles for self");
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event. Note that unlike {grantRole}, this function doesn't perform any
                               * checks on the calling account.
                               *
                               * [WARNING]
                               * ====
                               * This function should only be called from the constructor when setting
                               * up the initial roles for the system.
                               *
                               * Using this function in any other way is effectively circumventing the admin
                               * system imposed by {AccessControl}.
                               * ====
                               *
                               * NOTE: This function is deprecated in favor of {_grantRole}.
                               */
                              function _setupRole(bytes32 role, address account) internal virtual {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Sets `adminRole` as ``role``'s admin role.
                               *
                               * Emits a {RoleAdminChanged} event.
                               */
                              function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                                  bytes32 previousAdminRole = getRoleAdmin(role);
                                  _roles[role].adminRole = adminRole;
                                  emit RoleAdminChanged(role, previousAdminRole, adminRole);
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * Internal function without access restriction.
                               */
                              function _grantRole(bytes32 role, address account) internal virtual {
                                  if (!hasRole(role, account)) {
                                      _roles[role].members[account] = true;
                                      emit RoleGranted(role, account, _msgSender());
                                  }
                              }
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * Internal function without access restriction.
                               */
                              function _revokeRole(bytes32 role, address account) internal virtual {
                                  if (hasRole(role, account)) {
                                      _roles[role].members[account] = false;
                                      emit RoleRevoked(role, account, _msgSender());
                                  }
                              }
                              uint256[49] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (security/ReentrancyGuard.sol)
                          pragma solidity ^0.8.0;
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Contract module that helps prevent reentrant calls to a function.
                           *
                           * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
                           * available, which can be applied to functions to make sure there are no nested
                           * (reentrant) calls to them.
                           *
                           * Note that because there is a single `nonReentrant` guard, functions marked as
                           * `nonReentrant` may not call one another. This can be worked around by making
                           * those functions `private`, and then adding `external` `nonReentrant` entry
                           * points to them.
                           *
                           * TIP: If you would like to learn more about reentrancy and alternative ways
                           * to protect against it, check out our blog post
                           * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
                           */
                          abstract contract ReentrancyGuardUpgradeable is Initializable {
                              // Booleans are more expensive than uint256 or any type that takes up a full
                              // word because each write operation emits an extra SLOAD to first read the
                              // slot's contents, replace the bits taken up by the boolean, and then write
                              // back. This is the compiler's defense against contract upgrades and
                              // pointer aliasing, and it cannot be disabled.
                              // The values being non-zero value makes deployment a bit more expensive,
                              // but in exchange the refund on every call to nonReentrant will be lower in
                              // amount. Since refunds are capped to a percentage of the total
                              // transaction's gas, it is best to keep them low in cases like this one, to
                              // increase the likelihood of the full refund coming into effect.
                              uint256 private constant _NOT_ENTERED = 1;
                              uint256 private constant _ENTERED = 2;
                              uint256 private _status;
                              function __ReentrancyGuard_init() internal initializer {
                                  __ReentrancyGuard_init_unchained();
                              }
                              function __ReentrancyGuard_init_unchained() internal initializer {
                                  _status = _NOT_ENTERED;
                              }
                              /**
                               * @dev Prevents a contract from calling itself, directly or indirectly.
                               * Calling a `nonReentrant` function from another `nonReentrant`
                               * function is not supported. It is possible to prevent this from happening
                               * by making the `nonReentrant` function external, and making it call a
                               * `private` function that does the actual work.
                               */
                              modifier nonReentrant() {
                                  // On the first call to nonReentrant, _notEntered will be true
                                  require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                                  // Any calls to nonReentrant after this point will fail
                                  _status = _ENTERED;
                                  _;
                                  // By storing the original value once again, a refund is triggered (see
                                  // https://eips.ethereum.org/EIPS/eip-2200)
                                  _status = _NOT_ENTERED;
                              }
                              uint256[49] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (security/Pausable.sol)
                          pragma solidity ^0.8.0;
                          import "../utils/ContextUpgradeable.sol";
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Contract module which allows children to implement an emergency stop
                           * mechanism that can be triggered by an authorized account.
                           *
                           * This module is used through inheritance. It will make available the
                           * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
                           * the functions of your contract. Note that they will not be pausable by
                           * simply including this module, only once the modifiers are put in place.
                           */
                          abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
                              /**
                               * @dev Emitted when the pause is triggered by `account`.
                               */
                              event Paused(address account);
                              /**
                               * @dev Emitted when the pause is lifted by `account`.
                               */
                              event Unpaused(address account);
                              bool private _paused;
                              /**
                               * @dev Initializes the contract in unpaused state.
                               */
                              function __Pausable_init() internal initializer {
                                  __Context_init_unchained();
                                  __Pausable_init_unchained();
                              }
                              function __Pausable_init_unchained() internal initializer {
                                  _paused = false;
                              }
                              /**
                               * @dev Returns true if the contract is paused, and false otherwise.
                               */
                              function paused() public view virtual returns (bool) {
                                  return _paused;
                              }
                              /**
                               * @dev Modifier to make a function callable only when the contract is not paused.
                               *
                               * Requirements:
                               *
                               * - The contract must not be paused.
                               */
                              modifier whenNotPaused() {
                                  require(!paused(), "Pausable: paused");
                                  _;
                              }
                              /**
                               * @dev Modifier to make a function callable only when the contract is paused.
                               *
                               * Requirements:
                               *
                               * - The contract must be paused.
                               */
                              modifier whenPaused() {
                                  require(paused(), "Pausable: not paused");
                                  _;
                              }
                              /**
                               * @dev Triggers stopped state.
                               *
                               * Requirements:
                               *
                               * - The contract must not be paused.
                               */
                              function _pause() internal virtual whenNotPaused {
                                  _paused = true;
                                  emit Paused(_msgSender());
                              }
                              /**
                               * @dev Returns to normal state.
                               *
                               * Requirements:
                               *
                               * - The contract must be paused.
                               */
                              function _unpause() internal virtual whenPaused {
                                  _paused = false;
                                  emit Unpaused(_msgSender());
                              }
                              uint256[49] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.7;
                          /**
                           * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
                           * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
                           *
                           * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
                           * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
                           * need to send a transaction, and thus is not required to hold Ether at all.
                           */
                          interface IERC20Permit {
                              /**
                               * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
                               * given ``owner``'s signed approval.
                               *
                               * IMPORTANT: The same issues {IERC20-approve} has related to transaction
                               * ordering also apply here.
                               *
                               * Emits an {Approval} event.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               * - `deadline` must be a timestamp in the future.
                               * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
                               * over the EIP712-formatted function arguments.
                               * - the signature must use ``owner``'s current nonce (see {nonces}).
                               *
                               * For more information on the signature format, see the
                               * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
                               * section].
                               */
                              function permit(
                                  address owner,
                                  address spender,
                                  uint256 value,
                                  uint256 deadline,
                                  uint8 v,
                                  bytes32 r,
                                  bytes32 s
                              ) external;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.7;
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
                          import "../interfaces/IERC20Permit.sol";
                          interface IDeBridgeToken is IERC20Upgradeable, IERC20Permit {
                              /// @dev Issues new tokens.
                              /// @param _receiver Token's receiver.
                              /// @param _amount Amount to be minted.
                              function mint(address _receiver, uint256 _amount) external;
                              /// @dev Destroys existing tokens.
                              /// @param _amount Amount to be burnt.
                              function burn(uint256 _amount) external;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.7;
                          interface IDeBridgeTokenDeployer {
                              /// @dev Deploy a deToken(DeBridgeTokenProxy) for an asset
                              /// @param _debridgeId Asset id, see DeBridgeGate.getDebridgeId
                              /// @param _name The asset's name
                              /// @param _symbol The asset's symbol
                              /// @param _decimals The asset's decimals
                              function deployAsset(
                                  bytes32 _debridgeId,
                                  string memory _name,
                                  string memory _symbol,
                                  uint8 _decimals
                              ) external returns (address deTokenAddress);
                              /// @dev Emitted when a deToken(DeBridgeTokenProxy) is deployed using this contract
                              event DeBridgeTokenDeployed(
                                  address asset,
                                  string name,
                                  string symbol,
                                  uint8 decimals
                              );
                          }// SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.7;
                          interface ISignatureVerifier {
                              /* ========== EVENTS ========== */
                              /// @dev Emitted once the submission is confirmed by one oracle.
                              event Confirmed(bytes32 submissionId, address operator);
                              /// @dev Emitted once the submission is confirmed by min required amount of oracles.
                              event DeployConfirmed(bytes32 deployId, address operator);
                              /* ========== FUNCTIONS ========== */
                              /// @dev Check confirmation (validate signatures) for the transfer request.
                              /// @param _submissionId Submission identifier.
                              /// @param _signatures Array of signatures by oracles.
                              /// @param _excessConfirmations override min confirmations count
                              function submit(
                                  bytes32 _submissionId,
                                  bytes memory _signatures,
                                  uint8 _excessConfirmations
                              ) external;
                          }// SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.7;
                          interface IWETH {
                              function deposit() external payable;
                              function withdraw(uint256 wad) external;
                              function totalSupply() external view returns (uint256);
                              function balanceOf(address account) external view returns (uint256);
                              function transfer(address recipient, uint256 amount) external returns (bool);
                              function allowance(address owner, address spender) external view returns (uint256);
                              function approve(address spender, uint256 amount) external returns (bool);
                              function transferFrom(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) external returns (bool);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.7;
                          interface IDeBridgeGate {
                              /* ========== STRUCTS ========== */
                              struct TokenInfo {
                                  uint256 nativeChainId;
                                  bytes nativeAddress;
                              }
                              struct DebridgeInfo {
                                  uint256 chainId; // native chain id
                                  uint256 maxAmount; // maximum amount to transfer
                                  uint256 balance; // total locked assets
                                  uint256 lockedInStrategies; // total locked assets in strategy (AAVE, Compound, etc)
                                  address tokenAddress; // asset address on the current chain
                                  uint16 minReservesBps; // minimal hot reserves in basis points (1/10000)
                                  bool exist;
                              }
                              struct DebridgeFeeInfo {
                                  uint256 collectedFees; // total collected fees
                                  uint256 withdrawnFees; // fees that already withdrawn
                                  mapping(uint256 => uint256) getChainFee; // whether the chain for the asset is supported
                              }
                              struct ChainSupportInfo {
                                  uint256 fixedNativeFee; // transfer fixed fee
                                  bool isSupported; // whether the chain for the asset is supported
                                  uint16 transferFeeBps; // transfer fee rate nominated in basis points (1/10000) of transferred amount
                              }
                              struct DiscountInfo {
                                  uint16 discountFixBps; // fix discount in BPS
                                  uint16 discountTransferBps; // transfer % discount in BPS
                              }
                              /// @param executionFee Fee paid to the transaction executor.
                              /// @param fallbackAddress Receiver of the tokens if the call fails.
                              struct SubmissionAutoParamsTo {
                                  uint256 executionFee;
                                  uint256 flags;
                                  bytes fallbackAddress;
                                  bytes data;
                              }
                              /// @param executionFee Fee paid to the transaction executor.
                              /// @param fallbackAddress Receiver of the tokens if the call fails.
                              struct SubmissionAutoParamsFrom {
                                  uint256 executionFee;
                                  uint256 flags;
                                  address fallbackAddress;
                                  bytes data;
                                  bytes nativeSender;
                              }
                              struct FeeParams {
                                  uint256 receivedAmount;
                                  uint256 fixFee;
                                  uint256 transferFee;
                                  bool useAssetFee;
                                  bool isNativeToken;
                              }
                              /* ========== PUBLIC VARS GETTERS ========== */
                              /// @dev Returns whether the transfer with the submissionId was claimed.
                              /// submissionId is generated in getSubmissionIdFrom
                              function isSubmissionUsed(bytes32 submissionId) external returns (bool);
                              /// @dev Returns native token info by wrapped token address
                              function getNativeInfo(address token) external returns (
                                  uint256 nativeChainId,
                                  bytes memory nativeAddress);
                              /// @dev Returns address of the proxy to execute user's calls.
                              function callProxy() external returns (address);
                              /// @dev Fallback fixed fee in native asset, used if a chain fixed fee is set to 0
                              function globalFixedNativeFee() external returns (uint256);
                              /// @dev Fallback transfer fee in BPS, used if a chain transfer fee is set to 0
                              function globalTransferFeeBps() external returns (uint16);
                              /* ========== FUNCTIONS ========== */
                              /// @dev Submits the message to the deBridge infrastructure to be broadcasted to another supported blockchain (identified by _dstChainId)
                              ///      with the instructions to call the _targetContractAddress contract using the given _targetContractCalldata
                              /// @notice NO ASSETS ARE BROADCASTED ALONG WITH THIS MESSAGE
                              /// @notice DeBridgeGate only accepts submissions with msg.value (native ether) covering a small protocol fee
                              ///         (defined in the globalFixedNativeFee property). Any excess amount of ether passed to this function is
                              ///         included in the message as the execution fee - the amount deBridgeGate would give as an incentive to
                              ///         a third party in return for successful claim transaction execution on the destination chain.
                              /// @notice DeBridgeGate accepts a set of flags that control the behaviour of the execution. This simple method
                              ///         sets the default set of flags: REVERT_IF_EXTERNAL_FAIL, PROXY_WITH_SENDER
                              /// @param _dstChainId ID of the destination chain.
                              /// @param _targetContractAddress A contract address to be called on the destination chain
                              /// @param _targetContractCalldata Calldata to execute against the target contract on the destination chain
                              function sendMessage(
                                  uint256 _dstChainId,
                                  bytes memory _targetContractAddress,
                                  bytes memory _targetContractCalldata
                              ) external payable returns (bytes32 submissionId);
                              /// @dev Submits the message to the deBridge infrastructure to be broadcasted to another supported blockchain (identified by _dstChainId)
                              ///      with the instructions to call the _targetContractAddress contract using the given _targetContractCalldata
                              /// @notice NO ASSETS ARE BROADCASTED ALONG WITH THIS MESSAGE
                              /// @notice DeBridgeGate only accepts submissions with msg.value (native ether) covering a small protocol fee
                              ///         (defined in the globalFixedNativeFee property). Any excess amount of ether passed to this function is
                              ///         included in the message as the execution fee - the amount deBridgeGate would give as an incentive to
                              ///         a third party in return for successful claim transaction execution on the destination chain.
                              /// @notice DeBridgeGate accepts a set of flags that control the behaviour of the execution. This simple method
                              ///         sets the default set of flags: REVERT_IF_EXTERNAL_FAIL, PROXY_WITH_SENDER
                              /// @param _dstChainId ID of the destination chain.
                              /// @param _targetContractAddress A contract address to be called on the destination chain
                              /// @param _targetContractCalldata Calldata to execute against the target contract on the destination chain
                              /// @param _flags A bitmask of toggles listed in the Flags library
                              /// @param _referralCode Referral code to identify this submission
                              function sendMessage(
                                  uint256 _dstChainId,
                                  bytes memory _targetContractAddress,
                                  bytes memory _targetContractCalldata,
                                  uint256 _flags,
                                  uint32 _referralCode
                              ) external payable returns (bytes32 submissionId);
                              /// @dev This method is used for the transfer of assets [from the native chain](https://docs.debridge.finance/the-core-protocol/transfers#transfer-from-native-chain).
                              /// It locks an asset in the smart contract in the native chain and enables minting of deAsset on the secondary chain.
                              /// @param _tokenAddress Asset identifier.
                              /// @param _amount Amount to be transferred (note: the fee can be applied).
                              /// @param _chainIdTo Chain id of the target chain.
                              /// @param _receiver Receiver address.
                              /// @param _permitEnvelope Permit for approving the spender by signature. bytes (amount + deadline + signature)
                              /// @param _useAssetFee use assets fee for pay protocol fix (work only for specials token)
                              /// @param _referralCode Referral code
                              /// @param _autoParams Auto params for external call in target network
                              function send(
                                  address _tokenAddress,
                                  uint256 _amount,
                                  uint256 _chainIdTo,
                                  bytes memory _receiver,
                                  bytes memory _permitEnvelope,
                                  bool _useAssetFee,
                                  uint32 _referralCode,
                                  bytes calldata _autoParams
                              ) external payable returns (bytes32 submissionId) ;
                              /// @dev Is used for transfers [into the native chain](https://docs.debridge.finance/the-core-protocol/transfers#transfer-from-secondary-chain-to-native-chain)
                              /// to unlock the designated amount of asset from collateral and transfer it to the receiver.
                              /// @param _debridgeId Asset identifier.
                              /// @param _amount Amount of the transferred asset (note: the fee can be applied).
                              /// @param _chainIdFrom Chain where submission was sent
                              /// @param _receiver Receiver address.
                              /// @param _nonce Submission id.
                              /// @param _signatures Validators signatures to confirm
                              /// @param _autoParams Auto params for external call
                              function claim(
                                  bytes32 _debridgeId,
                                  uint256 _amount,
                                  uint256 _chainIdFrom,
                                  address _receiver,
                                  uint256 _nonce,
                                  bytes calldata _signatures,
                                  bytes calldata _autoParams
                              ) external;
                              /// @dev Withdraw collected fees to feeProxy
                              /// @param _debridgeId Asset identifier.
                              function withdrawFee(bytes32 _debridgeId) external;
                              /// @dev Returns asset fixed fee value for specified debridge and chainId.
                              /// @param _debridgeId Asset identifier.
                              /// @param _chainId Chain id.
                              function getDebridgeChainAssetFixedFee(
                                  bytes32 _debridgeId,
                                  uint256 _chainId
                              ) external view returns (uint256);
                              /* ========== EVENTS ========== */
                              /// @dev Emitted once the tokens are sent from the original(native) chain to the other chain; the transfer tokens
                              /// are expected to be claimed by the users.
                              event Sent(
                                  bytes32 submissionId,
                                  bytes32 indexed debridgeId,
                                  uint256 amount,
                                  bytes receiver,
                                  uint256 nonce,
                                  uint256 indexed chainIdTo,
                                  uint32 referralCode,
                                  FeeParams feeParams,
                                  bytes autoParams,
                                  address nativeSender
                                  // bool isNativeToken //added to feeParams
                              );
                              /// @dev Emitted once the tokens are transferred and withdrawn on a target chain
                              event Claimed(
                                  bytes32 submissionId,
                                  bytes32 indexed debridgeId,
                                  uint256 amount,
                                  address indexed receiver,
                                  uint256 nonce,
                                  uint256 indexed chainIdFrom,
                                  bytes autoParams,
                                  bool isNativeToken
                              );
                              /// @dev Emitted when new asset support is added.
                              event PairAdded(
                                  bytes32 debridgeId,
                                  address tokenAddress,
                                  bytes nativeAddress,
                                  uint256 indexed nativeChainId,
                                  uint256 maxAmount,
                                  uint16 minReservesBps
                              );
                              event MonitoringSendEvent(
                                  bytes32 submissionId,
                                  uint256 nonce,
                                  uint256 lockedOrMintedAmount,
                                  uint256 totalSupply
                              );
                              event MonitoringClaimEvent(
                                  bytes32 submissionId,
                                  uint256 lockedOrMintedAmount,
                                  uint256 totalSupply
                              );
                              /// @dev Emitted when the asset is allowed/disallowed to be transferred to the chain.
                              event ChainSupportUpdated(uint256 chainId, bool isSupported, bool isChainFrom);
                              /// @dev Emitted when the supported chains are updated.
                              event ChainsSupportUpdated(
                                  uint256 chainIds,
                                  ChainSupportInfo chainSupportInfo,
                                  bool isChainFrom);
                              /// @dev Emitted when the new call proxy is set.
                              event CallProxyUpdated(address callProxy);
                              /// @dev Emitted when the transfer request is executed.
                              event AutoRequestExecuted(
                                  bytes32 submissionId,
                                  bool indexed success,
                                  address callProxy
                              );
                              /// @dev Emitted when a submission is blocked.
                              event Blocked(bytes32 submissionId);
                              /// @dev Emitted when a submission is unblocked.
                              event Unblocked(bytes32 submissionId);
                              /// @dev Emitted when fee is withdrawn.
                              event WithdrawnFee(bytes32 debridgeId, uint256 fee);
                              /// @dev Emitted when globalFixedNativeFee and globalTransferFeeBps are updated.
                              event FixedNativeFeeUpdated(
                                  uint256 globalFixedNativeFee,
                                  uint256 globalTransferFeeBps);
                              /// @dev Emitted when globalFixedNativeFee is updated by feeContractUpdater
                              event FixedNativeFeeAutoUpdated(uint256 globalFixedNativeFee);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.7;
                          interface ICallProxy {
                              /// @dev Chain from which the current submission is received
                              function submissionChainIdFrom() external returns (uint256);
                              /// @dev Native sender of the current submission
                              function submissionNativeSender() external returns (bytes memory);
                              /// @dev Used for calls where native asset transfer is involved.
                              /// @param _reserveAddress Receiver of the tokens if the call to _receiver fails
                              /// @param _receiver Contract to be called
                              /// @param _data Call data
                              /// @param _flags Flags to change certain behavior of this function, see Flags library for more details
                              /// @param _nativeSender Native sender
                              /// @param _chainIdFrom Id of a chain that originated the request
                              function call(
                                  address _reserveAddress,
                                  address _receiver,
                                  bytes memory _data,
                                  uint256 _flags,
                                  bytes memory _nativeSender,
                                  uint256 _chainIdFrom
                              ) external payable returns (bool);
                              /// @dev Used for calls where ERC20 transfer is involved.
                              /// @param _token Asset address
                              /// @param _reserveAddress Receiver of the tokens if the call to _receiver fails
                              /// @param _receiver Contract to be called
                              /// @param _data Call data
                              /// @param _flags Flags to change certain behavior of this function, see Flags library for more details
                              /// @param _nativeSender Native sender
                              /// @param _chainIdFrom Id of a chain that originated the request
                              function callERC20(
                                  address _token,
                                  address _reserveAddress,
                                  address _receiver,
                                  bytes memory _data,
                                  uint256 _flags,
                                  bytes memory _nativeSender,
                                  uint256 _chainIdFrom
                              ) external returns (bool);
                          }// SPDX-License-Identifier: BUSL-1.1
                          pragma solidity ^0.8.7;
                          library SignatureUtil {
                              /* ========== ERRORS ========== */
                              error WrongArgumentLength();
                              error SignatureInvalidLength();
                              error SignatureInvalidV();
                              /// @dev Prepares raw msg that was signed by the oracle.
                              /// @param _submissionId Submission identifier.
                              function getUnsignedMsg(bytes32 _submissionId) internal pure returns (bytes32) {
                                  return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
                          32", _submissionId));
                              }
                              /// @dev Splits signature bytes to r,s,v components.
                              /// @param _signature Signature bytes in format r+s+v.
                              function splitSignature(bytes memory _signature)
                                  internal
                                  pure
                                  returns (
                                      bytes32 r,
                                      bytes32 s,
                                      uint8 v
                                  )
                              {
                                  if (_signature.length != 65) revert SignatureInvalidLength();
                                  return parseSignature(_signature, 0);
                              }
                              function parseSignature(bytes memory _signatures, uint256 offset)
                                  internal
                                  pure
                                  returns (
                                      bytes32 r,
                                      bytes32 s,
                                      uint8 v
                                  )
                              {
                                  assembly {
                                      r := mload(add(_signatures, add(32, offset)))
                                      s := mload(add(_signatures, add(64, offset)))
                                      v := and(mload(add(_signatures, add(65, offset))), 0xff)
                                  }
                                  if (v < 27) v += 27;
                                  if (v != 27 && v != 28) revert SignatureInvalidV();
                              }
                              function toUint256(bytes memory _bytes, uint256 _offset)
                                  internal
                                  pure
                                  returns (uint256 result)
                              {
                                  if (_bytes.length < _offset + 32) revert WrongArgumentLength();
                                  assembly {
                                      result := mload(add(add(_bytes, 0x20), _offset))
                                  }
                              }
                          }
                          // SPDX-License-Identifier: BUSL-1.1
                          pragma solidity ^0.8.7;
                          library Flags {
                              /* ========== FLAGS ========== */
                              /// @dev Flag to unwrap ETH
                              uint256 public constant UNWRAP_ETH = 0;
                              /// @dev Flag to revert if external call fails
                              uint256 public constant REVERT_IF_EXTERNAL_FAIL = 1;
                              /// @dev Flag to call proxy with a sender contract
                              uint256 public constant PROXY_WITH_SENDER = 2;
                              /// @dev Data is hash in DeBridgeGate send method
                              uint256 public constant SEND_HASHED_DATA = 3;
                              /// @dev First 24 bytes from data is gas limit for external call
                              uint256 public constant SEND_EXTERNAL_CALL_GAS_LIMIT = 4;
                              /// @dev Support multi send for externall call
                              uint256 public constant MULTI_SEND = 5;
                              /// @dev Get flag
                              /// @param _packedFlags Flags packed to uint256
                              /// @param _flag Flag to check
                              function getFlag(
                                  uint256 _packedFlags,
                                  uint256 _flag
                              ) internal pure returns (bool) {
                                  uint256 flag = (_packedFlags >> _flag) & uint256(1);
                                  return flag == 1;
                              }
                              /// @dev Set flag
                              /// @param _packedFlags Flags packed to uint256
                              /// @param _flag Flag to set
                              /// @param _value Is set or not set
                               function setFlag(
                                   uint256 _packedFlags,
                                   uint256 _flag,
                                   bool _value
                               ) internal pure returns (uint256) {
                                   if (_value)
                                       return _packedFlags | uint256(1) << _flag;
                                   else
                                       return _packedFlags & ~(uint256(1) << _flag);
                               }
                          }
                          // SPDX-License-Identifier: BUSL-1.1
                          pragma solidity ^0.8.7;
                          interface IWethGate {
                              /// @dev Transfer assets to a receiver.
                              /// @param receiver This address will receive a transfer.
                              /// @param wad Amount in wei
                              function withdraw(address receiver, uint wad) external;
                          }// SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC20 standard as defined in the EIP.
                           */
                          interface IERC20 {
                              /**
                               * @dev Returns the amount of tokens in existence.
                               */
                              function totalSupply() external view returns (uint256);
                              /**
                               * @dev Returns the amount of tokens owned by `account`.
                               */
                              function balanceOf(address account) external view returns (uint256);
                              /**
                               * @dev Moves `amount` tokens from the caller's account to `recipient`.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transfer(address recipient, uint256 amount) external returns (bool);
                              /**
                               * @dev Returns the remaining number of tokens that `spender` will be
                               * allowed to spend on behalf of `owner` through {transferFrom}. This is
                               * zero by default.
                               *
                               * This value changes when {approve} or {transferFrom} are called.
                               */
                              function allowance(address owner, address spender) external view returns (uint256);
                              /**
                               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * IMPORTANT: Beware that changing an allowance with this method brings the risk
                               * that someone may use both the old and the new allowance by unfortunate
                               * transaction ordering. One possible solution to mitigate this race
                               * condition is to first reduce the spender's allowance to 0 and set the
                               * desired value afterwards:
                               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                               *
                               * Emits an {Approval} event.
                               */
                              function approve(address spender, uint256 amount) external returns (bool);
                              /**
                               * @dev Moves `amount` tokens from `sender` to `recipient` using the
                               * allowance mechanism. `amount` is then deducted from the caller's
                               * allowance.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transferFrom(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) external returns (bool);
                              /**
                               * @dev Emitted when `value` tokens are moved from one account (`from`) to
                               * another (`to`).
                               *
                               * Note that `value` may be zero.
                               */
                              event Transfer(address indexed from, address indexed to, uint256 value);
                              /**
                               * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                               * a call to {approve}. `value` is the new allowance.
                               */
                              event Approval(address indexed owner, address indexed spender, uint256 value);
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/extensions/IERC20Metadata.sol)
                          pragma solidity ^0.8.0;
                          import "../IERC20.sol";
                          /**
                           * @dev Interface for the optional metadata functions from the ERC20 standard.
                           *
                           * _Available since v4.1._
                           */
                          interface IERC20Metadata is IERC20 {
                              /**
                               * @dev Returns the name of the token.
                               */
                              function name() external view returns (string memory);
                              /**
                               * @dev Returns the symbol of the token.
                               */
                              function symbol() external view returns (string memory);
                              /**
                               * @dev Returns the decimals places of the token.
                               */
                              function decimals() external view returns (uint8);
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Context.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract Context {
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  return msg.data;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Address.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library AddressUpgradeable {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  assembly {
                                      size := extcodesize(account)
                                  }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  (bool success, ) = recipient.call{value: amount}("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain `call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(
                                  address target,
                                  bytes memory data,
                                  uint256 value
                              ) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(
                                  address target,
                                  bytes memory data,
                                  uint256 value,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  (bool success, bytes memory returndata) = target.call{value: value}(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                               * revert reason using the provided one.
                               *
                               * _Available since v4.3._
                               */
                              function verifyCallResult(
                                  bool success,
                                  bytes memory returndata,
                                  string memory errorMessage
                              ) internal pure returns (bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (access/IAccessControl.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev External interface of AccessControl declared to support ERC165 detection.
                           */
                          interface IAccessControlUpgradeable {
                              /**
                               * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                               *
                               * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                               * {RoleAdminChanged} not being emitted signaling this.
                               *
                               * _Available since v3.1._
                               */
                              event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
                              /**
                               * @dev Emitted when `account` is granted `role`.
                               *
                               * `sender` is the account that originated the contract call, an admin role
                               * bearer except when using {AccessControl-_setupRole}.
                               */
                              event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Emitted when `account` is revoked `role`.
                               *
                               * `sender` is the account that originated the contract call:
                               *   - if using `revokeRole`, it is the admin role bearer
                               *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                               */
                              event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) external view returns (bool);
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {AccessControl-_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) external view returns (bytes32);
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been granted `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) external;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Context.sol)
                          pragma solidity ^0.8.0;
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract ContextUpgradeable is Initializable {
                              function __Context_init() internal initializer {
                                  __Context_init_unchained();
                              }
                              function __Context_init_unchained() internal initializer {
                              }
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  return msg.data;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Strings.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev String operations.
                           */
                          library StringsUpgradeable {
                              bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                               */
                              function toString(uint256 value) internal pure returns (string memory) {
                                  // Inspired by OraclizeAPI's implementation - MIT licence
                                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                                  if (value == 0) {
                                      return "0";
                                  }
                                  uint256 temp = value;
                                  uint256 digits;
                                  while (temp != 0) {
                                      digits++;
                                      temp /= 10;
                                  }
                                  bytes memory buffer = new bytes(digits);
                                  while (value != 0) {
                                      digits -= 1;
                                      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                                      value /= 10;
                                  }
                                  return string(buffer);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                               */
                              function toHexString(uint256 value) internal pure returns (string memory) {
                                  if (value == 0) {
                                      return "0x00";
                                  }
                                  uint256 temp = value;
                                  uint256 length = 0;
                                  while (temp != 0) {
                                      length++;
                                      temp >>= 8;
                                  }
                                  return toHexString(value, length);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                               */
                              function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                                  bytes memory buffer = new bytes(2 * length + 2);
                                  buffer[0] = "0";
                                  buffer[1] = "x";
                                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                                      buffer[i] = _HEX_SYMBOLS[value & 0xf];
                                      value >>= 4;
                                  }
                                  require(value == 0, "Strings: hex length insufficient");
                                  return string(buffer);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/introspection/ERC165.sol)
                          pragma solidity ^0.8.0;
                          import "./IERC165Upgradeable.sol";
                          import "../../proxy/utils/Initializable.sol";
                          /**
                           * @dev Implementation of the {IERC165} interface.
                           *
                           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
                           * for the additional interface id that will be supported. For example:
                           *
                           * ```solidity
                           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
                           * }
                           * ```
                           *
                           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
                           */
                          abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
                              function __ERC165_init() internal initializer {
                                  __ERC165_init_unchained();
                              }
                              function __ERC165_init_unchained() internal initializer {
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IERC165Upgradeable).interfaceId;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/introspection/IERC165.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC165 standard, as defined in the
                           * https://eips.ethereum.org/EIPS/eip-165[EIP].
                           *
                           * Implementers can declare support of contract interfaces, which can then be
                           * queried by others ({ERC165Checker}).
                           *
                           * For an implementation, see {ERC165}.
                           */
                          interface IERC165Upgradeable {
                              /**
                               * @dev Returns true if this contract implements the interface defined by
                               * `interfaceId`. See the corresponding
                               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                               * to learn more about how these ids are created.
                               *
                               * This function call must use less than 30 000 gas.
                               */
                              function supportsInterface(bytes4 interfaceId) external view returns (bool);
                          }
                          

                          File 7 of 12: SignatureVerifier
                          // SPDX-License-Identifier: BUSL-1.1
                          pragma solidity 0.8.7;
                          import "./OraclesManager.sol";
                          import "../interfaces/ISignatureVerifier.sol";
                          import "../libraries/SignatureUtil.sol";
                          /// @dev It's used to verify that a transfer is signed by oracles.
                          contract SignatureVerifier is OraclesManager, ISignatureVerifier {
                              using SignatureUtil for bytes;
                              using SignatureUtil for bytes32;
                              /* ========== STATE VARIABLES ========== */
                              /// @dev Number of required confirmations per block after the extra check is enabled
                              uint8 public confirmationThreshold;
                              /// @dev submissions count in current block
                              uint40 public submissionsInBlock;
                              /// @dev Current block
                              uint40 public currentBlock;
                              /// @dev Debridge gate address
                              address public debridgeAddress;
                              /* ========== ERRORS ========== */
                              error DeBridgeGateBadRole();
                              error NotConfirmedByRequiredOracles();
                              error NotConfirmedThreshold();
                              error SubmissionNotConfirmed();
                              error DuplicateSignatures();
                              /* ========== MODIFIERS ========== */
                              modifier onlyDeBridgeGate() {
                                  if (msg.sender != debridgeAddress) revert DeBridgeGateBadRole();
                                  _;
                              }
                              /* ========== CONSTRUCTOR  ========== */
                              /// @dev Constructor that initializes the most important configurations.
                              /// @param _minConfirmations Common confirmations count.
                              /// @param _confirmationThreshold Confirmations per block after the extra check is enabled.
                              /// @param _excessConfirmations Confirmations count in case of excess activity.
                              function initialize(
                                  uint8 _minConfirmations,
                                  uint8 _confirmationThreshold,
                                  uint8 _excessConfirmations,
                                  address _debridgeAddress
                              ) public initializer {
                                  OraclesManager.initialize(_minConfirmations, _excessConfirmations);
                                  confirmationThreshold = _confirmationThreshold;
                                  debridgeAddress = _debridgeAddress;
                              }
                              /// @inheritdoc ISignatureVerifier
                              function submit(
                                  bytes32 _submissionId,
                                  bytes memory _signatures,
                                  uint8 _excessConfirmations
                              ) external override onlyDeBridgeGate {
                                  //Need confirmation to confirm submission
                                  uint8 needConfirmations = _excessConfirmations > minConfirmations
                                      ? _excessConfirmations
                                      : minConfirmations;
                                  // Count of required(DSRM) oracles confirmation
                                  uint256 currentRequiredOraclesCount;
                                  // stack variable to aggregate confirmations and write to storage once
                                  uint8 confirmations;
                                  uint256 signaturesCount = _countSignatures(_signatures);
                                  address[] memory validators = new address[](signaturesCount);
                                  for (uint256 i = 0; i < signaturesCount; i++) {
                                      (bytes32 r, bytes32 s, uint8 v) = _signatures.parseSignature(i * 65);
                                      address oracle = ecrecover(_submissionId.getUnsignedMsg(), v, r, s);
                                      if (getOracleInfo[oracle].isValid) {
                                          for (uint256 k = 0; k < i; k++) {
                                              if (validators[k] == oracle) revert DuplicateSignatures();
                                          }
                                          validators[i] = oracle;
                                          confirmations += 1;
                                          emit Confirmed(_submissionId, oracle);
                                          if (getOracleInfo[oracle].required) {
                                              currentRequiredOraclesCount += 1;
                                          }
                                          if (
                                              confirmations >= needConfirmations &&
                                              currentRequiredOraclesCount >= requiredOraclesCount
                                          ) {
                                              break;
                                          }
                                      }
                                  }
                                  if (currentRequiredOraclesCount != requiredOraclesCount)
                                      revert NotConfirmedByRequiredOracles();
                                  if (confirmations >= minConfirmations) {
                                      if (currentBlock == uint40(block.number)) {
                                          submissionsInBlock += 1;
                                      } else {
                                          currentBlock = uint40(block.number);
                                          submissionsInBlock = 1;
                                      }
                                      emit SubmissionApproved(_submissionId);
                                  }
                                  if (submissionsInBlock > confirmationThreshold) {
                                      if (confirmations < excessConfirmations) revert NotConfirmedThreshold();
                                  }
                                  if (confirmations < needConfirmations) revert SubmissionNotConfirmed();
                              }
                              /* ========== ADMIN ========== */
                              /// @dev Sets minimal required confirmations.
                              /// @param _confirmationThreshold Confirmation info.
                              function setThreshold(uint8 _confirmationThreshold) external onlyAdmin {
                                  if (_confirmationThreshold == 0) revert WrongArgument();
                                  confirmationThreshold = _confirmationThreshold;
                              }
                              /// @dev Sets core debridge conrtact address.
                              /// @param _debridgeAddress Debridge address.
                              function setDebridgeAddress(address _debridgeAddress) external onlyAdmin {
                                  debridgeAddress = _debridgeAddress;
                              }
                              /* ========== VIEW ========== */
                              /// @dev Check is valid signature
                              /// @param _submissionId Submission identifier.
                              /// @param _signature signature by oracle.
                              function isValidSignature(bytes32 _submissionId, bytes memory _signature)
                                  external
                                  view
                                  returns (bool)
                              {
                                  (bytes32 r, bytes32 s, uint8 v) = _signature.splitSignature();
                                  address oracle = ecrecover(_submissionId.getUnsignedMsg(), v, r, s);
                                  return getOracleInfo[oracle].isValid;
                              }
                              /* ========== INTERNAL ========== */
                              function _countSignatures(bytes memory _signatures) internal pure returns (uint256) {
                                  return _signatures.length % 65 == 0 ? _signatures.length / 65 : 0;
                              }
                              // ============ Version Control ============
                              /// @dev Get this contract's version
                              function version() external pure returns (uint256) {
                                  return 201; // 2.0.1
                              }
                          }// SPDX-License-Identifier: BUSL-1.1
                          pragma solidity 0.8.7;
                          import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
                          import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
                          import "../interfaces/IOraclesManager.sol";
                          /// @dev The base contract for oracles management. Allows adding/removing oracles,
                          /// managing the minimal required amount of confirmations.
                          contract OraclesManager is Initializable, AccessControlUpgradeable, IOraclesManager {
                              /* ========== STATE VARIABLES ========== */
                              /// @dev Minimal required confirmations
                              uint8 public minConfirmations;
                              /// @dev Minimal required confirmations in case of too many confirmations
                              uint8 public excessConfirmations;
                              /// @dev Count of required oracles
                              uint8 public requiredOraclesCount;
                              /// @dev Oracle addresses
                              address[] public oracleAddresses;
                              /// @dev Maps an oracle address to the oracle details
                              mapping(address => OracleInfo) public getOracleInfo;
                              /* ========== ERRORS ========== */
                              error AdminBadRole();
                              error OracleBadRole();
                              error OracleAlreadyExist();
                              error OracleNotFound();
                              error WrongArgument();
                              error LowMinConfirmations();
                              /* ========== MODIFIERS ========== */
                              modifier onlyAdmin() {
                                  if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert AdminBadRole();
                                  _;
                              }
                              modifier onlyOracle() {
                                  if (!getOracleInfo[msg.sender].isValid) revert OracleBadRole();
                                  _;
                              }
                              /* ========== CONSTRUCTOR  ========== */
                              /// @dev Constructor that initializes the most important configurations.
                              /// @param _minConfirmations Minimal required confirmations.
                              /// @param _excessConfirmations Minimal required confirmations in case of too many confirmations.
                              function initialize(uint8 _minConfirmations, uint8 _excessConfirmations) internal {
                                  if (_minConfirmations == 0 || _excessConfirmations < _minConfirmations) revert LowMinConfirmations();
                                  minConfirmations = _minConfirmations;
                                  excessConfirmations = _excessConfirmations;
                                  _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
                              }
                              /* ========== ADMIN ========== */
                              /// @dev Sets minimal required confirmations.
                              /// @param _minConfirmations Minimal required confirmations.
                              function setMinConfirmations(uint8 _minConfirmations) external onlyAdmin {
                                  if (_minConfirmations < oracleAddresses.length / 2 + 1) revert LowMinConfirmations();
                                  minConfirmations = _minConfirmations;
                              }
                              /// @dev Sets minimal required confirmations in case of too many confirmations.
                              /// @param _excessConfirmations Minimal required confirmations in case of too many confirmations.
                              function setExcessConfirmations(uint8 _excessConfirmations) external onlyAdmin {
                                  if (_excessConfirmations < minConfirmations) revert LowMinConfirmations();
                                  excessConfirmations = _excessConfirmations;
                              }
                              /// @dev Add oracles.
                              /// @param _oracles Oracles' addresses.
                              /// @param _required A transfer will not be confirmed without oracles having required set to true,
                              function addOracles(
                                  address[] memory _oracles,
                                  bool[] memory _required
                              ) external onlyAdmin {
                                  if (_oracles.length != _required.length) revert WrongArgument();
                                  if (minConfirmations < (oracleAddresses.length +  _oracles.length) / 2 + 1) revert LowMinConfirmations();
                                  for (uint256 i = 0; i < _oracles.length; i++) {
                                      OracleInfo storage oracleInfo = getOracleInfo[_oracles[i]];
                                      if (oracleInfo.exist) revert OracleAlreadyExist();
                                      oracleAddresses.push(_oracles[i]);
                                      if (_required[i]) {
                                          requiredOraclesCount += 1;
                                      }
                                      oracleInfo.exist = true;
                                      oracleInfo.isValid = true;
                                      oracleInfo.required = _required[i];
                                      emit AddOracle(_oracles[i], _required[i]);
                                  }
                              }
                              /// @dev Update an oracle.
                              /// @param _oracle An oracle address.
                              /// @param _isValid Is this oracle valid, i.e. should it be treated as an oracle.
                              /// @param _required If set to true a transfer will not be confirmed without this oracle.
                              function updateOracle(
                                  address _oracle,
                                  bool _isValid,
                                  bool _required
                              ) external onlyAdmin {
                                  //If oracle is invalid, it must be not required
                                  if (!_isValid && _required) revert WrongArgument();
                                  OracleInfo storage oracleInfo = getOracleInfo[_oracle];
                                  if (!oracleInfo.exist) revert OracleNotFound();
                                  if (oracleInfo.required && !_required) {
                                      requiredOraclesCount -= 1;
                                  } else if (!oracleInfo.required && _required) {
                                      requiredOraclesCount += 1;
                                  }
                                  if (oracleInfo.isValid && !_isValid) {
                                      // remove oracle from oracleAddresses array without keeping an order
                                      for (uint256 i = 0; i < oracleAddresses.length; i++) {
                                          if (oracleAddresses[i] == _oracle) {
                                              oracleAddresses[i] = oracleAddresses[oracleAddresses.length - 1];
                                              oracleAddresses.pop();
                                              break;
                                          }
                                      }
                                  } else if (!oracleInfo.isValid && _isValid) {
                                      if (minConfirmations < (oracleAddresses.length + 1) / 2 + 1) revert LowMinConfirmations();
                                      oracleAddresses.push(_oracle);
                                  }
                                  oracleInfo.isValid = _isValid;
                                  oracleInfo.required = _required;
                                  emit UpdateOracle(_oracle, _required, _isValid);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity 0.8.7;
                          interface ISignatureVerifier {
                              /* ========== EVENTS ========== */
                              /// @dev Emitted once the submission is confirmed by one oracle.
                              event Confirmed(bytes32 submissionId, address operator);
                              /// @dev Emitted once the submission is confirmed by min required amount of oracles.
                              event DeployConfirmed(bytes32 deployId, address operator);
                              /* ========== FUNCTIONS ========== */
                              /// @dev Check confirmation (validate signatures) for the transfer request.
                              /// @param _submissionId Submission identifier.
                              /// @param _signatures Array of signatures by oracles.
                              /// @param _excessConfirmations override min confirmations count
                              function submit(
                                  bytes32 _submissionId,
                                  bytes memory _signatures,
                                  uint8 _excessConfirmations
                              ) external;
                          }// SPDX-License-Identifier: BUSL-1.1
                          pragma solidity 0.8.7;
                          library SignatureUtil {
                              /* ========== ERRORS ========== */
                              error WrongArgumentLength();
                              error SignatureInvalidLength();
                              error SignatureInvalidV();
                              /// @dev Prepares raw msg that was signed by the oracle.
                              /// @param _submissionId Submission identifier.
                              function getUnsignedMsg(bytes32 _submissionId) internal pure returns (bytes32) {
                                  return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
                          32", _submissionId));
                              }
                              /// @dev Splits signature bytes to r,s,v components.
                              /// @param _signature Signature bytes in format r+s+v.
                              function splitSignature(bytes memory _signature)
                                  internal
                                  pure
                                  returns (
                                      bytes32 r,
                                      bytes32 s,
                                      uint8 v
                                  )
                              {
                                  if (_signature.length != 65) revert SignatureInvalidLength();
                                  return parseSignature(_signature, 0);
                              }
                              function parseSignature(bytes memory _signatures, uint256 offset)
                                  internal
                                  pure
                                  returns (
                                      bytes32 r,
                                      bytes32 s,
                                      uint8 v
                                  )
                              {
                                  assembly {
                                      r := mload(add(_signatures, add(32, offset)))
                                      s := mload(add(_signatures, add(64, offset)))
                                      v := and(mload(add(_signatures, add(65, offset))), 0xff)
                                  }
                                  if (v < 27) v += 27;
                                  if (v != 27 && v != 28) revert SignatureInvalidV();
                              }
                              function toUint256(bytes memory _bytes, uint256 _offset)
                                  internal
                                  pure
                                  returns (uint256 result)
                              {
                                  if (_bytes.length < _offset + 32) revert WrongArgumentLength();
                                  assembly {
                                      result := mload(add(add(_bytes, 0x20), _offset))
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (proxy/utils/Initializable.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                           * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
                           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                           *
                           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                           * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                           *
                           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                           *
                           * [CAUTION]
                           * ====
                           * Avoid leaving a contract uninitialized.
                           *
                           * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                           * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
                           * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
                           *
                           * [.hljs-theme-light.nopadding]
                           * ```
                           * /// @custom:oz-upgrades-unsafe-allow constructor
                           * constructor() initializer {}
                           * ```
                           * ====
                           */
                          abstract contract Initializable {
                              /**
                               * @dev Indicates that the contract has been initialized.
                               */
                              bool private _initialized;
                              /**
                               * @dev Indicates that the contract is in the process of being initialized.
                               */
                              bool private _initializing;
                              /**
                               * @dev Modifier to protect an initializer function from being invoked twice.
                               */
                              modifier initializer() {
                                  require(_initializing || !_initialized, "Initializable: contract is already initialized");
                                  bool isTopLevelCall = !_initializing;
                                  if (isTopLevelCall) {
                                      _initializing = true;
                                      _initialized = true;
                                  }
                                  _;
                                  if (isTopLevelCall) {
                                      _initializing = false;
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (access/AccessControl.sol)
                          pragma solidity ^0.8.0;
                          import "./IAccessControlUpgradeable.sol";
                          import "../utils/ContextUpgradeable.sol";
                          import "../utils/StringsUpgradeable.sol";
                          import "../utils/introspection/ERC165Upgradeable.sol";
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Contract module that allows children to implement role-based access
                           * control mechanisms. This is a lightweight version that doesn't allow enumerating role
                           * members except through off-chain means by accessing the contract event logs. Some
                           * applications may benefit from on-chain enumerability, for those cases see
                           * {AccessControlEnumerable}.
                           *
                           * Roles are referred to by their `bytes32` identifier. These should be exposed
                           * in the external API and be unique. The best way to achieve this is by
                           * using `public constant` hash digests:
                           *
                           * ```
                           * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
                           * ```
                           *
                           * Roles can be used to represent a set of permissions. To restrict access to a
                           * function call, use {hasRole}:
                           *
                           * ```
                           * function foo() public {
                           *     require(hasRole(MY_ROLE, msg.sender));
                           *     ...
                           * }
                           * ```
                           *
                           * Roles can be granted and revoked dynamically via the {grantRole} and
                           * {revokeRole} functions. Each role has an associated admin role, and only
                           * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
                           *
                           * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
                           * that only accounts with this role will be able to grant or revoke other
                           * roles. More complex role relationships can be created by using
                           * {_setRoleAdmin}.
                           *
                           * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
                           * grant and revoke this role. Extra precautions should be taken to secure
                           * accounts that have been granted it.
                           */
                          abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
                              function __AccessControl_init() internal initializer {
                                  __Context_init_unchained();
                                  __ERC165_init_unchained();
                                  __AccessControl_init_unchained();
                              }
                              function __AccessControl_init_unchained() internal initializer {
                              }
                              struct RoleData {
                                  mapping(address => bool) members;
                                  bytes32 adminRole;
                              }
                              mapping(bytes32 => RoleData) private _roles;
                              bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
                              /**
                               * @dev Modifier that checks that an account has a specific role. Reverts
                               * with a standardized message including the required role.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               *
                               * _Available since v4.1._
                               */
                              modifier onlyRole(bytes32 role) {
                                  _checkRole(role, _msgSender());
                                  _;
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
                              }
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) public view override returns (bool) {
                                  return _roles[role].members[account];
                              }
                              /**
                               * @dev Revert with a standard message if `account` is missing `role`.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               */
                              function _checkRole(bytes32 role, address account) internal view {
                                  if (!hasRole(role, account)) {
                                      revert(
                                          string(
                                              abi.encodePacked(
                                                  "AccessControl: account ",
                                                  StringsUpgradeable.toHexString(uint160(account), 20),
                                                  " is missing role ",
                                                  StringsUpgradeable.toHexString(uint256(role), 32)
                                              )
                                          )
                                      );
                                  }
                              }
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
                                  return _roles[role].adminRole;
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been revoked `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) public virtual override {
                                  require(account == _msgSender(), "AccessControl: can only renounce roles for self");
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event. Note that unlike {grantRole}, this function doesn't perform any
                               * checks on the calling account.
                               *
                               * [WARNING]
                               * ====
                               * This function should only be called from the constructor when setting
                               * up the initial roles for the system.
                               *
                               * Using this function in any other way is effectively circumventing the admin
                               * system imposed by {AccessControl}.
                               * ====
                               *
                               * NOTE: This function is deprecated in favor of {_grantRole}.
                               */
                              function _setupRole(bytes32 role, address account) internal virtual {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Sets `adminRole` as ``role``'s admin role.
                               *
                               * Emits a {RoleAdminChanged} event.
                               */
                              function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                                  bytes32 previousAdminRole = getRoleAdmin(role);
                                  _roles[role].adminRole = adminRole;
                                  emit RoleAdminChanged(role, previousAdminRole, adminRole);
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * Internal function without access restriction.
                               */
                              function _grantRole(bytes32 role, address account) internal virtual {
                                  if (!hasRole(role, account)) {
                                      _roles[role].members[account] = true;
                                      emit RoleGranted(role, account, _msgSender());
                                  }
                              }
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * Internal function without access restriction.
                               */
                              function _revokeRole(bytes32 role, address account) internal virtual {
                                  if (hasRole(role, account)) {
                                      _roles[role].members[account] = false;
                                      emit RoleRevoked(role, account, _msgSender());
                                  }
                              }
                              uint256[49] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity 0.8.7;
                          interface IOraclesManager {
                              /* ========== STRUCTS ========== */
                              struct OracleInfo {
                                  bool exist; // exist oracle
                                  bool isValid; // is valid oracle
                                  bool required; // without this oracle (DSRM), the transfer will not be confirmed
                              }
                              /* ========== EVENTS ========== */
                              /// @dev Emitted when an oracle is added
                              /// @param oracle Address of an added oracle
                              /// @param required Is this oracle's signature required for every transfer
                              event AddOracle(address oracle, bool required);
                              /// @dev Emitted when an oracle is updated
                              /// @param oracle Address of an updated oracle
                              /// @param required Is this oracle's signature required for every transfer
                              /// @param isValid Is this oracle valid, i.e. should it be treated as an oracle
                              event UpdateOracle(address oracle, bool required, bool isValid);
                              /// @dev Emitted once the submission is confirmed by min required amount of oracles
                              event DeployApproved(bytes32 deployId);
                              /// @dev Emitted once the submission is confirmed by min required amount of oracles
                              event SubmissionApproved(bytes32 submissionId);
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (access/IAccessControl.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev External interface of AccessControl declared to support ERC165 detection.
                           */
                          interface IAccessControlUpgradeable {
                              /**
                               * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                               *
                               * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                               * {RoleAdminChanged} not being emitted signaling this.
                               *
                               * _Available since v3.1._
                               */
                              event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
                              /**
                               * @dev Emitted when `account` is granted `role`.
                               *
                               * `sender` is the account that originated the contract call, an admin role
                               * bearer except when using {AccessControl-_setupRole}.
                               */
                              event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Emitted when `account` is revoked `role`.
                               *
                               * `sender` is the account that originated the contract call:
                               *   - if using `revokeRole`, it is the admin role bearer
                               *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                               */
                              event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) external view returns (bool);
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {AccessControl-_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) external view returns (bytes32);
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been granted `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) external;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Context.sol)
                          pragma solidity ^0.8.0;
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract ContextUpgradeable is Initializable {
                              function __Context_init() internal initializer {
                                  __Context_init_unchained();
                              }
                              function __Context_init_unchained() internal initializer {
                              }
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  return msg.data;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Strings.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev String operations.
                           */
                          library StringsUpgradeable {
                              bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                               */
                              function toString(uint256 value) internal pure returns (string memory) {
                                  // Inspired by OraclizeAPI's implementation - MIT licence
                                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                                  if (value == 0) {
                                      return "0";
                                  }
                                  uint256 temp = value;
                                  uint256 digits;
                                  while (temp != 0) {
                                      digits++;
                                      temp /= 10;
                                  }
                                  bytes memory buffer = new bytes(digits);
                                  while (value != 0) {
                                      digits -= 1;
                                      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                                      value /= 10;
                                  }
                                  return string(buffer);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                               */
                              function toHexString(uint256 value) internal pure returns (string memory) {
                                  if (value == 0) {
                                      return "0x00";
                                  }
                                  uint256 temp = value;
                                  uint256 length = 0;
                                  while (temp != 0) {
                                      length++;
                                      temp >>= 8;
                                  }
                                  return toHexString(value, length);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                               */
                              function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                                  bytes memory buffer = new bytes(2 * length + 2);
                                  buffer[0] = "0";
                                  buffer[1] = "x";
                                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                                      buffer[i] = _HEX_SYMBOLS[value & 0xf];
                                      value >>= 4;
                                  }
                                  require(value == 0, "Strings: hex length insufficient");
                                  return string(buffer);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/introspection/ERC165.sol)
                          pragma solidity ^0.8.0;
                          import "./IERC165Upgradeable.sol";
                          import "../../proxy/utils/Initializable.sol";
                          /**
                           * @dev Implementation of the {IERC165} interface.
                           *
                           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
                           * for the additional interface id that will be supported. For example:
                           *
                           * ```solidity
                           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
                           * }
                           * ```
                           *
                           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
                           */
                          abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
                              function __ERC165_init() internal initializer {
                                  __ERC165_init_unchained();
                              }
                              function __ERC165_init_unchained() internal initializer {
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IERC165Upgradeable).interfaceId;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/introspection/IERC165.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC165 standard, as defined in the
                           * https://eips.ethereum.org/EIPS/eip-165[EIP].
                           *
                           * Implementers can declare support of contract interfaces, which can then be
                           * queried by others ({ERC165Checker}).
                           *
                           * For an implementation, see {ERC165}.
                           */
                          interface IERC165Upgradeable {
                              /**
                               * @dev Returns true if this contract implements the interface defined by
                               * `interfaceId`. See the corresponding
                               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                               * to learn more about how these ids are created.
                               *
                               * This function call must use less than 30 000 gas.
                               */
                              function supportsInterface(bytes4 interfaceId) external view returns (bool);
                          }
                          

                          File 8 of 12: TransparentUpgradeableProxy
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
                          // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
                          contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
                              constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../Proxy.sol";
                          import "./ERC1967Upgrade.sol";
                          /**
                           * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                           * implementation address that can be changed. This address is stored in storage in the location specified by
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                           * implementation behind the proxy.
                           */
                          contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                              /**
                               * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                               *
                               * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                               * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                               */
                              constructor(address _logic, bytes memory _data) payable {
                                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                                  _upgradeToAndCall(_logic, _data, false);
                              }
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _implementation() internal view virtual override returns (address impl) {
                                  return ERC1967Upgrade._getImplementation();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Proxy.sol";
                          /**
                           * @dev This contract implements a proxy that is upgradeable by an admin.
                           *
                           * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
                           * clashing], which can potentially be used in an attack, this contract uses the
                           * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
                           * things that go hand in hand:
                           *
                           * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
                           * that call matches one of the admin functions exposed by the proxy itself.
                           * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
                           * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
                           * "admin cannot fallback to proxy target".
                           *
                           * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
                           * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
                           * to sudden errors when trying to call a function from the proxy implementation.
                           *
                           * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
                           * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
                           */
                          contract TransparentUpgradeableProxy is ERC1967Proxy {
                              /**
                               * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                               * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                               */
                              constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                                  assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                                  _changeAdmin(admin_);
                              }
                              /**
                               * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                               */
                              modifier ifAdmin() {
                                  if (msg.sender == _getAdmin()) {
                                      _;
                                  } else {
                                      _fallback();
                                  }
                              }
                              /**
                               * @dev Returns the current admin.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                               */
                              function admin() external ifAdmin returns (address admin_) {
                                  admin_ = _getAdmin();
                              }
                              /**
                               * @dev Returns the current implementation.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                               */
                              function implementation() external ifAdmin returns (address implementation_) {
                                  implementation_ = _implementation();
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                               */
                              function changeAdmin(address newAdmin) external virtual ifAdmin {
                                  _changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                               */
                              function upgradeTo(address newImplementation) external ifAdmin {
                                  _upgradeToAndCall(newImplementation, bytes(""), false);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                               * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                               * proxied contract.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                               */
                              function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                                  _upgradeToAndCall(newImplementation, data, true);
                              }
                              /**
                               * @dev Returns the current admin.
                               */
                              function _admin() internal view virtual returns (address) {
                                  return _getAdmin();
                              }
                              /**
                               * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                               */
                              function _beforeFallback() internal virtual override {
                                  require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                                  super._beforeFallback();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./TransparentUpgradeableProxy.sol";
                          import "../../access/Ownable.sol";
                          /**
                           * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
                           * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
                           */
                          contract ProxyAdmin is Ownable {
                              /**
                               * @dev Returns the current implementation of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("implementation()")) == 0x5c60da1b
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Returns the current admin of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("admin()")) == 0xf851a440
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Changes the admin of `proxy` to `newAdmin`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the current admin of `proxy`.
                               */
                              function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                                  proxy.changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                                  proxy.upgradeTo(implementation);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
                               * {TransparentUpgradeableProxy-upgradeToAndCall}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                                  proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                           * be specified by overriding the virtual {_implementation} function.
                           *
                           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                           * different contract through the {_delegate} function.
                           *
                           * The success and return data of the delegated call will be returned back to the caller of the proxy.
                           */
                          abstract contract Proxy {
                              /**
                               * @dev Delegates the current call to `implementation`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _delegate(address implementation) internal virtual {
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly {
                                      // Copy msg.data. We take full control of memory in this inline assembly
                                      // block because it will not return to Solidity code. We overwrite the
                                      // Solidity scratch pad at memory position 0.
                                      calldatacopy(0, 0, calldatasize())
                                      // Call the implementation.
                                      // out and outsize are 0 because we don't know the size yet.
                                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                      // Copy the returned data.
                                      returndatacopy(0, 0, returndatasize())
                                      switch result
                                      // delegatecall returns 0 on error.
                                      case 0 { revert(0, returndatasize()) }
                                      default { return(0, returndatasize()) }
                                  }
                              }
                              /**
                               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                               * and {_fallback} should delegate.
                               */
                              function _implementation() internal view virtual returns (address);
                              /**
                               * @dev Delegates the current call to the address returned by `_implementation()`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _fallback() internal virtual {
                                  _beforeFallback();
                                  _delegate(_implementation());
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                               * function in the contract matches the call data.
                               */
                              fallback () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                               * is empty.
                               */
                              receive () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                               * call, or as part of the Solidity `fallback` or `receive` functions.
                               *
                               * If overriden should call `super._beforeFallback()`.
                               */
                              function _beforeFallback() internal virtual {
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "../beacon/IBeacon.sol";
                          import "../../utils/Address.sol";
                          import "../../utils/StorageSlot.sol";
                          /**
                           * @dev This abstract contract provides getters and event emitting update functions for
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                           *
                           * _Available since v4.1._
                           *
                           * @custom:oz-upgrades-unsafe-allow delegatecall
                           */
                          abstract contract ERC1967Upgrade {
                              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                              /**
                               * @dev Storage slot with the address of the current implementation.
                               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                              /**
                               * @dev Emitted when the implementation is upgraded.
                               */
                              event Upgraded(address indexed implementation);
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _getImplementation() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 implementation slot.
                               */
                              function _setImplementation(address newImplementation) private {
                                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                              }
                              /**
                               * @dev Perform implementation upgrade
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeTo(address newImplementation) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                              /**
                               * @dev Perform implementation upgrade with additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                              }
                              /**
                               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                                  address oldImplementation = _getImplementation();
                                  // Initial upgrade and setup call
                                  _setImplementation(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                                  // Perform rollback test if not already in progress
                                  StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                                  if (!rollbackTesting.value) {
                                      // Trigger rollback using upgradeTo from the new implementation
                                      rollbackTesting.value = true;
                                      Address.functionDelegateCall(
                                          newImplementation,
                                          abi.encodeWithSignature(
                                              "upgradeTo(address)",
                                              oldImplementation
                                          )
                                      );
                                      rollbackTesting.value = false;
                                      // Check rollback was effective
                                      require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                      // Finally reset to the new implementation and log the upgrade
                                      _setImplementation(newImplementation);
                                      emit Upgraded(newImplementation);
                                  }
                              }
                              /**
                               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                               *
                               * Emits a {BeaconUpgraded} event.
                               */
                              function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                                  _setBeacon(newBeacon);
                                  emit BeaconUpgraded(newBeacon);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                                  }
                              }
                              /**
                               * @dev Storage slot with the admin of the contract.
                               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                              /**
                               * @dev Emitted when the admin account has changed.
                               */
                              event AdminChanged(address previousAdmin, address newAdmin);
                              /**
                               * @dev Returns the current admin.
                               */
                              function _getAdmin() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 admin slot.
                               */
                              function _setAdmin(address newAdmin) private {
                                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               */
                              function _changeAdmin(address newAdmin) internal {
                                  emit AdminChanged(_getAdmin(), newAdmin);
                                  _setAdmin(newAdmin);
                              }
                              /**
                               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                               */
                              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                              /**
                               * @dev Emitted when the beacon is upgraded.
                               */
                              event BeaconUpgraded(address indexed beacon);
                              /**
                               * @dev Returns the current beacon.
                               */
                              function _getBeacon() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                              }
                              /**
                               * @dev Stores a new beacon in the EIP1967 beacon slot.
                               */
                              function _setBeacon(address newBeacon) private {
                                  require(
                                      Address.isContract(newBeacon),
                                      "ERC1967: new beacon is not a contract"
                                  );
                                  require(
                                      Address.isContract(IBeacon(newBeacon).implementation()),
                                      "ERC1967: beacon implementation is not a contract"
                                  );
                                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is the interface that {BeaconProxy} expects of its beacon.
                           */
                          interface IBeacon {
                              /**
                               * @dev Must return an address that can be used as a delegate call target.
                               *
                               * {BeaconProxy} will check that this address is a contract.
                               */
                              function implementation() external view returns (address);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library Address {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly { size := extcodesize(account) }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                                  (bool success, ) = recipient.call{ value: amount }("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain`call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  require(isContract(target), "Address: delegate call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.delegatecall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          // solhint-disable-next-line no-inline-assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Library for reading and writing primitive types to specific storage slots.
                           *
                           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                           * This library helps with reading and writing to such slots without the need for inline assembly.
                           *
                           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                           *
                           * Example usage to set ERC1967 implementation slot:
                           * ```
                           * contract ERC1967 {
                           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                           *
                           *     function _getImplementation() internal view returns (address) {
                           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                           *     }
                           *
                           *     function _setImplementation(address newImplementation) internal {
                           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                           *     }
                           * }
                           * ```
                           *
                           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                           */
                          library StorageSlot {
                              struct AddressSlot {
                                  address value;
                              }
                              struct BooleanSlot {
                                  bool value;
                              }
                              struct Bytes32Slot {
                                  bytes32 value;
                              }
                              struct Uint256Slot {
                                  uint256 value;
                              }
                              /**
                               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                               */
                              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                               */
                              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                               */
                              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                               */
                              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../utils/Context.sol";
                          /**
                           * @dev Contract module which provides a basic access control mechanism, where
                           * there is an account (an owner) that can be granted exclusive access to
                           * specific functions.
                           *
                           * By default, the owner account will be the one that deploys the contract. This
                           * can later be changed with {transferOwnership}.
                           *
                           * This module is used through inheritance. It will make available the modifier
                           * `onlyOwner`, which can be applied to your functions to restrict their use to
                           * the owner.
                           */
                          abstract contract Ownable is Context {
                              address private _owner;
                              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                              /**
                               * @dev Initializes the contract setting the deployer as the initial owner.
                               */
                              constructor () {
                                  address msgSender = _msgSender();
                                  _owner = msgSender;
                                  emit OwnershipTransferred(address(0), msgSender);
                              }
                              /**
                               * @dev Returns the address of the current owner.
                               */
                              function owner() public view virtual returns (address) {
                                  return _owner;
                              }
                              /**
                               * @dev Throws if called by any account other than the owner.
                               */
                              modifier onlyOwner() {
                                  require(owner() == _msgSender(), "Ownable: caller is not the owner");
                                  _;
                              }
                              /**
                               * @dev 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.
                               */
                              function renounceOwnership() public virtual onlyOwner {
                                  emit OwnershipTransferred(_owner, address(0));
                                  _owner = address(0);
                              }
                              /**
                               * @dev Transfers ownership of the contract to a new account (`newOwner`).
                               * Can only be called by the current owner.
                               */
                              function transferOwnership(address newOwner) public virtual onlyOwner {
                                  require(newOwner != address(0), "Ownable: new owner is the zero address");
                                  emit OwnershipTransferred(_owner, newOwner);
                                  _owner = newOwner;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /*
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract Context {
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                                  return msg.data;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Upgrade.sol";
                          /**
                           * @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes
                           * publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify
                           * continuation of the upgradability.
                           *
                           * The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism.
                           *
                           * _Available since v4.1._
                           */
                          abstract contract UUPSUpgradeable is ERC1967Upgrade {
                              function upgradeTo(address newImplementation) external virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, bytes(""), false);
                              }
                              function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, data, true);
                              }
                              function _authorizeUpgrade(address newImplementation) internal virtual;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
                          abstract contract Proxiable is UUPSUpgradeable {
                              function _authorizeUpgrade(address newImplementation) internal override {
                                  _beforeUpgrade(newImplementation);
                              }
                              function _beforeUpgrade(address newImplementation) internal virtual;
                          }
                          contract ChildOfProxiable is Proxiable {
                              function _beforeUpgrade(address newImplementation) internal virtual override {}
                          }
                          

                          File 9 of 12: DeBridgeTokenDeployer
                          // SPDX-License-Identifier: BUSL-1.1
                          pragma solidity 0.8.7;
                          import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
                          import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
                          import "../interfaces/IDeBridgeTokenDeployer.sol";
                          import "../periphery/DeBridgeToken.sol";
                          import "../periphery/DeBridgeTokenProxy.sol";
                          contract DeBridgeTokenDeployer is
                              Initializable,
                              AccessControlUpgradeable,
                              IDeBridgeTokenDeployer
                          {
                              /* ========== STATE VARIABLES ========== */
                              /// @dev Address of deBridgeToken implementation
                              address public tokenImplementation;
                              /// @dev An address to set as admin for any deployed deBridgeToken
                              address public deBridgeTokenAdmin;
                              /// @dev Debridge gate address
                              address public debridgeAddress;
                              /// @dev Maps debridge id to deBridgeToken address
                              mapping(bytes32 => address) public getDeployedAssetAddress;
                              /// @dev Maps debridge id to overridden token info (name, symbol). Used when autogenerated
                              /// values for a token are not ideal.
                              mapping(bytes32 => OverridedTokenInfo) public overridedTokens;
                              /* ========== STRUCTS ========== */
                              struct OverridedTokenInfo {
                                  bool accept;
                                  string name;
                                  string symbol;
                              }
                              /* ========== ERRORS ========== */
                              error WrongArgument();
                              error DeployedAlready();
                              error AdminBadRole();
                              error DeBridgeGateBadRole();
                              /* ========== MODIFIERS ========== */
                              modifier onlyAdmin() {
                                  if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert AdminBadRole();
                                  _;
                              }
                              modifier onlyDeBridgeGate() {
                                  if (msg.sender != debridgeAddress) revert DeBridgeGateBadRole();
                                  _;
                              }
                              /* ========== CONSTRUCTOR  ========== */
                              /// @dev Constructor that initializes the most important configurations.
                              /// @param _tokenImplementation Address of deBridgeToken implementation
                              /// @param _deBridgeTokenAdmin Address to set as admin for any deployed deBridgeToken
                              /// @param _debridgeAddress DeBridge gate address
                              function initialize(
                                  address _tokenImplementation,
                                  address _deBridgeTokenAdmin,
                                  address _debridgeAddress
                              ) public initializer {
                                  tokenImplementation = _tokenImplementation;
                                  deBridgeTokenAdmin = _deBridgeTokenAdmin;
                                  debridgeAddress = _debridgeAddress;
                                  _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
                              }
                              /// @inheritdoc IDeBridgeTokenDeployer
                              function deployAsset(
                                  bytes32 _debridgeId,
                                  string memory _name,
                                  string memory _symbol,
                                  uint8 _decimals)
                              external
                              override
                              onlyDeBridgeGate
                              returns (address deBridgeTokenAddress)
                              {
                                  if (getDeployedAssetAddress[_debridgeId] != address(0)) revert DeployedAlready();
                                  OverridedTokenInfo memory overridedToken = overridedTokens[_debridgeId];
                                  if (overridedToken.accept) {
                                      _name = overridedToken.name;
                                      _symbol = overridedToken.symbol;
                                  }
                                  address[] memory minters = new address[](1);
                                  minters[0] = debridgeAddress;
                                  // Initialize args
                                  bytes memory initialisationArgs = abi.encodeWithSelector(
                                      DeBridgeToken.initialize.selector,
                                      _name,
                                      _symbol,
                                      _decimals,
                                      deBridgeTokenAdmin,
                                      minters
                                  );
                                  // initialize Proxy
                                  bytes memory constructorArgs = abi.encode(address(this), initialisationArgs);
                                  // deployment code
                                  bytes memory bytecode = abi.encodePacked(type(DeBridgeTokenProxy).creationCode, constructorArgs);
                                  assembly {
                                  // debridgeId is a salt
                                      deBridgeTokenAddress := create2(0, add(bytecode, 0x20), mload(bytecode), _debridgeId)
                                      if iszero(extcodesize(deBridgeTokenAddress)) {
                                          revert(0, 0)
                                      }
                                  }
                                  getDeployedAssetAddress[_debridgeId] = deBridgeTokenAddress;
                                  emit DeBridgeTokenDeployed(
                                      deBridgeTokenAddress,
                                      _name,
                                      _symbol,
                                      _decimals
                                  );
                              }
                              /// @dev Beacon getter for the deBridgeToken contracts
                              function implementation() public view returns (address) {
                                  return tokenImplementation;
                              }
                              /* ========== ADMIN ========== */
                              /// @dev Set deBridgeToken implementation contract address
                              /// @param _impl Wrapped asset implementation contract address.
                              function setTokenImplementation(address _impl) external onlyAdmin {
                                  if (_impl == address(0)) revert WrongArgument();
                                  tokenImplementation = _impl;
                              }
                              /// @dev Set admin for any deployed deBridgeToken.
                              /// @param _deBridgeTokenAdmin Admin address.
                              function setDeBridgeTokenAdmin(address _deBridgeTokenAdmin) external onlyAdmin {
                                  if (_deBridgeTokenAdmin == address(0)) revert WrongArgument();
                                  deBridgeTokenAdmin = _deBridgeTokenAdmin;
                              }
                              /// @dev Sets core debridge contract address.
                              /// @param _debridgeAddress Debridge address.
                              function setDebridgeAddress(address _debridgeAddress) external onlyAdmin {
                                  if (_debridgeAddress == address(0)) revert WrongArgument();
                                  debridgeAddress = _debridgeAddress;
                              }
                              /// @dev Override specific tokens name/symbol
                              /// @param _debridgeIds Array of debridgeIds for tokens
                              /// @param _tokens Array of new name/symbols for tokens
                              function setOverridedTokenInfo (
                                  bytes32[] memory _debridgeIds,
                                  OverridedTokenInfo[] memory _tokens
                              ) external onlyAdmin {
                                  if (_debridgeIds.length != _tokens.length) revert WrongArgument();
                                  for (uint256 i = 0; i < _debridgeIds.length; i++) {
                                      overridedTokens[_debridgeIds[i]] = _tokens[i];
                                  }
                              }
                              // ============ Version Control ============
                              /// @dev Get this contract's version
                              function version() external pure returns (uint256) {
                                  return 110; // 1.1.0
                              }
                          }// SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                           * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
                           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                           *
                           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                           * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                           *
                           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                           */
                          abstract contract Initializable {
                              /**
                               * @dev Indicates that the contract has been initialized.
                               */
                              bool private _initialized;
                              /**
                               * @dev Indicates that the contract is in the process of being initialized.
                               */
                              bool private _initializing;
                              /**
                               * @dev Modifier to protect an initializer function from being invoked twice.
                               */
                              modifier initializer() {
                                  require(_initializing || !_initialized, "Initializable: contract is already initialized");
                                  bool isTopLevelCall = !_initializing;
                                  if (isTopLevelCall) {
                                      _initializing = true;
                                      _initialized = true;
                                  }
                                  _;
                                  if (isTopLevelCall) {
                                      _initializing = false;
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./IAccessControlUpgradeable.sol";
                          import "../utils/ContextUpgradeable.sol";
                          import "../utils/StringsUpgradeable.sol";
                          import "../utils/introspection/ERC165Upgradeable.sol";
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Contract module that allows children to implement role-based access
                           * control mechanisms. This is a lightweight version that doesn't allow enumerating role
                           * members except through off-chain means by accessing the contract event logs. Some
                           * applications may benefit from on-chain enumerability, for those cases see
                           * {AccessControlEnumerable}.
                           *
                           * Roles are referred to by their `bytes32` identifier. These should be exposed
                           * in the external API and be unique. The best way to achieve this is by
                           * using `public constant` hash digests:
                           *
                           * ```
                           * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
                           * ```
                           *
                           * Roles can be used to represent a set of permissions. To restrict access to a
                           * function call, use {hasRole}:
                           *
                           * ```
                           * function foo() public {
                           *     require(hasRole(MY_ROLE, msg.sender));
                           *     ...
                           * }
                           * ```
                           *
                           * Roles can be granted and revoked dynamically via the {grantRole} and
                           * {revokeRole} functions. Each role has an associated admin role, and only
                           * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
                           *
                           * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
                           * that only accounts with this role will be able to grant or revoke other
                           * roles. More complex role relationships can be created by using
                           * {_setRoleAdmin}.
                           *
                           * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
                           * grant and revoke this role. Extra precautions should be taken to secure
                           * accounts that have been granted it.
                           */
                          abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
                              function __AccessControl_init() internal initializer {
                                  __Context_init_unchained();
                                  __ERC165_init_unchained();
                                  __AccessControl_init_unchained();
                              }
                              function __AccessControl_init_unchained() internal initializer {
                              }
                              struct RoleData {
                                  mapping(address => bool) members;
                                  bytes32 adminRole;
                              }
                              mapping(bytes32 => RoleData) private _roles;
                              bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
                              /**
                               * @dev Modifier that checks that an account has a specific role. Reverts
                               * with a standardized message including the required role.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               *
                               * _Available since v4.1._
                               */
                              modifier onlyRole(bytes32 role) {
                                  _checkRole(role, _msgSender());
                                  _;
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
                              }
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) public view override returns (bool) {
                                  return _roles[role].members[account];
                              }
                              /**
                               * @dev Revert with a standard message if `account` is missing `role`.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               */
                              function _checkRole(bytes32 role, address account) internal view {
                                  if (!hasRole(role, account)) {
                                      revert(
                                          string(
                                              abi.encodePacked(
                                                  "AccessControl: account ",
                                                  StringsUpgradeable.toHexString(uint160(account), 20),
                                                  " is missing role ",
                                                  StringsUpgradeable.toHexString(uint256(role), 32)
                                              )
                                          )
                                      );
                                  }
                              }
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
                                  return _roles[role].adminRole;
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been granted `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) public virtual override {
                                  require(account == _msgSender(), "AccessControl: can only renounce roles for self");
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event. Note that unlike {grantRole}, this function doesn't perform any
                               * checks on the calling account.
                               *
                               * [WARNING]
                               * ====
                               * This function should only be called from the constructor when setting
                               * up the initial roles for the system.
                               *
                               * Using this function in any other way is effectively circumventing the admin
                               * system imposed by {AccessControl}.
                               * ====
                               */
                              function _setupRole(bytes32 role, address account) internal virtual {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Sets `adminRole` as ``role``'s admin role.
                               *
                               * Emits a {RoleAdminChanged} event.
                               */
                              function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                                  bytes32 previousAdminRole = getRoleAdmin(role);
                                  _roles[role].adminRole = adminRole;
                                  emit RoleAdminChanged(role, previousAdminRole, adminRole);
                              }
                              function _grantRole(bytes32 role, address account) private {
                                  if (!hasRole(role, account)) {
                                      _roles[role].members[account] = true;
                                      emit RoleGranted(role, account, _msgSender());
                                  }
                              }
                              function _revokeRole(bytes32 role, address account) private {
                                  if (hasRole(role, account)) {
                                      _roles[role].members[account] = false;
                                      emit RoleRevoked(role, account, _msgSender());
                                  }
                              }
                              uint256[49] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity 0.8.7;
                          interface IDeBridgeTokenDeployer {
                              /// @dev Deploy a deToken(DeBridgeTokenProxy) for an asset
                              /// @param _debridgeId Asset id, see DeBridgeGate.getDebridgeId
                              /// @param _name The asset's name
                              /// @param _symbol The asset's symbol
                              /// @param _decimals The asset's decimals
                              function deployAsset(
                                  bytes32 _debridgeId,
                                  string memory _name,
                                  string memory _symbol,
                                  uint8 _decimals
                              ) external returns (address deTokenAddress);
                              /// @dev Emitted when a deToken(DeBridgeTokenProxy) is deployed using this contract
                              event DeBridgeTokenDeployed(
                                  address asset,
                                  string name,
                                  string symbol,
                                  uint8 decimals
                              );
                          }// SPDX-License-Identifier: BUSL-1.1
                          pragma solidity 0.8.7;
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
                          import "../interfaces/IDeBridgeToken.sol";
                          contract DeBridgeToken is ERC20Upgradeable, AccessControlUpgradeable, IDeBridgeToken {
                              bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); // minter role identifier
                              bytes32 public DOMAIN_SEPARATOR;
                              bytes32 public constant PERMIT_TYPEHASH =
                                  0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
                              mapping(address => uint256) public nonces; // transfer's counter
                              uint8 internal _decimals;
                              /* ========== ERRORS ========== */
                              error MinterBadRole();
                              /* ========== MODIFIERS ========== */
                              modifier onlyMinter() {
                                  if (!hasRole(MINTER_ROLE, msg.sender)) revert MinterBadRole();
                                  _;
                              }
                              /// @dev Constructor that initializes the most important configurations.
                              /// @param name_ Asset's name.
                              /// @param symbol_ Asset's symbol.
                              /// @param minters The accounts allowed to int new tokens.
                              function initialize(
                                  string memory name_,
                                  string memory symbol_,
                                  uint8 decimals_,
                                  address admin,
                                  address[] memory minters
                              ) public initializer {
                                  _decimals = decimals_;
                                  name_ = string(abi.encodePacked("deBridge ",
                                      bytes(name_).length == 0 ? symbol_ : name_));
                                  symbol_ = string(abi.encodePacked("de", symbol_));
                                  __ERC20_init(name_, symbol_);
                                  _setupRole(DEFAULT_ADMIN_ROLE, admin);
                                  for (uint256 i = 0; i < minters.length; i++) {
                                      _setupRole(MINTER_ROLE, minters[i]);
                                  }
                                  uint256 chainId;
                                  assembly {
                                      chainId := chainid()
                                  }
                                  DOMAIN_SEPARATOR = keccak256(
                                      abi.encode(
                                          keccak256(
                                              "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                                          ),
                                          keccak256(bytes(name_)),
                                          keccak256(bytes("1")),
                                          chainId,
                                          address(this)
                                      )
                                  );
                              }
                              /// @dev Issues new tokens.
                              /// @param _receiver Token's receiver.
                              /// @param _amount Amount to be minted.
                              function mint(address _receiver, uint256 _amount) external override onlyMinter {
                                  _mint(_receiver, _amount);
                              }
                              /// @dev Destroys existed tokens.
                              /// @param _amount Amount to be burnt.
                              function burn(uint256 _amount) external override onlyMinter {
                                  _burn(msg.sender, _amount);
                              }
                              /// @dev Approves the spender by signature.
                              /// @param _owner Token's owner.
                              /// @param _spender Account to be approved.
                              /// @param _value Amount to be approved.
                              /// @param _deadline The permit valid until.
                              /// @param _v Signature part.
                              /// @param _r Signature part.
                              /// @param _s Signature part.
                              function permit(
                                  address _owner,
                                  address _spender,
                                  uint256 _value,
                                  uint256 _deadline,
                                  uint8 _v,
                                  bytes32 _r,
                                  bytes32 _s
                              ) external override {
                                  require(_deadline >= block.timestamp, "permit: EXPIRED");
                                  bytes32 digest = keccak256(
                                      abi.encodePacked(
                                          "\\x19\\x01",
                                          DOMAIN_SEPARATOR,
                                          keccak256(
                                              abi.encode(
                                                  PERMIT_TYPEHASH,
                                                  _owner,
                                                  _spender,
                                                  _value,
                                                  nonces[_owner]++,
                                                  _deadline
                                              )
                                          )
                                      )
                                  );
                                  address recoveredAddress = ecrecover(digest, _v, _r, _s);
                                  require(
                                      recoveredAddress != address(0) && recoveredAddress == _owner,
                                      "permit: invalid signature"
                                  );
                                  _approve(_owner, _spender, _value);
                              }
                              function decimals() public view override returns (uint8) {
                                  return _decimals;
                              }
                          }
                          // SPDX-License-Identifier: BUSL-1.1
                          pragma solidity 0.8.7;
                          import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
                          contract DeBridgeTokenProxy is BeaconProxy {
                              constructor(address beacon, bytes memory data) BeaconProxy(beacon, data) {
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev External interface of AccessControl declared to support ERC165 detection.
                           */
                          interface IAccessControlUpgradeable {
                              /**
                               * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                               *
                               * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                               * {RoleAdminChanged} not being emitted signaling this.
                               *
                               * _Available since v3.1._
                               */
                              event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
                              /**
                               * @dev Emitted when `account` is granted `role`.
                               *
                               * `sender` is the account that originated the contract call, an admin role
                               * bearer except when using {AccessControl-_setupRole}.
                               */
                              event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Emitted when `account` is revoked `role`.
                               *
                               * `sender` is the account that originated the contract call:
                               *   - if using `revokeRole`, it is the admin role bearer
                               *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                               */
                              event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) external view returns (bool);
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {AccessControl-_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) external view returns (bytes32);
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been granted `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) external;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract ContextUpgradeable is Initializable {
                              function __Context_init() internal initializer {
                                  __Context_init_unchained();
                              }
                              function __Context_init_unchained() internal initializer {
                              }
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  return msg.data;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev String operations.
                           */
                          library StringsUpgradeable {
                              bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                               */
                              function toString(uint256 value) internal pure returns (string memory) {
                                  // Inspired by OraclizeAPI's implementation - MIT licence
                                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                                  if (value == 0) {
                                      return "0";
                                  }
                                  uint256 temp = value;
                                  uint256 digits;
                                  while (temp != 0) {
                                      digits++;
                                      temp /= 10;
                                  }
                                  bytes memory buffer = new bytes(digits);
                                  while (value != 0) {
                                      digits -= 1;
                                      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                                      value /= 10;
                                  }
                                  return string(buffer);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                               */
                              function toHexString(uint256 value) internal pure returns (string memory) {
                                  if (value == 0) {
                                      return "0x00";
                                  }
                                  uint256 temp = value;
                                  uint256 length = 0;
                                  while (temp != 0) {
                                      length++;
                                      temp >>= 8;
                                  }
                                  return toHexString(value, length);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                               */
                              function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                                  bytes memory buffer = new bytes(2 * length + 2);
                                  buffer[0] = "0";
                                  buffer[1] = "x";
                                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                                      buffer[i] = _HEX_SYMBOLS[value & 0xf];
                                      value >>= 4;
                                  }
                                  require(value == 0, "Strings: hex length insufficient");
                                  return string(buffer);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./IERC165Upgradeable.sol";
                          import "../../proxy/utils/Initializable.sol";
                          /**
                           * @dev Implementation of the {IERC165} interface.
                           *
                           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
                           * for the additional interface id that will be supported. For example:
                           *
                           * ```solidity
                           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
                           * }
                           * ```
                           *
                           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
                           */
                          abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
                              function __ERC165_init() internal initializer {
                                  __ERC165_init_unchained();
                              }
                              function __ERC165_init_unchained() internal initializer {
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IERC165Upgradeable).interfaceId;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC165 standard, as defined in the
                           * https://eips.ethereum.org/EIPS/eip-165[EIP].
                           *
                           * Implementers can declare support of contract interfaces, which can then be
                           * queried by others ({ERC165Checker}).
                           *
                           * For an implementation, see {ERC165}.
                           */
                          interface IERC165Upgradeable {
                              /**
                               * @dev Returns true if this contract implements the interface defined by
                               * `interfaceId`. See the corresponding
                               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                               * to learn more about how these ids are created.
                               *
                               * This function call must use less than 30 000 gas.
                               */
                              function supportsInterface(bytes4 interfaceId) external view returns (bool);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./IERC20Upgradeable.sol";
                          import "./extensions/IERC20MetadataUpgradeable.sol";
                          import "../../utils/ContextUpgradeable.sol";
                          import "../../proxy/utils/Initializable.sol";
                          /**
                           * @dev Implementation of the {IERC20} interface.
                           *
                           * This implementation is agnostic to the way tokens are created. This means
                           * that a supply mechanism has to be added in a derived contract using {_mint}.
                           * For a generic mechanism see {ERC20PresetMinterPauser}.
                           *
                           * TIP: For a detailed writeup see our guide
                           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
                           * to implement supply mechanisms].
                           *
                           * We have followed general OpenZeppelin Contracts guidelines: functions revert
                           * instead returning `false` on failure. This behavior is nonetheless
                           * conventional and does not conflict with the expectations of ERC20
                           * applications.
                           *
                           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
                           * This allows applications to reconstruct the allowance for all accounts just
                           * by listening to said events. Other implementations of the EIP may not emit
                           * these events, as it isn't required by the specification.
                           *
                           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
                           * functions have been added to mitigate the well-known issues around setting
                           * allowances. See {IERC20-approve}.
                           */
                          contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
                              mapping(address => uint256) private _balances;
                              mapping(address => mapping(address => uint256)) private _allowances;
                              uint256 private _totalSupply;
                              string private _name;
                              string private _symbol;
                              /**
                               * @dev Sets the values for {name} and {symbol}.
                               *
                               * The default value of {decimals} is 18. To select a different value for
                               * {decimals} you should overload it.
                               *
                               * All two of these values are immutable: they can only be set once during
                               * construction.
                               */
                              function __ERC20_init(string memory name_, string memory symbol_) internal initializer {
                                  __Context_init_unchained();
                                  __ERC20_init_unchained(name_, symbol_);
                              }
                              function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer {
                                  _name = name_;
                                  _symbol = symbol_;
                              }
                              /**
                               * @dev Returns the name of the token.
                               */
                              function name() public view virtual override returns (string memory) {
                                  return _name;
                              }
                              /**
                               * @dev Returns the symbol of the token, usually a shorter version of the
                               * name.
                               */
                              function symbol() public view virtual override returns (string memory) {
                                  return _symbol;
                              }
                              /**
                               * @dev Returns the number of decimals used to get its user representation.
                               * For example, if `decimals` equals `2`, a balance of `505` tokens should
                               * be displayed to a user as `5.05` (`505 / 10 ** 2`).
                               *
                               * Tokens usually opt for a value of 18, imitating the relationship between
                               * Ether and Wei. This is the value {ERC20} uses, unless this function is
                               * overridden;
                               *
                               * NOTE: This information is only used for _display_ purposes: it in
                               * no way affects any of the arithmetic of the contract, including
                               * {IERC20-balanceOf} and {IERC20-transfer}.
                               */
                              function decimals() public view virtual override returns (uint8) {
                                  return 18;
                              }
                              /**
                               * @dev See {IERC20-totalSupply}.
                               */
                              function totalSupply() public view virtual override returns (uint256) {
                                  return _totalSupply;
                              }
                              /**
                               * @dev See {IERC20-balanceOf}.
                               */
                              function balanceOf(address account) public view virtual override returns (uint256) {
                                  return _balances[account];
                              }
                              /**
                               * @dev See {IERC20-transfer}.
                               *
                               * Requirements:
                               *
                               * - `recipient` cannot be the zero address.
                               * - the caller must have a balance of at least `amount`.
                               */
                              function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                                  _transfer(_msgSender(), recipient, amount);
                                  return true;
                              }
                              /**
                               * @dev See {IERC20-allowance}.
                               */
                              function allowance(address owner, address spender) public view virtual override returns (uint256) {
                                  return _allowances[owner][spender];
                              }
                              /**
                               * @dev See {IERC20-approve}.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               */
                              function approve(address spender, uint256 amount) public virtual override returns (bool) {
                                  _approve(_msgSender(), spender, amount);
                                  return true;
                              }
                              /**
                               * @dev See {IERC20-transferFrom}.
                               *
                               * Emits an {Approval} event indicating the updated allowance. This is not
                               * required by the EIP. See the note at the beginning of {ERC20}.
                               *
                               * Requirements:
                               *
                               * - `sender` and `recipient` cannot be the zero address.
                               * - `sender` must have a balance of at least `amount`.
                               * - the caller must have allowance for ``sender``'s tokens of at least
                               * `amount`.
                               */
                              function transferFrom(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) public virtual override returns (bool) {
                                  _transfer(sender, recipient, amount);
                                  uint256 currentAllowance = _allowances[sender][_msgSender()];
                                  require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
                                  unchecked {
                                      _approve(sender, _msgSender(), currentAllowance - amount);
                                  }
                                  return true;
                              }
                              /**
                               * @dev Atomically increases the allowance granted to `spender` by the caller.
                               *
                               * This is an alternative to {approve} that can be used as a mitigation for
                               * problems described in {IERC20-approve}.
                               *
                               * Emits an {Approval} event indicating the updated allowance.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               */
                              function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
                                  return true;
                              }
                              /**
                               * @dev Atomically decreases the allowance granted to `spender` by the caller.
                               *
                               * This is an alternative to {approve} that can be used as a mitigation for
                               * problems described in {IERC20-approve}.
                               *
                               * Emits an {Approval} event indicating the updated allowance.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               * - `spender` must have allowance for the caller of at least
                               * `subtractedValue`.
                               */
                              function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                                  uint256 currentAllowance = _allowances[_msgSender()][spender];
                                  require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
                                  unchecked {
                                      _approve(_msgSender(), spender, currentAllowance - subtractedValue);
                                  }
                                  return true;
                              }
                              /**
                               * @dev Moves `amount` of tokens from `sender` to `recipient`.
                               *
                               * This internal function is equivalent to {transfer}, and can be used to
                               * e.g. implement automatic token fees, slashing mechanisms, etc.
                               *
                               * Emits a {Transfer} event.
                               *
                               * Requirements:
                               *
                               * - `sender` cannot be the zero address.
                               * - `recipient` cannot be the zero address.
                               * - `sender` must have a balance of at least `amount`.
                               */
                              function _transfer(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) internal virtual {
                                  require(sender != address(0), "ERC20: transfer from the zero address");
                                  require(recipient != address(0), "ERC20: transfer to the zero address");
                                  _beforeTokenTransfer(sender, recipient, amount);
                                  uint256 senderBalance = _balances[sender];
                                  require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
                                  unchecked {
                                      _balances[sender] = senderBalance - amount;
                                  }
                                  _balances[recipient] += amount;
                                  emit Transfer(sender, recipient, amount);
                                  _afterTokenTransfer(sender, recipient, amount);
                              }
                              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                               * the total supply.
                               *
                               * Emits a {Transfer} event with `from` set to the zero address.
                               *
                               * Requirements:
                               *
                               * - `account` cannot be the zero address.
                               */
                              function _mint(address account, uint256 amount) internal virtual {
                                  require(account != address(0), "ERC20: mint to the zero address");
                                  _beforeTokenTransfer(address(0), account, amount);
                                  _totalSupply += amount;
                                  _balances[account] += amount;
                                  emit Transfer(address(0), account, amount);
                                  _afterTokenTransfer(address(0), account, amount);
                              }
                              /**
                               * @dev Destroys `amount` tokens from `account`, reducing the
                               * total supply.
                               *
                               * Emits a {Transfer} event with `to` set to the zero address.
                               *
                               * Requirements:
                               *
                               * - `account` cannot be the zero address.
                               * - `account` must have at least `amount` tokens.
                               */
                              function _burn(address account, uint256 amount) internal virtual {
                                  require(account != address(0), "ERC20: burn from the zero address");
                                  _beforeTokenTransfer(account, address(0), amount);
                                  uint256 accountBalance = _balances[account];
                                  require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                                  unchecked {
                                      _balances[account] = accountBalance - amount;
                                  }
                                  _totalSupply -= amount;
                                  emit Transfer(account, address(0), amount);
                                  _afterTokenTransfer(account, address(0), amount);
                              }
                              /**
                               * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                               *
                               * This internal function is equivalent to `approve`, and can be used to
                               * e.g. set automatic allowances for certain subsystems, etc.
                               *
                               * Emits an {Approval} event.
                               *
                               * Requirements:
                               *
                               * - `owner` cannot be the zero address.
                               * - `spender` cannot be the zero address.
                               */
                              function _approve(
                                  address owner,
                                  address spender,
                                  uint256 amount
                              ) internal virtual {
                                  require(owner != address(0), "ERC20: approve from the zero address");
                                  require(spender != address(0), "ERC20: approve to the zero address");
                                  _allowances[owner][spender] = amount;
                                  emit Approval(owner, spender, amount);
                              }
                              /**
                               * @dev Hook that is called before any transfer of tokens. This includes
                               * minting and burning.
                               *
                               * Calling conditions:
                               *
                               * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                               * will be transferred to `to`.
                               * - when `from` is zero, `amount` tokens will be minted for `to`.
                               * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                               * - `from` and `to` are never both zero.
                               *
                               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                               */
                              function _beforeTokenTransfer(
                                  address from,
                                  address to,
                                  uint256 amount
                              ) internal virtual {}
                              /**
                               * @dev Hook that is called after any transfer of tokens. This includes
                               * minting and burning.
                               *
                               * Calling conditions:
                               *
                               * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                               * has been transferred to `to`.
                               * - when `from` is zero, `amount` tokens have been minted for `to`.
                               * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
                               * - `from` and `to` are never both zero.
                               *
                               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                               */
                              function _afterTokenTransfer(
                                  address from,
                                  address to,
                                  uint256 amount
                              ) internal virtual {}
                              uint256[45] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity 0.8.7;
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
                          import "../interfaces/IERC20Permit.sol";
                          interface IDeBridgeToken is IERC20Upgradeable, IERC20Permit {
                              function mint(address _receiver, uint256 _amount) external;
                              function burn(uint256 _amount) external;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC20 standard as defined in the EIP.
                           */
                          interface IERC20Upgradeable {
                              /**
                               * @dev Returns the amount of tokens in existence.
                               */
                              function totalSupply() external view returns (uint256);
                              /**
                               * @dev Returns the amount of tokens owned by `account`.
                               */
                              function balanceOf(address account) external view returns (uint256);
                              /**
                               * @dev Moves `amount` tokens from the caller's account to `recipient`.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transfer(address recipient, uint256 amount) external returns (bool);
                              /**
                               * @dev Returns the remaining number of tokens that `spender` will be
                               * allowed to spend on behalf of `owner` through {transferFrom}. This is
                               * zero by default.
                               *
                               * This value changes when {approve} or {transferFrom} are called.
                               */
                              function allowance(address owner, address spender) external view returns (uint256);
                              /**
                               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * IMPORTANT: Beware that changing an allowance with this method brings the risk
                               * that someone may use both the old and the new allowance by unfortunate
                               * transaction ordering. One possible solution to mitigate this race
                               * condition is to first reduce the spender's allowance to 0 and set the
                               * desired value afterwards:
                               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                               *
                               * Emits an {Approval} event.
                               */
                              function approve(address spender, uint256 amount) external returns (bool);
                              /**
                               * @dev Moves `amount` tokens from `sender` to `recipient` using the
                               * allowance mechanism. `amount` is then deducted from the caller's
                               * allowance.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transferFrom(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) external returns (bool);
                              /**
                               * @dev Emitted when `value` tokens are moved from one account (`from`) to
                               * another (`to`).
                               *
                               * Note that `value` may be zero.
                               */
                              event Transfer(address indexed from, address indexed to, uint256 value);
                              /**
                               * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                               * a call to {approve}. `value` is the new allowance.
                               */
                              event Approval(address indexed owner, address indexed spender, uint256 value);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../IERC20Upgradeable.sol";
                          /**
                           * @dev Interface for the optional metadata functions from the ERC20 standard.
                           *
                           * _Available since v4.1._
                           */
                          interface IERC20MetadataUpgradeable is IERC20Upgradeable {
                              /**
                               * @dev Returns the name of the token.
                               */
                              function name() external view returns (string memory);
                              /**
                               * @dev Returns the symbol of the token.
                               */
                              function symbol() external view returns (string memory);
                              /**
                               * @dev Returns the decimals places of the token.
                               */
                              function decimals() external view returns (uint8);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity 0.8.7;
                          /**
                           * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
                           * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
                           *
                           * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
                           * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
                           * need to send a transaction, and thus is not required to hold Ether at all.
                           */
                          interface IERC20Permit {
                              /**
                               * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
                               * given ``owner``'s signed approval.
                               *
                               * IMPORTANT: The same issues {IERC20-approve} has related to transaction
                               * ordering also apply here.
                               *
                               * Emits an {Approval} event.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               * - `deadline` must be a timestamp in the future.
                               * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
                               * over the EIP712-formatted function arguments.
                               * - the signature must use ``owner``'s current nonce (see {nonces}).
                               *
                               * For more information on the signature format, see the
                               * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
                               * section].
                               */
                              function permit(
                                  address owner,
                                  address spender,
                                  uint256 value,
                                  uint256 deadline,
                                  uint8 v,
                                  bytes32 r,
                                  bytes32 s
                              ) external;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./IBeacon.sol";
                          import "../Proxy.sol";
                          import "../ERC1967/ERC1967Upgrade.sol";
                          /**
                           * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}.
                           *
                           * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
                           * conflict with the storage layout of the implementation behind the proxy.
                           *
                           * _Available since v3.4._
                           */
                          contract BeaconProxy is Proxy, ERC1967Upgrade {
                              /**
                               * @dev Initializes the proxy with `beacon`.
                               *
                               * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
                               * will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity
                               * constructor.
                               *
                               * Requirements:
                               *
                               * - `beacon` must be a contract with the interface {IBeacon}.
                               */
                              constructor(address beacon, bytes memory data) payable {
                                  assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1));
                                  _upgradeBeaconToAndCall(beacon, data, false);
                              }
                              /**
                               * @dev Returns the current beacon address.
                               */
                              function _beacon() internal view virtual returns (address) {
                                  return _getBeacon();
                              }
                              /**
                               * @dev Returns the current implementation address of the associated beacon.
                               */
                              function _implementation() internal view virtual override returns (address) {
                                  return IBeacon(_getBeacon()).implementation();
                              }
                              /**
                               * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.
                               *
                               * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
                               *
                               * Requirements:
                               *
                               * - `beacon` must be a contract.
                               * - The implementation returned by `beacon` must be a contract.
                               */
                              function _setBeacon(address beacon, bytes memory data) internal virtual {
                                  _upgradeBeaconToAndCall(beacon, data, false);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is the interface that {BeaconProxy} expects of its beacon.
                           */
                          interface IBeacon {
                              /**
                               * @dev Must return an address that can be used as a delegate call target.
                               *
                               * {BeaconProxy} will check that this address is a contract.
                               */
                              function implementation() external view returns (address);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                           * be specified by overriding the virtual {_implementation} function.
                           *
                           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                           * different contract through the {_delegate} function.
                           *
                           * The success and return data of the delegated call will be returned back to the caller of the proxy.
                           */
                          abstract contract Proxy {
                              /**
                               * @dev Delegates the current call to `implementation`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _delegate(address implementation) internal virtual {
                                  assembly {
                                      // Copy msg.data. We take full control of memory in this inline assembly
                                      // block because it will not return to Solidity code. We overwrite the
                                      // Solidity scratch pad at memory position 0.
                                      calldatacopy(0, 0, calldatasize())
                                      // Call the implementation.
                                      // out and outsize are 0 because we don't know the size yet.
                                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                      // Copy the returned data.
                                      returndatacopy(0, 0, returndatasize())
                                      switch result
                                      // delegatecall returns 0 on error.
                                      case 0 {
                                          revert(0, returndatasize())
                                      }
                                      default {
                                          return(0, returndatasize())
                                      }
                                  }
                              }
                              /**
                               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                               * and {_fallback} should delegate.
                               */
                              function _implementation() internal view virtual returns (address);
                              /**
                               * @dev Delegates the current call to the address returned by `_implementation()`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _fallback() internal virtual {
                                  _beforeFallback();
                                  _delegate(_implementation());
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                               * function in the contract matches the call data.
                               */
                              fallback() external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                               * is empty.
                               */
                              receive() external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                               * call, or as part of the Solidity `fallback` or `receive` functions.
                               *
                               * If overriden should call `super._beforeFallback()`.
                               */
                              function _beforeFallback() internal virtual {}
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "../beacon/IBeacon.sol";
                          import "../../utils/Address.sol";
                          import "../../utils/StorageSlot.sol";
                          /**
                           * @dev This abstract contract provides getters and event emitting update functions for
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                           *
                           * _Available since v4.1._
                           *
                           * @custom:oz-upgrades-unsafe-allow delegatecall
                           */
                          abstract contract ERC1967Upgrade {
                              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                              /**
                               * @dev Storage slot with the address of the current implementation.
                               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                              /**
                               * @dev Emitted when the implementation is upgraded.
                               */
                              event Upgraded(address indexed implementation);
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _getImplementation() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 implementation slot.
                               */
                              function _setImplementation(address newImplementation) private {
                                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                              }
                              /**
                               * @dev Perform implementation upgrade
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeTo(address newImplementation) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                              /**
                               * @dev Perform implementation upgrade with additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCall(
                                  address newImplementation,
                                  bytes memory data,
                                  bool forceCall
                              ) internal {
                                  _upgradeTo(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                              }
                              /**
                               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCallSecure(
                                  address newImplementation,
                                  bytes memory data,
                                  bool forceCall
                              ) internal {
                                  address oldImplementation = _getImplementation();
                                  // Initial upgrade and setup call
                                  _setImplementation(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                                  // Perform rollback test if not already in progress
                                  StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                                  if (!rollbackTesting.value) {
                                      // Trigger rollback using upgradeTo from the new implementation
                                      rollbackTesting.value = true;
                                      Address.functionDelegateCall(
                                          newImplementation,
                                          abi.encodeWithSignature("upgradeTo(address)", oldImplementation)
                                      );
                                      rollbackTesting.value = false;
                                      // Check rollback was effective
                                      require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                      // Finally reset to the new implementation and log the upgrade
                                      _upgradeTo(newImplementation);
                                  }
                              }
                              /**
                               * @dev Storage slot with the admin of the contract.
                               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                              /**
                               * @dev Emitted when the admin account has changed.
                               */
                              event AdminChanged(address previousAdmin, address newAdmin);
                              /**
                               * @dev Returns the current admin.
                               */
                              function _getAdmin() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 admin slot.
                               */
                              function _setAdmin(address newAdmin) private {
                                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               */
                              function _changeAdmin(address newAdmin) internal {
                                  emit AdminChanged(_getAdmin(), newAdmin);
                                  _setAdmin(newAdmin);
                              }
                              /**
                               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                               */
                              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                              /**
                               * @dev Emitted when the beacon is upgraded.
                               */
                              event BeaconUpgraded(address indexed beacon);
                              /**
                               * @dev Returns the current beacon.
                               */
                              function _getBeacon() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                              }
                              /**
                               * @dev Stores a new beacon in the EIP1967 beacon slot.
                               */
                              function _setBeacon(address newBeacon) private {
                                  require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                                  require(
                                      Address.isContract(IBeacon(newBeacon).implementation()),
                                      "ERC1967: beacon implementation is not a contract"
                                  );
                                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                              }
                              /**
                               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                               *
                               * Emits a {BeaconUpgraded} event.
                               */
                              function _upgradeBeaconToAndCall(
                                  address newBeacon,
                                  bytes memory data,
                                  bool forceCall
                              ) internal {
                                  _setBeacon(newBeacon);
                                  emit BeaconUpgraded(newBeacon);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library Address {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  assembly {
                                      size := extcodesize(account)
                                  }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  (bool success, ) = recipient.call{value: amount}("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain `call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(
                                  address target,
                                  bytes memory data,
                                  uint256 value
                              ) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(
                                  address target,
                                  bytes memory data,
                                  uint256 value,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  (bool success, bytes memory returndata) = target.call{value: value}(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  require(isContract(target), "Address: delegate call to non-contract");
                                  (bool success, bytes memory returndata) = target.delegatecall(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                               * revert reason using the provided one.
                               *
                               * _Available since v4.3._
                               */
                              function verifyCallResult(
                                  bool success,
                                  bytes memory returndata,
                                  string memory errorMessage
                              ) internal pure returns (bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Library for reading and writing primitive types to specific storage slots.
                           *
                           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                           * This library helps with reading and writing to such slots without the need for inline assembly.
                           *
                           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                           *
                           * Example usage to set ERC1967 implementation slot:
                           * ```
                           * contract ERC1967 {
                           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                           *
                           *     function _getImplementation() internal view returns (address) {
                           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                           *     }
                           *
                           *     function _setImplementation(address newImplementation) internal {
                           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                           *     }
                           * }
                           * ```
                           *
                           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                           */
                          library StorageSlot {
                              struct AddressSlot {
                                  address value;
                              }
                              struct BooleanSlot {
                                  bool value;
                              }
                              struct Bytes32Slot {
                                  bytes32 value;
                              }
                              struct Uint256Slot {
                                  uint256 value;
                              }
                              /**
                               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                               */
                              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                               */
                              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                               */
                              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                               */
                              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                          }
                          

                          File 10 of 12: DeBridgeToken
                          // SPDX-License-Identifier: BUSL-1.1
                          pragma solidity ^0.8.7;
                          import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol";
                          import "../interfaces/IDeBridgeToken.sol";
                          /// @dev ERC20 token that is used as wrapped asset to represent the native token value on the other chains.
                          contract DeBridgeToken is
                              Initializable,
                              AccessControlUpgradeable,
                              ERC20PausableUpgradeable,
                              IDeBridgeToken
                          {
                              /// @dev Minter role identifier
                              bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
                              /// @dev Pauser role identifier
                              bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
                              /// @dev Domain separator as described in [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale)
                              bytes32 public DOMAIN_SEPARATOR;
                              /// @dev Typehash as described in [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale).
                              /// =keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
                              bytes32 public constant PERMIT_TYPEHASH =
                                  0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
                              /// @dev Transfers counter
                              mapping(address => uint256) public nonces;
                              /// @dev Asset's decimals
                              uint8 internal _decimals;
                              /* ========== EVENTS ========== */
                              event NameUpdated(string oldName, string newName, string oldSymbol, string newSymbol, bytes32 oldDomainSeparator, bytes32 newDomainSeparator);
                              
                              /* ========== ERRORS ========== */
                              error MinterBadRole();
                              error PauserBadRole();
                              error AdminBadRole();
                              /* ========== MODIFIERS ========== */
                              modifier onlyMinter() {
                                  if (!hasRole(MINTER_ROLE, msg.sender)) revert MinterBadRole();
                                  _;
                              }
                              modifier onlyPauser() {
                                  if (!hasRole(PAUSER_ROLE, msg.sender)) revert PauserBadRole();
                                  _;
                              }
                              modifier onlyAdmin() {
                                  if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert AdminBadRole();
                                  _;
                              }
                              /// @dev Constructor that initializes the most important configurations.
                              /// @param name_ Asset's name.
                              /// @param symbol_ Asset's symbol.
                              /// @param decimals_ Asset's decimals.
                              /// @param admin Address to set as asset's admin.
                              /// @param minters The accounts allowed to int new tokens.
                              function initialize(
                                  string memory name_,
                                  string memory symbol_,
                                  uint8 decimals_,
                                  address admin,
                                  address[] memory minters
                              ) public initializer {
                                  _decimals = decimals_;
                                  name_ = bytes(name_).length == 0 ? symbol_ : name_;
                                  __ERC20_init_unchained(name_, symbol_);
                                  _setupRole(DEFAULT_ADMIN_ROLE, admin);
                                  _setupRole(PAUSER_ROLE, admin);
                                  uint256 mintersCount = minters.length;
                                  for (uint256 i = 0; i < mintersCount; i++) {
                                      _setupRole(MINTER_ROLE, minters[i]);
                                  }
                                  uint256 chainId;
                                  assembly {
                                      chainId := chainid()
                                  }
                                  DOMAIN_SEPARATOR = keccak256(
                                      abi.encode(
                                          keccak256(
                                              "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                                          ),
                                          keccak256(bytes(name_)),
                                          keccak256(bytes("1")),
                                          chainId,
                                          address(this)
                                      )
                                  );
                              }
                              /// @inheritdoc IDeBridgeToken
                              function mint(address _receiver, uint256 _amount) external override onlyMinter {
                                  _mint(_receiver, _amount);
                              }
                              /// @inheritdoc IDeBridgeToken
                              function burn(uint256 _amount) external override onlyMinter {
                                  _burn(msg.sender, _amount);
                              }
                              /// @dev Approves the spender by signature.
                              /// @param _owner Token's owner.
                              /// @param _spender Account to be approved.
                              /// @param _value Amount to be approved.
                              /// @param _deadline The permit valid until.
                              /// @param _v Signature part.
                              /// @param _r Signature part.
                              /// @param _s Signature part.
                              function permit(
                                  address _owner,
                                  address _spender,
                                  uint256 _value,
                                  uint256 _deadline,
                                  uint8 _v,
                                  bytes32 _r,
                                  bytes32 _s
                              ) external override {
                                  require(_deadline >= block.timestamp, "permit: EXPIRED");
                                  bytes32 digest = keccak256(
                                      abi.encodePacked(
                                          "\\x19\\x01",
                                          DOMAIN_SEPARATOR,
                                          keccak256(
                                              abi.encode(
                                                  PERMIT_TYPEHASH,
                                                  _owner,
                                                  _spender,
                                                  _value,
                                                  nonces[_owner]++,
                                                  _deadline
                                              )
                                          )
                                      )
                                  );
                                  address recoveredAddress = ecrecover(digest, _v, _r, _s);
                                  require(
                                      recoveredAddress != address(0) && recoveredAddress == _owner,
                                      "permit: invalid signature"
                                  );
                                  _approve(_owner, _spender, _value);
                              }
                              /// @dev Asset's decimals
                              function decimals() public view override returns (uint8) {
                                  return _decimals;
                              }
                              /// @dev Pauses all token transfers. The caller must have the `PAUSER_ROLE`.
                              function pause() public onlyPauser {
                                  _pause();
                              }
                              /// @dev Unpauses all token transfers. The caller must have the `PAUSER_ROLE`.
                              function unpause() public onlyPauser {
                                  _unpause();
                              }
                              /// @dev Set new name/symbol. The caller must have the `DEFAULT_ADMIN_ROLE`.
                              /// @param _newName new name
                              /// @param _newSymbol new symbol
                              function updateName(string memory _newName, string memory _newSymbol) external onlyAdmin {
                                  string memory oldName = _name;
                                  string memory oldSymbol = _symbol;
                                  bytes32 oldDomainSeparator = DOMAIN_SEPARATOR;
                                  _name = _newName;
                                  _symbol = _newSymbol;
                                  uint256 chainId;
                                  assembly {
                                      chainId := chainid()
                                  }
                                  DOMAIN_SEPARATOR = keccak256(
                                      abi.encode(
                                          keccak256(
                                              "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                                          ),
                                          keccak256(bytes(_name)),
                                          keccak256(bytes("1")),
                                          chainId,
                                          address(this)
                                      )
                                  );
                                  emit NameUpdated(oldName, _newName, oldSymbol, _newSymbol, oldDomainSeparator, DOMAIN_SEPARATOR);
                              }
                              function _beforeTokenTransfer(
                                  address from,
                                  address to,
                                  uint256 amount
                              ) internal virtual override {
                                  super._beforeTokenTransfer(from, to, amount);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (access/AccessControl.sol)
                          pragma solidity ^0.8.0;
                          import "./IAccessControlUpgradeable.sol";
                          import "../utils/ContextUpgradeable.sol";
                          import "../utils/StringsUpgradeable.sol";
                          import "../utils/introspection/ERC165Upgradeable.sol";
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Contract module that allows children to implement role-based access
                           * control mechanisms. This is a lightweight version that doesn't allow enumerating role
                           * members except through off-chain means by accessing the contract event logs. Some
                           * applications may benefit from on-chain enumerability, for those cases see
                           * {AccessControlEnumerable}.
                           *
                           * Roles are referred to by their `bytes32` identifier. These should be exposed
                           * in the external API and be unique. The best way to achieve this is by
                           * using `public constant` hash digests:
                           *
                           * ```
                           * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
                           * ```
                           *
                           * Roles can be used to represent a set of permissions. To restrict access to a
                           * function call, use {hasRole}:
                           *
                           * ```
                           * function foo() public {
                           *     require(hasRole(MY_ROLE, msg.sender));
                           *     ...
                           * }
                           * ```
                           *
                           * Roles can be granted and revoked dynamically via the {grantRole} and
                           * {revokeRole} functions. Each role has an associated admin role, and only
                           * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
                           *
                           * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
                           * that only accounts with this role will be able to grant or revoke other
                           * roles. More complex role relationships can be created by using
                           * {_setRoleAdmin}.
                           *
                           * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
                           * grant and revoke this role. Extra precautions should be taken to secure
                           * accounts that have been granted it.
                           */
                          abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
                              function __AccessControl_init() internal initializer {
                                  __Context_init_unchained();
                                  __ERC165_init_unchained();
                                  __AccessControl_init_unchained();
                              }
                              function __AccessControl_init_unchained() internal initializer {
                              }
                              struct RoleData {
                                  mapping(address => bool) members;
                                  bytes32 adminRole;
                              }
                              mapping(bytes32 => RoleData) private _roles;
                              bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
                              /**
                               * @dev Modifier that checks that an account has a specific role. Reverts
                               * with a standardized message including the required role.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               *
                               * _Available since v4.1._
                               */
                              modifier onlyRole(bytes32 role) {
                                  _checkRole(role, _msgSender());
                                  _;
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
                              }
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) public view override returns (bool) {
                                  return _roles[role].members[account];
                              }
                              /**
                               * @dev Revert with a standard message if `account` is missing `role`.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               */
                              function _checkRole(bytes32 role, address account) internal view {
                                  if (!hasRole(role, account)) {
                                      revert(
                                          string(
                                              abi.encodePacked(
                                                  "AccessControl: account ",
                                                  StringsUpgradeable.toHexString(uint160(account), 20),
                                                  " is missing role ",
                                                  StringsUpgradeable.toHexString(uint256(role), 32)
                                              )
                                          )
                                      );
                                  }
                              }
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
                                  return _roles[role].adminRole;
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been revoked `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) public virtual override {
                                  require(account == _msgSender(), "AccessControl: can only renounce roles for self");
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event. Note that unlike {grantRole}, this function doesn't perform any
                               * checks on the calling account.
                               *
                               * [WARNING]
                               * ====
                               * This function should only be called from the constructor when setting
                               * up the initial roles for the system.
                               *
                               * Using this function in any other way is effectively circumventing the admin
                               * system imposed by {AccessControl}.
                               * ====
                               *
                               * NOTE: This function is deprecated in favor of {_grantRole}.
                               */
                              function _setupRole(bytes32 role, address account) internal virtual {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Sets `adminRole` as ``role``'s admin role.
                               *
                               * Emits a {RoleAdminChanged} event.
                               */
                              function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                                  bytes32 previousAdminRole = getRoleAdmin(role);
                                  _roles[role].adminRole = adminRole;
                                  emit RoleAdminChanged(role, previousAdminRole, adminRole);
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * Internal function without access restriction.
                               */
                              function _grantRole(bytes32 role, address account) internal virtual {
                                  if (!hasRole(role, account)) {
                                      _roles[role].members[account] = true;
                                      emit RoleGranted(role, account, _msgSender());
                                  }
                              }
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * Internal function without access restriction.
                               */
                              function _revokeRole(bytes32 role, address account) internal virtual {
                                  if (hasRole(role, account)) {
                                      _roles[role].members[account] = false;
                                      emit RoleRevoked(role, account, _msgSender());
                                  }
                              }
                              uint256[49] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (proxy/utils/Initializable.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                           * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
                           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                           *
                           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                           * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                           *
                           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                           *
                           * [CAUTION]
                           * ====
                           * Avoid leaving a contract uninitialized.
                           *
                           * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                           * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
                           * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
                           *
                           * [.hljs-theme-light.nopadding]
                           * ```
                           * /// @custom:oz-upgrades-unsafe-allow constructor
                           * constructor() initializer {}
                           * ```
                           * ====
                           */
                          abstract contract Initializable {
                              /**
                               * @dev Indicates that the contract has been initialized.
                               */
                              bool private _initialized;
                              /**
                               * @dev Indicates that the contract is in the process of being initialized.
                               */
                              bool private _initializing;
                              /**
                               * @dev Modifier to protect an initializer function from being invoked twice.
                               */
                              modifier initializer() {
                                  require(_initializing || !_initialized, "Initializable: contract is already initialized");
                                  bool isTopLevelCall = !_initializing;
                                  if (isTopLevelCall) {
                                      _initializing = true;
                                      _initialized = true;
                                  }
                                  _;
                                  if (isTopLevelCall) {
                                      _initializing = false;
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/extensions/ERC20Pausable.sol)
                          pragma solidity ^0.8.0;
                          import "../ERC20Upgradeable.sol";
                          import "../../../security/PausableUpgradeable.sol";
                          import "../../../proxy/utils/Initializable.sol";
                          /**
                           * @dev ERC20 token with pausable token transfers, minting and burning.
                           *
                           * Useful for scenarios such as preventing trades until the end of an evaluation
                           * period, or having an emergency switch for freezing all token transfers in the
                           * event of a large bug.
                           */
                          abstract contract ERC20PausableUpgradeable is Initializable, ERC20Upgradeable, PausableUpgradeable {
                              function __ERC20Pausable_init() internal initializer {
                                  __Context_init_unchained();
                                  __Pausable_init_unchained();
                                  __ERC20Pausable_init_unchained();
                              }
                              function __ERC20Pausable_init_unchained() internal initializer {
                              }
                              /**
                               * @dev See {ERC20-_beforeTokenTransfer}.
                               *
                               * Requirements:
                               *
                               * - the contract must not be paused.
                               */
                              function _beforeTokenTransfer(
                                  address from,
                                  address to,
                                  uint256 amount
                              ) internal virtual override {
                                  super._beforeTokenTransfer(from, to, amount);
                                  require(!paused(), "ERC20Pausable: token transfer while paused");
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.7;
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
                          import "../interfaces/IERC20Permit.sol";
                          interface IDeBridgeToken is IERC20Upgradeable, IERC20Permit {
                              /// @dev Issues new tokens.
                              /// @param _receiver Token's receiver.
                              /// @param _amount Amount to be minted.
                              function mint(address _receiver, uint256 _amount) external;
                              /// @dev Destroys existing tokens.
                              /// @param _amount Amount to be burnt.
                              function burn(uint256 _amount) external;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (access/IAccessControl.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev External interface of AccessControl declared to support ERC165 detection.
                           */
                          interface IAccessControlUpgradeable {
                              /**
                               * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                               *
                               * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                               * {RoleAdminChanged} not being emitted signaling this.
                               *
                               * _Available since v3.1._
                               */
                              event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
                              /**
                               * @dev Emitted when `account` is granted `role`.
                               *
                               * `sender` is the account that originated the contract call, an admin role
                               * bearer except when using {AccessControl-_setupRole}.
                               */
                              event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Emitted when `account` is revoked `role`.
                               *
                               * `sender` is the account that originated the contract call:
                               *   - if using `revokeRole`, it is the admin role bearer
                               *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                               */
                              event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) external view returns (bool);
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {AccessControl-_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) external view returns (bytes32);
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been granted `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) external;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Context.sol)
                          pragma solidity ^0.8.0;
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract ContextUpgradeable is Initializable {
                              function __Context_init() internal initializer {
                                  __Context_init_unchained();
                              }
                              function __Context_init_unchained() internal initializer {
                              }
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  return msg.data;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Strings.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev String operations.
                           */
                          library StringsUpgradeable {
                              bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                               */
                              function toString(uint256 value) internal pure returns (string memory) {
                                  // Inspired by OraclizeAPI's implementation - MIT licence
                                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                                  if (value == 0) {
                                      return "0";
                                  }
                                  uint256 temp = value;
                                  uint256 digits;
                                  while (temp != 0) {
                                      digits++;
                                      temp /= 10;
                                  }
                                  bytes memory buffer = new bytes(digits);
                                  while (value != 0) {
                                      digits -= 1;
                                      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                                      value /= 10;
                                  }
                                  return string(buffer);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                               */
                              function toHexString(uint256 value) internal pure returns (string memory) {
                                  if (value == 0) {
                                      return "0x00";
                                  }
                                  uint256 temp = value;
                                  uint256 length = 0;
                                  while (temp != 0) {
                                      length++;
                                      temp >>= 8;
                                  }
                                  return toHexString(value, length);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                               */
                              function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                                  bytes memory buffer = new bytes(2 * length + 2);
                                  buffer[0] = "0";
                                  buffer[1] = "x";
                                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                                      buffer[i] = _HEX_SYMBOLS[value & 0xf];
                                      value >>= 4;
                                  }
                                  require(value == 0, "Strings: hex length insufficient");
                                  return string(buffer);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/introspection/ERC165.sol)
                          pragma solidity ^0.8.0;
                          import "./IERC165Upgradeable.sol";
                          import "../../proxy/utils/Initializable.sol";
                          /**
                           * @dev Implementation of the {IERC165} interface.
                           *
                           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
                           * for the additional interface id that will be supported. For example:
                           *
                           * ```solidity
                           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
                           * }
                           * ```
                           *
                           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
                           */
                          abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
                              function __ERC165_init() internal initializer {
                                  __ERC165_init_unchained();
                              }
                              function __ERC165_init_unchained() internal initializer {
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IERC165Upgradeable).interfaceId;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/introspection/IERC165.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC165 standard, as defined in the
                           * https://eips.ethereum.org/EIPS/eip-165[EIP].
                           *
                           * Implementers can declare support of contract interfaces, which can then be
                           * queried by others ({ERC165Checker}).
                           *
                           * For an implementation, see {ERC165}.
                           */
                          interface IERC165Upgradeable {
                              /**
                               * @dev Returns true if this contract implements the interface defined by
                               * `interfaceId`. See the corresponding
                               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                               * to learn more about how these ids are created.
                               *
                               * This function call must use less than 30 000 gas.
                               */
                              function supportsInterface(bytes4 interfaceId) external view returns (bool);
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/ERC20.sol)
                          pragma solidity ^0.8.0;
                          import "./IERC20Upgradeable.sol";
                          import "./extensions/IERC20MetadataUpgradeable.sol";
                          import "../../utils/ContextUpgradeable.sol";
                          import "../../proxy/utils/Initializable.sol";
                          /**
                           * @dev Implementation of the {IERC20} interface.
                           *
                           * This implementation is agnostic to the way tokens are created. This means
                           * that a supply mechanism has to be added in a derived contract using {_mint}.
                           * For a generic mechanism see {ERC20PresetMinterPauser}.
                           *
                           * TIP: For a detailed writeup see our guide
                           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
                           * to implement supply mechanisms].
                           *
                           * We have followed general OpenZeppelin Contracts guidelines: functions revert
                           * instead returning `false` on failure. This behavior is nonetheless
                           * conventional and does not conflict with the expectations of ERC20
                           * applications.
                           *
                           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
                           * This allows applications to reconstruct the allowance for all accounts just
                           * by listening to said events. Other implementations of the EIP may not emit
                           * these events, as it isn't required by the specification.
                           *
                           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
                           * functions have been added to mitigate the well-known issues around setting
                           * allowances. See {IERC20-approve}.
                           */
                          contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
                              mapping(address => uint256) private _balances;
                              mapping(address => mapping(address => uint256)) private _allowances;
                              uint256 private _totalSupply;
                              string internal _name;
                              string internal _symbol;
                              /**
                               * @dev Sets the values for {name} and {symbol}.
                               *
                               * The default value of {decimals} is 18. To select a different value for
                               * {decimals} you should overload it.
                               *
                               * All two of these values are immutable: they can only be set once during
                               * construction.
                               */
                              function __ERC20_init(string memory name_, string memory symbol_) internal initializer {
                                  __Context_init_unchained();
                                  __ERC20_init_unchained(name_, symbol_);
                              }
                              function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer {
                                  _name = name_;
                                  _symbol = symbol_;
                              }
                              /**
                               * @dev Returns the name of the token.
                               */
                              function name() public view virtual override returns (string memory) {
                                  return _name;
                              }
                              /**
                               * @dev Returns the symbol of the token, usually a shorter version of the
                               * name.
                               */
                              function symbol() public view virtual override returns (string memory) {
                                  return _symbol;
                              }
                              /**
                               * @dev Returns the number of decimals used to get its user representation.
                               * For example, if `decimals` equals `2`, a balance of `505` tokens should
                               * be displayed to a user as `5.05` (`505 / 10 ** 2`).
                               *
                               * Tokens usually opt for a value of 18, imitating the relationship between
                               * Ether and Wei. This is the value {ERC20} uses, unless this function is
                               * overridden;
                               *
                               * NOTE: This information is only used for _display_ purposes: it in
                               * no way affects any of the arithmetic of the contract, including
                               * {IERC20-balanceOf} and {IERC20-transfer}.
                               */
                              function decimals() public view virtual override returns (uint8) {
                                  return 18;
                              }
                              /**
                               * @dev See {IERC20-totalSupply}.
                               */
                              function totalSupply() public view virtual override returns (uint256) {
                                  return _totalSupply;
                              }
                              /**
                               * @dev See {IERC20-balanceOf}.
                               */
                              function balanceOf(address account) public view virtual override returns (uint256) {
                                  return _balances[account];
                              }
                              /**
                               * @dev See {IERC20-transfer}.
                               *
                               * Requirements:
                               *
                               * - `recipient` cannot be the zero address.
                               * - the caller must have a balance of at least `amount`.
                               */
                              function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                                  _transfer(_msgSender(), recipient, amount);
                                  return true;
                              }
                              /**
                               * @dev See {IERC20-allowance}.
                               */
                              function allowance(address owner, address spender) public view virtual override returns (uint256) {
                                  return _allowances[owner][spender];
                              }
                              /**
                               * @dev See {IERC20-approve}.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               */
                              function approve(address spender, uint256 amount) public virtual override returns (bool) {
                                  _approve(_msgSender(), spender, amount);
                                  return true;
                              }
                              /**
                               * @dev See {IERC20-transferFrom}.
                               *
                               * Emits an {Approval} event indicating the updated allowance. This is not
                               * required by the EIP. See the note at the beginning of {ERC20}.
                               *
                               * Requirements:
                               *
                               * - `sender` and `recipient` cannot be the zero address.
                               * - `sender` must have a balance of at least `amount`.
                               * - the caller must have allowance for ``sender``'s tokens of at least
                               * `amount`.
                               */
                              function transferFrom(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) public virtual override returns (bool) {
                                  _transfer(sender, recipient, amount);
                                  uint256 currentAllowance = _allowances[sender][_msgSender()];
                                  require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
                                  unchecked {
                                      _approve(sender, _msgSender(), currentAllowance - amount);
                                  }
                                  return true;
                              }
                              /**
                               * @dev Atomically increases the allowance granted to `spender` by the caller.
                               *
                               * This is an alternative to {approve} that can be used as a mitigation for
                               * problems described in {IERC20-approve}.
                               *
                               * Emits an {Approval} event indicating the updated allowance.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               */
                              function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
                                  return true;
                              }
                              /**
                               * @dev Atomically decreases the allowance granted to `spender` by the caller.
                               *
                               * This is an alternative to {approve} that can be used as a mitigation for
                               * problems described in {IERC20-approve}.
                               *
                               * Emits an {Approval} event indicating the updated allowance.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               * - `spender` must have allowance for the caller of at least
                               * `subtractedValue`.
                               */
                              function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                                  uint256 currentAllowance = _allowances[_msgSender()][spender];
                                  require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
                                  unchecked {
                                      _approve(_msgSender(), spender, currentAllowance - subtractedValue);
                                  }
                                  return true;
                              }
                              /**
                               * @dev Moves `amount` of tokens from `sender` to `recipient`.
                               *
                               * This internal function is equivalent to {transfer}, and can be used to
                               * e.g. implement automatic token fees, slashing mechanisms, etc.
                               *
                               * Emits a {Transfer} event.
                               *
                               * Requirements:
                               *
                               * - `sender` cannot be the zero address.
                               * - `recipient` cannot be the zero address.
                               * - `sender` must have a balance of at least `amount`.
                               */
                              function _transfer(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) internal virtual {
                                  require(sender != address(0), "ERC20: transfer from the zero address");
                                  require(recipient != address(0), "ERC20: transfer to the zero address");
                                  _beforeTokenTransfer(sender, recipient, amount);
                                  uint256 senderBalance = _balances[sender];
                                  require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
                                  unchecked {
                                      _balances[sender] = senderBalance - amount;
                                  }
                                  _balances[recipient] += amount;
                                  emit Transfer(sender, recipient, amount);
                                  _afterTokenTransfer(sender, recipient, amount);
                              }
                              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                               * the total supply.
                               *
                               * Emits a {Transfer} event with `from` set to the zero address.
                               *
                               * Requirements:
                               *
                               * - `account` cannot be the zero address.
                               */
                              function _mint(address account, uint256 amount) internal virtual {
                                  require(account != address(0), "ERC20: mint to the zero address");
                                  _beforeTokenTransfer(address(0), account, amount);
                                  _totalSupply += amount;
                                  _balances[account] += amount;
                                  emit Transfer(address(0), account, amount);
                                  _afterTokenTransfer(address(0), account, amount);
                              }
                              /**
                               * @dev Destroys `amount` tokens from `account`, reducing the
                               * total supply.
                               *
                               * Emits a {Transfer} event with `to` set to the zero address.
                               *
                               * Requirements:
                               *
                               * - `account` cannot be the zero address.
                               * - `account` must have at least `amount` tokens.
                               */
                              function _burn(address account, uint256 amount) internal virtual {
                                  require(account != address(0), "ERC20: burn from the zero address");
                                  _beforeTokenTransfer(account, address(0), amount);
                                  uint256 accountBalance = _balances[account];
                                  require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                                  unchecked {
                                      _balances[account] = accountBalance - amount;
                                  }
                                  _totalSupply -= amount;
                                  emit Transfer(account, address(0), amount);
                                  _afterTokenTransfer(account, address(0), amount);
                              }
                              /**
                               * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                               *
                               * This internal function is equivalent to `approve`, and can be used to
                               * e.g. set automatic allowances for certain subsystems, etc.
                               *
                               * Emits an {Approval} event.
                               *
                               * Requirements:
                               *
                               * - `owner` cannot be the zero address.
                               * - `spender` cannot be the zero address.
                               */
                              function _approve(
                                  address owner,
                                  address spender,
                                  uint256 amount
                              ) internal virtual {
                                  require(owner != address(0), "ERC20: approve from the zero address");
                                  require(spender != address(0), "ERC20: approve to the zero address");
                                  _allowances[owner][spender] = amount;
                                  emit Approval(owner, spender, amount);
                              }
                              /**
                               * @dev Hook that is called before any transfer of tokens. This includes
                               * minting and burning.
                               *
                               * Calling conditions:
                               *
                               * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                               * will be transferred to `to`.
                               * - when `from` is zero, `amount` tokens will be minted for `to`.
                               * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                               * - `from` and `to` are never both zero.
                               *
                               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                               */
                              function _beforeTokenTransfer(
                                  address from,
                                  address to,
                                  uint256 amount
                              ) internal virtual {}
                              /**
                               * @dev Hook that is called after any transfer of tokens. This includes
                               * minting and burning.
                               *
                               * Calling conditions:
                               *
                               * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                               * has been transferred to `to`.
                               * - when `from` is zero, `amount` tokens have been minted for `to`.
                               * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
                               * - `from` and `to` are never both zero.
                               *
                               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                               */
                              function _afterTokenTransfer(
                                  address from,
                                  address to,
                                  uint256 amount
                              ) internal virtual {}
                              uint256[45] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (security/Pausable.sol)
                          pragma solidity ^0.8.0;
                          import "../utils/ContextUpgradeable.sol";
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Contract module which allows children to implement an emergency stop
                           * mechanism that can be triggered by an authorized account.
                           *
                           * This module is used through inheritance. It will make available the
                           * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
                           * the functions of your contract. Note that they will not be pausable by
                           * simply including this module, only once the modifiers are put in place.
                           */
                          abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
                              /**
                               * @dev Emitted when the pause is triggered by `account`.
                               */
                              event Paused(address account);
                              /**
                               * @dev Emitted when the pause is lifted by `account`.
                               */
                              event Unpaused(address account);
                              bool private _paused;
                              /**
                               * @dev Initializes the contract in unpaused state.
                               */
                              function __Pausable_init() internal initializer {
                                  __Context_init_unchained();
                                  __Pausable_init_unchained();
                              }
                              function __Pausable_init_unchained() internal initializer {
                                  _paused = false;
                              }
                              /**
                               * @dev Returns true if the contract is paused, and false otherwise.
                               */
                              function paused() public view virtual returns (bool) {
                                  return _paused;
                              }
                              /**
                               * @dev Modifier to make a function callable only when the contract is not paused.
                               *
                               * Requirements:
                               *
                               * - The contract must not be paused.
                               */
                              modifier whenNotPaused() {
                                  require(!paused(), "Pausable: paused");
                                  _;
                              }
                              /**
                               * @dev Modifier to make a function callable only when the contract is paused.
                               *
                               * Requirements:
                               *
                               * - The contract must be paused.
                               */
                              modifier whenPaused() {
                                  require(paused(), "Pausable: not paused");
                                  _;
                              }
                              /**
                               * @dev Triggers stopped state.
                               *
                               * Requirements:
                               *
                               * - The contract must not be paused.
                               */
                              function _pause() internal virtual whenNotPaused {
                                  _paused = true;
                                  emit Paused(_msgSender());
                              }
                              /**
                               * @dev Returns to normal state.
                               *
                               * Requirements:
                               *
                               * - The contract must be paused.
                               */
                              function _unpause() internal virtual whenPaused {
                                  _paused = false;
                                  emit Unpaused(_msgSender());
                              }
                              uint256[49] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC20 standard as defined in the EIP.
                           */
                          interface IERC20Upgradeable {
                              /**
                               * @dev Returns the amount of tokens in existence.
                               */
                              function totalSupply() external view returns (uint256);
                              /**
                               * @dev Returns the amount of tokens owned by `account`.
                               */
                              function balanceOf(address account) external view returns (uint256);
                              /**
                               * @dev Moves `amount` tokens from the caller's account to `recipient`.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transfer(address recipient, uint256 amount) external returns (bool);
                              /**
                               * @dev Returns the remaining number of tokens that `spender` will be
                               * allowed to spend on behalf of `owner` through {transferFrom}. This is
                               * zero by default.
                               *
                               * This value changes when {approve} or {transferFrom} are called.
                               */
                              function allowance(address owner, address spender) external view returns (uint256);
                              /**
                               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * IMPORTANT: Beware that changing an allowance with this method brings the risk
                               * that someone may use both the old and the new allowance by unfortunate
                               * transaction ordering. One possible solution to mitigate this race
                               * condition is to first reduce the spender's allowance to 0 and set the
                               * desired value afterwards:
                               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                               *
                               * Emits an {Approval} event.
                               */
                              function approve(address spender, uint256 amount) external returns (bool);
                              /**
                               * @dev Moves `amount` tokens from `sender` to `recipient` using the
                               * allowance mechanism. `amount` is then deducted from the caller's
                               * allowance.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transferFrom(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) external returns (bool);
                              /**
                               * @dev Emitted when `value` tokens are moved from one account (`from`) to
                               * another (`to`).
                               *
                               * Note that `value` may be zero.
                               */
                              event Transfer(address indexed from, address indexed to, uint256 value);
                              /**
                               * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                               * a call to {approve}. `value` is the new allowance.
                               */
                              event Approval(address indexed owner, address indexed spender, uint256 value);
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/extensions/IERC20Metadata.sol)
                          pragma solidity ^0.8.0;
                          import "../IERC20Upgradeable.sol";
                          /**
                           * @dev Interface for the optional metadata functions from the ERC20 standard.
                           *
                           * _Available since v4.1._
                           */
                          interface IERC20MetadataUpgradeable is IERC20Upgradeable {
                              /**
                               * @dev Returns the name of the token.
                               */
                              function name() external view returns (string memory);
                              /**
                               * @dev Returns the symbol of the token.
                               */
                              function symbol() external view returns (string memory);
                              /**
                               * @dev Returns the decimals places of the token.
                               */
                              function decimals() external view returns (uint8);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.7;
                          /**
                           * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
                           * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
                           *
                           * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
                           * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
                           * need to send a transaction, and thus is not required to hold Ether at all.
                           */
                          interface IERC20Permit {
                              /**
                               * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
                               * given ``owner``'s signed approval.
                               *
                               * IMPORTANT: The same issues {IERC20-approve} has related to transaction
                               * ordering also apply here.
                               *
                               * Emits an {Approval} event.
                               *
                               * Requirements:
                               *
                               * - `spender` cannot be the zero address.
                               * - `deadline` must be a timestamp in the future.
                               * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
                               * over the EIP712-formatted function arguments.
                               * - the signature must use ``owner``'s current nonce (see {nonces}).
                               *
                               * For more information on the signature format, see the
                               * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
                               * section].
                               */
                              function permit(
                                  address owner,
                                  address spender,
                                  uint256 value,
                                  uint256 deadline,
                                  uint8 v,
                                  bytes32 r,
                                  bytes32 s
                              ) external;
                          }
                          

                          File 11 of 12: TransparentUpgradeableProxy
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
                          import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
                          // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
                          contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
                              constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../Proxy.sol";
                          import "./ERC1967Upgrade.sol";
                          /**
                           * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                           * implementation address that can be changed. This address is stored in storage in the location specified by
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                           * implementation behind the proxy.
                           */
                          contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                              /**
                               * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                               *
                               * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                               * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                               */
                              constructor(address _logic, bytes memory _data) payable {
                                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                                  _upgradeToAndCall(_logic, _data, false);
                              }
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _implementation() internal view virtual override returns (address impl) {
                                  return ERC1967Upgrade._getImplementation();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Proxy.sol";
                          /**
                           * @dev This contract implements a proxy that is upgradeable by an admin.
                           *
                           * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
                           * clashing], which can potentially be used in an attack, this contract uses the
                           * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
                           * things that go hand in hand:
                           *
                           * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
                           * that call matches one of the admin functions exposed by the proxy itself.
                           * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
                           * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
                           * "admin cannot fallback to proxy target".
                           *
                           * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
                           * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
                           * to sudden errors when trying to call a function from the proxy implementation.
                           *
                           * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
                           * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
                           */
                          contract TransparentUpgradeableProxy is ERC1967Proxy {
                              /**
                               * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                               * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                               */
                              constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                                  assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                                  _changeAdmin(admin_);
                              }
                              /**
                               * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                               */
                              modifier ifAdmin() {
                                  if (msg.sender == _getAdmin()) {
                                      _;
                                  } else {
                                      _fallback();
                                  }
                              }
                              /**
                               * @dev Returns the current admin.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                               */
                              function admin() external ifAdmin returns (address admin_) {
                                  admin_ = _getAdmin();
                              }
                              /**
                               * @dev Returns the current implementation.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                               *
                               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                               * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                               */
                              function implementation() external ifAdmin returns (address implementation_) {
                                  implementation_ = _implementation();
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                               */
                              function changeAdmin(address newAdmin) external virtual ifAdmin {
                                  _changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                               */
                              function upgradeTo(address newImplementation) external ifAdmin {
                                  _upgradeToAndCall(newImplementation, bytes(""), false);
                              }
                              /**
                               * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                               * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                               * proxied contract.
                               *
                               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                               */
                              function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                                  _upgradeToAndCall(newImplementation, data, true);
                              }
                              /**
                               * @dev Returns the current admin.
                               */
                              function _admin() internal view virtual returns (address) {
                                  return _getAdmin();
                              }
                              /**
                               * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                               */
                              function _beforeFallback() internal virtual override {
                                  require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                                  super._beforeFallback();
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "./TransparentUpgradeableProxy.sol";
                          import "../../access/Ownable.sol";
                          /**
                           * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
                           * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
                           */
                          contract ProxyAdmin is Ownable {
                              /**
                               * @dev Returns the current implementation of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("implementation()")) == 0x5c60da1b
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Returns the current admin of `proxy`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                                  // We need to manually run the static call since the getter cannot be flagged as view
                                  // bytes4(keccak256("admin()")) == 0xf851a440
                                  (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                                  require(success);
                                  return abi.decode(returndata, (address));
                              }
                              /**
                               * @dev Changes the admin of `proxy` to `newAdmin`.
                               *
                               * Requirements:
                               *
                               * - This contract must be the current admin of `proxy`.
                               */
                              function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                                  proxy.changeAdmin(newAdmin);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                                  proxy.upgradeTo(implementation);
                              }
                              /**
                               * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
                               * {TransparentUpgradeableProxy-upgradeToAndCall}.
                               *
                               * Requirements:
                               *
                               * - This contract must be the admin of `proxy`.
                               */
                              function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                                  proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                           * be specified by overriding the virtual {_implementation} function.
                           *
                           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                           * different contract through the {_delegate} function.
                           *
                           * The success and return data of the delegated call will be returned back to the caller of the proxy.
                           */
                          abstract contract Proxy {
                              /**
                               * @dev Delegates the current call to `implementation`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _delegate(address implementation) internal virtual {
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly {
                                      // Copy msg.data. We take full control of memory in this inline assembly
                                      // block because it will not return to Solidity code. We overwrite the
                                      // Solidity scratch pad at memory position 0.
                                      calldatacopy(0, 0, calldatasize())
                                      // Call the implementation.
                                      // out and outsize are 0 because we don't know the size yet.
                                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                      // Copy the returned data.
                                      returndatacopy(0, 0, returndatasize())
                                      switch result
                                      // delegatecall returns 0 on error.
                                      case 0 { revert(0, returndatasize()) }
                                      default { return(0, returndatasize()) }
                                  }
                              }
                              /**
                               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                               * and {_fallback} should delegate.
                               */
                              function _implementation() internal view virtual returns (address);
                              /**
                               * @dev Delegates the current call to the address returned by `_implementation()`.
                               *
                               * This function does not return to its internall call site, it will return directly to the external caller.
                               */
                              function _fallback() internal virtual {
                                  _beforeFallback();
                                  _delegate(_implementation());
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                               * function in the contract matches the call data.
                               */
                              fallback () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                               * is empty.
                               */
                              receive () external payable virtual {
                                  _fallback();
                              }
                              /**
                               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                               * call, or as part of the Solidity `fallback` or `receive` functions.
                               *
                               * If overriden should call `super._beforeFallback()`.
                               */
                              function _beforeFallback() internal virtual {
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "../beacon/IBeacon.sol";
                          import "../../utils/Address.sol";
                          import "../../utils/StorageSlot.sol";
                          /**
                           * @dev This abstract contract provides getters and event emitting update functions for
                           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                           *
                           * _Available since v4.1._
                           *
                           * @custom:oz-upgrades-unsafe-allow delegatecall
                           */
                          abstract contract ERC1967Upgrade {
                              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                              /**
                               * @dev Storage slot with the address of the current implementation.
                               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                              /**
                               * @dev Emitted when the implementation is upgraded.
                               */
                              event Upgraded(address indexed implementation);
                              /**
                               * @dev Returns the current implementation address.
                               */
                              function _getImplementation() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 implementation slot.
                               */
                              function _setImplementation(address newImplementation) private {
                                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                              }
                              /**
                               * @dev Perform implementation upgrade
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeTo(address newImplementation) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                              /**
                               * @dev Perform implementation upgrade with additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                              }
                              /**
                               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                               *
                               * Emits an {Upgraded} event.
                               */
                              function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                                  address oldImplementation = _getImplementation();
                                  // Initial upgrade and setup call
                                  _setImplementation(newImplementation);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(newImplementation, data);
                                  }
                                  // Perform rollback test if not already in progress
                                  StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                                  if (!rollbackTesting.value) {
                                      // Trigger rollback using upgradeTo from the new implementation
                                      rollbackTesting.value = true;
                                      Address.functionDelegateCall(
                                          newImplementation,
                                          abi.encodeWithSignature(
                                              "upgradeTo(address)",
                                              oldImplementation
                                          )
                                      );
                                      rollbackTesting.value = false;
                                      // Check rollback was effective
                                      require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                      // Finally reset to the new implementation and log the upgrade
                                      _setImplementation(newImplementation);
                                      emit Upgraded(newImplementation);
                                  }
                              }
                              /**
                               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                               *
                               * Emits a {BeaconUpgraded} event.
                               */
                              function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                                  _setBeacon(newBeacon);
                                  emit BeaconUpgraded(newBeacon);
                                  if (data.length > 0 || forceCall) {
                                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                                  }
                              }
                              /**
                               * @dev Storage slot with the admin of the contract.
                               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                               * validated in the constructor.
                               */
                              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                              /**
                               * @dev Emitted when the admin account has changed.
                               */
                              event AdminChanged(address previousAdmin, address newAdmin);
                              /**
                               * @dev Returns the current admin.
                               */
                              function _getAdmin() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                              }
                              /**
                               * @dev Stores a new address in the EIP1967 admin slot.
                               */
                              function _setAdmin(address newAdmin) private {
                                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                              }
                              /**
                               * @dev Changes the admin of the proxy.
                               *
                               * Emits an {AdminChanged} event.
                               */
                              function _changeAdmin(address newAdmin) internal {
                                  emit AdminChanged(_getAdmin(), newAdmin);
                                  _setAdmin(newAdmin);
                              }
                              /**
                               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                               */
                              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                              /**
                               * @dev Emitted when the beacon is upgraded.
                               */
                              event BeaconUpgraded(address indexed beacon);
                              /**
                               * @dev Returns the current beacon.
                               */
                              function _getBeacon() internal view returns (address) {
                                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                              }
                              /**
                               * @dev Stores a new beacon in the EIP1967 beacon slot.
                               */
                              function _setBeacon(address newBeacon) private {
                                  require(
                                      Address.isContract(newBeacon),
                                      "ERC1967: new beacon is not a contract"
                                  );
                                  require(
                                      Address.isContract(IBeacon(newBeacon).implementation()),
                                      "ERC1967: beacon implementation is not a contract"
                                  );
                                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is the interface that {BeaconProxy} expects of its beacon.
                           */
                          interface IBeacon {
                              /**
                               * @dev Must return an address that can be used as a delegate call target.
                               *
                               * {BeaconProxy} will check that this address is a contract.
                               */
                              function implementation() external view returns (address);
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library Address {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly { size := extcodesize(account) }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                                  (bool success, ) = recipient.call{ value: amount }("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain`call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a delegate call.
                               *
                               * _Available since v3.4._
                               */
                              function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                                  require(isContract(target), "Address: delegate call to non-contract");
                                  // solhint-disable-next-line avoid-low-level-calls
                                  (bool success, bytes memory returndata) = target.delegatecall(data);
                                  return _verifyCallResult(success, returndata, errorMessage);
                              }
                              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          // solhint-disable-next-line no-inline-assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Library for reading and writing primitive types to specific storage slots.
                           *
                           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                           * This library helps with reading and writing to such slots without the need for inline assembly.
                           *
                           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                           *
                           * Example usage to set ERC1967 implementation slot:
                           * ```
                           * contract ERC1967 {
                           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                           *
                           *     function _getImplementation() internal view returns (address) {
                           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                           *     }
                           *
                           *     function _setImplementation(address newImplementation) internal {
                           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                           *     }
                           * }
                           * ```
                           *
                           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                           */
                          library StorageSlot {
                              struct AddressSlot {
                                  address value;
                              }
                              struct BooleanSlot {
                                  bool value;
                              }
                              struct Bytes32Slot {
                                  bytes32 value;
                              }
                              struct Uint256Slot {
                                  uint256 value;
                              }
                              /**
                               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                               */
                              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                               */
                              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                               */
                              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                              /**
                               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                               */
                              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                                  assembly {
                                      r.slot := slot
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../utils/Context.sol";
                          /**
                           * @dev Contract module which provides a basic access control mechanism, where
                           * there is an account (an owner) that can be granted exclusive access to
                           * specific functions.
                           *
                           * By default, the owner account will be the one that deploys the contract. This
                           * can later be changed with {transferOwnership}.
                           *
                           * This module is used through inheritance. It will make available the modifier
                           * `onlyOwner`, which can be applied to your functions to restrict their use to
                           * the owner.
                           */
                          abstract contract Ownable is Context {
                              address private _owner;
                              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                              /**
                               * @dev Initializes the contract setting the deployer as the initial owner.
                               */
                              constructor () {
                                  address msgSender = _msgSender();
                                  _owner = msgSender;
                                  emit OwnershipTransferred(address(0), msgSender);
                              }
                              /**
                               * @dev Returns the address of the current owner.
                               */
                              function owner() public view virtual returns (address) {
                                  return _owner;
                              }
                              /**
                               * @dev Throws if called by any account other than the owner.
                               */
                              modifier onlyOwner() {
                                  require(owner() == _msgSender(), "Ownable: caller is not the owner");
                                  _;
                              }
                              /**
                               * @dev 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.
                               */
                              function renounceOwnership() public virtual onlyOwner {
                                  emit OwnershipTransferred(_owner, address(0));
                                  _owner = address(0);
                              }
                              /**
                               * @dev Transfers ownership of the contract to a new account (`newOwner`).
                               * Can only be called by the current owner.
                               */
                              function transferOwnership(address newOwner) public virtual onlyOwner {
                                  require(newOwner != address(0), "Ownable: new owner is the zero address");
                                  emit OwnershipTransferred(_owner, newOwner);
                                  _owner = newOwner;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          /*
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract Context {
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                                  return msg.data;
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.0;
                          import "../ERC1967/ERC1967Upgrade.sol";
                          /**
                           * @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes
                           * publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify
                           * continuation of the upgradability.
                           *
                           * The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism.
                           *
                           * _Available since v4.1._
                           */
                          abstract contract UUPSUpgradeable is ERC1967Upgrade {
                              function upgradeTo(address newImplementation) external virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, bytes(""), false);
                              }
                              function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
                                  _authorizeUpgrade(newImplementation);
                                  _upgradeToAndCallSecure(newImplementation, data, true);
                              }
                              function _authorizeUpgrade(address newImplementation) internal virtual;
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity ^0.8.2;
                          import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
                          abstract contract Proxiable is UUPSUpgradeable {
                              function _authorizeUpgrade(address newImplementation) internal override {
                                  _beforeUpgrade(newImplementation);
                              }
                              function _beforeUpgrade(address newImplementation) internal virtual;
                          }
                          contract ChildOfProxiable is Proxiable {
                              function _beforeUpgrade(address newImplementation) internal virtual override {}
                          }
                          

                          File 12 of 12: CallProxy
                          // SPDX-License-Identifier: BUSL-1.1
                          pragma solidity 0.8.7;
                          import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
                          import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
                          import "../interfaces/ICallProxy.sol";
                          import "../libraries/Flags.sol";
                          import "../libraries/BytesLib.sol";
                          import "../libraries/MultiSendCallOnly.sol";
                          /// @dev Proxy to execute the other contract calls.
                          /// This contract is used when a user requests transfer with specific call of other contract.
                          contract CallProxy is Initializable, AccessControlUpgradeable, MultiSendCallOnly, ICallProxy {
                              using SafeERC20Upgradeable for IERC20Upgradeable;
                              using Flags for uint256;
                              using AddressUpgradeable for address;
                              /* ========== STATE VARIABLES ========== */
                              /// @dev Role allowed to withdraw fee
                              bytes32 public constant DEBRIDGE_GATE_ROLE = keccak256("DEBRIDGE_GATE_ROLE");
                              /// @dev Value for lock variable when function is not entered
                              uint256 private constant _NOT_LOCKED = 1;
                              /// @dev Value for lock variable when function is entered
                              uint256 private constant _LOCKED = 2;
                              /// @dev Chain from which the current submission is received
                              uint256 public override submissionChainIdFrom;
                              /// @dev Native sender of the current submission
                              bytes public override submissionNativeSender;
                              uint256 private _lock;
                              /* ========== ERRORS ========== */
                              error DeBridgeGateBadRole();
                              error CallProxyBadRole();
                              error ExternalCallFailed();
                              error NotEnoughSafeTxGas();
                              error CallFailed();
                              error Locked();
                              /* ========== MODIFIERS ========== */
                              modifier onlyGateRole() {
                                  if (!hasRole(DEBRIDGE_GATE_ROLE, msg.sender)) revert DeBridgeGateBadRole();
                                  _;
                              }
                              /// @dev lock
                              modifier lock() {
                                  if (_lock == _LOCKED) revert Locked();
                                  _lock = _LOCKED;
                                  _;
                                  _lock = _NOT_LOCKED;
                              }
                              /* ========== CONSTRUCTOR  ========== */
                              function initialize() public initializer {
                                  _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
                              }
                              /* ========== PUBLIC METHODS ========== */
                              /// @inheritdoc ICallProxy
                              function call(
                                  address _reserveAddress,
                                  address _receiver,
                                  bytes memory _data,
                                  uint256 _flags,
                                  bytes memory _nativeSender,
                                  uint256 _chainIdFrom
                              ) external payable override onlyGateRole lock returns (bool _result) {
                                  uint256 amount = address(this).balance;
                                  _result = _externalCall(
                                      _receiver,
                                      amount,
                                      _data,
                                      _nativeSender,
                                      _chainIdFrom,
                                      _flags
                                  );
                                  if (!_result && _flags.getFlag(Flags.REVERT_IF_EXTERNAL_FAIL)) {
                                      revert ExternalCallFailed();
                                  }
                                  amount = address(this).balance;
                                  if (amount > 0) {
                                      (bool success, ) = _reserveAddress.call{value: amount}(new bytes(0));
                                      if (!success) revert CallFailed();
                                  }
                              }
                              /// @inheritdoc ICallProxy
                              function callERC20(
                                  address _token,
                                  address _reserveAddress,
                                  address _receiver,
                                  bytes memory _data,
                                  uint256 _flags,
                                  bytes memory _nativeSender,
                                  uint256 _chainIdFrom
                              ) external override onlyGateRole lock returns (bool _result) {
                                  uint256 amount = IERC20Upgradeable(_token).balanceOf(address(this));
                                  if (_receiver != address(0)) {
                                      _customApprove(IERC20Upgradeable(_token), _receiver, amount);
                                  }
                                  _result = _externalCall(
                                      _receiver,
                                      0,
                                      _data,
                                      _nativeSender,
                                      _chainIdFrom,
                                      _flags
                                  );
                                  amount = IERC20Upgradeable(_token).balanceOf(address(this));
                                  if (!_result &&_flags.getFlag(Flags.REVERT_IF_EXTERNAL_FAIL)) {
                                      revert ExternalCallFailed();
                                  }
                                  if (amount > 0) {
                                      IERC20Upgradeable(_token).safeTransfer(_reserveAddress, amount);
                                  }
                                  if (_receiver != address(0)) {
                                      _customApprove(IERC20Upgradeable(_token), _receiver, 0);
                                  }
                              }
                              /// @dev Sends multiple transactions and reverts all if one fails.
                              /// @param transactions Encoded transactions. Each transaction is encoded as a packed bytes of
                              ///                     operation has to be uint8(0) in this version (=> 1 byte),
                              ///                     to as a address (=> 20 bytes),
                              ///                     value as a uint256 (=> 32 bytes),
                              ///                     data length as a uint256 (=> 32 bytes),
                              ///                     data as bytes.
                              ///                     see abi.encodePacked for more information on packed encoding
                              /// @notice The code is for most part the same as the normal MultiSend (to keep compatibility),
                              ///         but reverts if a transaction tries to use a delegatecall.
                              /// @notice This method is payable as delegatecalls keep the msg.value from the previous call
                              ///         If the calling method (e.g. execTransaction) received ETH this would revert otherwise
                              function multiSend(bytes memory transactions) external payable {
                                  if (address(this) != msg.sender) revert CallProxyBadRole();
                                  _multiSend(transactions);
                              }
                              // we need to accept ETH from deBridgeGate
                              receive() external payable {
                              }
                              /* ========== INTERNAL METHODS ========== */
                              function _externalCall(
                                  address _destination,
                                  uint256 _value,
                                  bytes memory _data,
                                  bytes memory _nativeSender,
                                  uint256 _chainIdFrom,
                                  uint256 _flags
                              ) internal returns (bool result) {
                                  bool storeSender = _flags.getFlag(Flags.PROXY_WITH_SENDER);
                                  bool checkGasLimit = _flags.getFlag(Flags.SEND_EXTERNAL_CALL_GAS_LIMIT);
                                  bool multisendFlag = _flags.getFlag(Flags.MULTI_SEND);
                                  // Temporary write to a storage nativeSender and chainIdFrom variables.
                                  // External contract can read them during a call if needed
                                  if (storeSender) {
                                      submissionChainIdFrom = _chainIdFrom;
                                      submissionNativeSender = _nativeSender;
                                  }
                                  uint256 safeTxGas;
                                  if (checkGasLimit && _data.length > 4) {
                                      safeTxGas = BytesLib.toUint32(_data, 0);
                                      // Remove first 4 bytes from data
                                      _data = BytesLib.slice(_data, 4, _data.length - 4);
                                  }
                                  // We require some gas to finish transaction emit the events, approve(0) etc (at least 15000) after the execution and some to perform code until the execution (500)
                                  // We also include the 1/64 in the check that is not send along with a call to counteract potential shortings because of EIP-150
                                  if (gasleft() < safeTxGas * 64 / 63 + 15500) revert NotEnoughSafeTxGas();
                                  // if safeTxGas is zero set gasleft
                                  safeTxGas = safeTxGas == 0 ? gasleft() : uint256(safeTxGas);
                                  if (multisendFlag) {
                                      _destination = address(this);
                                      assembly {
                                          result := call(safeTxGas, _destination, _value, add(_data, 0x20), mload(_data), 0, 0)
                                      }
                                  }
                                  else {
                                      assembly {
                                          result := call(safeTxGas, _destination, _value, add(_data, 0x20), mload(_data), 0, 0)
                                      }
                                  }
                                  // clear storage variables to get gas refund
                                  if (storeSender) {
                                      submissionChainIdFrom = 0;
                                      submissionNativeSender = "";
                                  }
                              }
                              function _customApprove(IERC20Upgradeable token, address spender, uint value) internal {
                                  bytes memory returndata = address(token).functionCall(
                                      abi.encodeWithSelector(token.approve.selector, spender, value),
                                      "ERC20 approve failed"
                                  );
                                  if (returndata.length > 0) {
                                      // Return data is optional
                                      require(abi.decode(returndata, (bool)), "ERC20 operation did not succeed");
                                  }
                              }
                              // ============ Version Control ============
                               /// @dev Get this contract's version
                              function version() external pure returns (uint256) {
                                  return 423; // 4.2.3
                              }
                          }// SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (access/AccessControl.sol)
                          pragma solidity ^0.8.0;
                          import "./IAccessControlUpgradeable.sol";
                          import "../utils/ContextUpgradeable.sol";
                          import "../utils/StringsUpgradeable.sol";
                          import "../utils/introspection/ERC165Upgradeable.sol";
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Contract module that allows children to implement role-based access
                           * control mechanisms. This is a lightweight version that doesn't allow enumerating role
                           * members except through off-chain means by accessing the contract event logs. Some
                           * applications may benefit from on-chain enumerability, for those cases see
                           * {AccessControlEnumerable}.
                           *
                           * Roles are referred to by their `bytes32` identifier. These should be exposed
                           * in the external API and be unique. The best way to achieve this is by
                           * using `public constant` hash digests:
                           *
                           * ```
                           * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
                           * ```
                           *
                           * Roles can be used to represent a set of permissions. To restrict access to a
                           * function call, use {hasRole}:
                           *
                           * ```
                           * function foo() public {
                           *     require(hasRole(MY_ROLE, msg.sender));
                           *     ...
                           * }
                           * ```
                           *
                           * Roles can be granted and revoked dynamically via the {grantRole} and
                           * {revokeRole} functions. Each role has an associated admin role, and only
                           * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
                           *
                           * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
                           * that only accounts with this role will be able to grant or revoke other
                           * roles. More complex role relationships can be created by using
                           * {_setRoleAdmin}.
                           *
                           * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
                           * grant and revoke this role. Extra precautions should be taken to secure
                           * accounts that have been granted it.
                           */
                          abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
                              function __AccessControl_init() internal initializer {
                                  __Context_init_unchained();
                                  __ERC165_init_unchained();
                                  __AccessControl_init_unchained();
                              }
                              function __AccessControl_init_unchained() internal initializer {
                              }
                              struct RoleData {
                                  mapping(address => bool) members;
                                  bytes32 adminRole;
                              }
                              mapping(bytes32 => RoleData) private _roles;
                              bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
                              /**
                               * @dev Modifier that checks that an account has a specific role. Reverts
                               * with a standardized message including the required role.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               *
                               * _Available since v4.1._
                               */
                              modifier onlyRole(bytes32 role) {
                                  _checkRole(role, _msgSender());
                                  _;
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
                              }
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) public view override returns (bool) {
                                  return _roles[role].members[account];
                              }
                              /**
                               * @dev Revert with a standard message if `account` is missing `role`.
                               *
                               * The format of the revert reason is given by the following regular expression:
                               *
                               *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
                               */
                              function _checkRole(bytes32 role, address account) internal view {
                                  if (!hasRole(role, account)) {
                                      revert(
                                          string(
                                              abi.encodePacked(
                                                  "AccessControl: account ",
                                                  StringsUpgradeable.toHexString(uint160(account), 20),
                                                  " is missing role ",
                                                  StringsUpgradeable.toHexString(uint256(role), 32)
                                              )
                                          )
                                      );
                                  }
                              }
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
                                  return _roles[role].adminRole;
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been revoked `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) public virtual override {
                                  require(account == _msgSender(), "AccessControl: can only renounce roles for self");
                                  _revokeRole(role, account);
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event. Note that unlike {grantRole}, this function doesn't perform any
                               * checks on the calling account.
                               *
                               * [WARNING]
                               * ====
                               * This function should only be called from the constructor when setting
                               * up the initial roles for the system.
                               *
                               * Using this function in any other way is effectively circumventing the admin
                               * system imposed by {AccessControl}.
                               * ====
                               *
                               * NOTE: This function is deprecated in favor of {_grantRole}.
                               */
                              function _setupRole(bytes32 role, address account) internal virtual {
                                  _grantRole(role, account);
                              }
                              /**
                               * @dev Sets `adminRole` as ``role``'s admin role.
                               *
                               * Emits a {RoleAdminChanged} event.
                               */
                              function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                                  bytes32 previousAdminRole = getRoleAdmin(role);
                                  _roles[role].adminRole = adminRole;
                                  emit RoleAdminChanged(role, previousAdminRole, adminRole);
                              }
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * Internal function without access restriction.
                               */
                              function _grantRole(bytes32 role, address account) internal virtual {
                                  if (!hasRole(role, account)) {
                                      _roles[role].members[account] = true;
                                      emit RoleGranted(role, account, _msgSender());
                                  }
                              }
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * Internal function without access restriction.
                               */
                              function _revokeRole(bytes32 role, address account) internal virtual {
                                  if (hasRole(role, account)) {
                                      _roles[role].members[account] = false;
                                      emit RoleRevoked(role, account, _msgSender());
                                  }
                              }
                              uint256[49] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (proxy/utils/Initializable.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                           * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
                           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                           *
                           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                           * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                           *
                           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                           *
                           * [CAUTION]
                           * ====
                           * Avoid leaving a contract uninitialized.
                           *
                           * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                           * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
                           * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
                           *
                           * [.hljs-theme-light.nopadding]
                           * ```
                           * /// @custom:oz-upgrades-unsafe-allow constructor
                           * constructor() initializer {}
                           * ```
                           * ====
                           */
                          abstract contract Initializable {
                              /**
                               * @dev Indicates that the contract has been initialized.
                               */
                              bool private _initialized;
                              /**
                               * @dev Indicates that the contract is in the process of being initialized.
                               */
                              bool private _initializing;
                              /**
                               * @dev Modifier to protect an initializer function from being invoked twice.
                               */
                              modifier initializer() {
                                  require(_initializing || !_initialized, "Initializable: contract is already initialized");
                                  bool isTopLevelCall = !_initializing;
                                  if (isTopLevelCall) {
                                      _initializing = true;
                                      _initialized = true;
                                  }
                                  _;
                                  if (isTopLevelCall) {
                                      _initializing = false;
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC20 standard as defined in the EIP.
                           */
                          interface IERC20Upgradeable {
                              /**
                               * @dev Returns the amount of tokens in existence.
                               */
                              function totalSupply() external view returns (uint256);
                              /**
                               * @dev Returns the amount of tokens owned by `account`.
                               */
                              function balanceOf(address account) external view returns (uint256);
                              /**
                               * @dev Moves `amount` tokens from the caller's account to `recipient`.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transfer(address recipient, uint256 amount) external returns (bool);
                              /**
                               * @dev Returns the remaining number of tokens that `spender` will be
                               * allowed to spend on behalf of `owner` through {transferFrom}. This is
                               * zero by default.
                               *
                               * This value changes when {approve} or {transferFrom} are called.
                               */
                              function allowance(address owner, address spender) external view returns (uint256);
                              /**
                               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * IMPORTANT: Beware that changing an allowance with this method brings the risk
                               * that someone may use both the old and the new allowance by unfortunate
                               * transaction ordering. One possible solution to mitigate this race
                               * condition is to first reduce the spender's allowance to 0 and set the
                               * desired value afterwards:
                               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                               *
                               * Emits an {Approval} event.
                               */
                              function approve(address spender, uint256 amount) external returns (bool);
                              /**
                               * @dev Moves `amount` tokens from `sender` to `recipient` using the
                               * allowance mechanism. `amount` is then deducted from the caller's
                               * allowance.
                               *
                               * Returns a boolean value indicating whether the operation succeeded.
                               *
                               * Emits a {Transfer} event.
                               */
                              function transferFrom(
                                  address sender,
                                  address recipient,
                                  uint256 amount
                              ) external returns (bool);
                              /**
                               * @dev Emitted when `value` tokens are moved from one account (`from`) to
                               * another (`to`).
                               *
                               * Note that `value` may be zero.
                               */
                              event Transfer(address indexed from, address indexed to, uint256 value);
                              /**
                               * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                               * a call to {approve}. `value` is the new allowance.
                               */
                              event Approval(address indexed owner, address indexed spender, uint256 value);
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (token/ERC20/utils/SafeERC20.sol)
                          pragma solidity ^0.8.0;
                          import "../IERC20Upgradeable.sol";
                          import "../../../utils/AddressUpgradeable.sol";
                          /**
                           * @title SafeERC20
                           * @dev Wrappers around ERC20 operations that throw on failure (when the token
                           * contract returns false). Tokens that return no value (and instead revert or
                           * throw on failure) are also supported, non-reverting calls are assumed to be
                           * successful.
                           * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
                           * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
                           */
                          library SafeERC20Upgradeable {
                              using AddressUpgradeable for address;
                              function safeTransfer(
                                  IERC20Upgradeable token,
                                  address to,
                                  uint256 value
                              ) internal {
                                  _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                              }
                              function safeTransferFrom(
                                  IERC20Upgradeable token,
                                  address from,
                                  address to,
                                  uint256 value
                              ) internal {
                                  _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                              }
                              /**
                               * @dev Deprecated. This function has issues similar to the ones found in
                               * {IERC20-approve}, and its usage is discouraged.
                               *
                               * Whenever possible, use {safeIncreaseAllowance} and
                               * {safeDecreaseAllowance} instead.
                               */
                              function safeApprove(
                                  IERC20Upgradeable token,
                                  address spender,
                                  uint256 value
                              ) internal {
                                  // safeApprove should only be called when setting an initial allowance,
                                  // or when resetting it to zero. To increase and decrease it, use
                                  // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                                  require(
                                      (value == 0) || (token.allowance(address(this), spender) == 0),
                                      "SafeERC20: approve from non-zero to non-zero allowance"
                                  );
                                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                              }
                              function safeIncreaseAllowance(
                                  IERC20Upgradeable token,
                                  address spender,
                                  uint256 value
                              ) internal {
                                  uint256 newAllowance = token.allowance(address(this), spender) + value;
                                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                              }
                              function safeDecreaseAllowance(
                                  IERC20Upgradeable token,
                                  address spender,
                                  uint256 value
                              ) internal {
                                  unchecked {
                                      uint256 oldAllowance = token.allowance(address(this), spender);
                                      require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                                      uint256 newAllowance = oldAllowance - value;
                                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                                  }
                              }
                              /**
                               * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                               * on the return value: the return value is optional (but if data is returned, it must not be false).
                               * @param token The token targeted by the call.
                               * @param data The call data (encoded using abi.encode or one of its variants).
                               */
                              function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
                                  // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                                  // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                                  // the target address contains contract code and also asserts for success in the low-level call.
                                  bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                                  if (returndata.length > 0) {
                                      // Return data is optional
                                      require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Address.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Collection of functions related to the address type
                           */
                          library AddressUpgradeable {
                              /**
                               * @dev Returns true if `account` is a contract.
                               *
                               * [IMPORTANT]
                               * ====
                               * It is unsafe to assume that an address for which this function returns
                               * false is an externally-owned account (EOA) and not a contract.
                               *
                               * Among others, `isContract` will return false for the following
                               * types of addresses:
                               *
                               *  - an externally-owned account
                               *  - a contract in construction
                               *  - an address where a contract will be created
                               *  - an address where a contract lived, but was destroyed
                               * ====
                               */
                              function isContract(address account) internal view returns (bool) {
                                  // This method relies on extcodesize, which returns 0 for contracts in
                                  // construction, since the code is only stored at the end of the
                                  // constructor execution.
                                  uint256 size;
                                  assembly {
                                      size := extcodesize(account)
                                  }
                                  return size > 0;
                              }
                              /**
                               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                               * `recipient`, forwarding all available gas and reverting on errors.
                               *
                               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                               * of certain opcodes, possibly making contracts go over the 2300 gas limit
                               * imposed by `transfer`, making them unable to receive funds via
                               * `transfer`. {sendValue} removes this limitation.
                               *
                               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                               *
                               * IMPORTANT: because control is transferred to `recipient`, care must be
                               * taken to not create reentrancy vulnerabilities. Consider using
                               * {ReentrancyGuard} or the
                               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                               */
                              function sendValue(address payable recipient, uint256 amount) internal {
                                  require(address(this).balance >= amount, "Address: insufficient balance");
                                  (bool success, ) = recipient.call{value: amount}("");
                                  require(success, "Address: unable to send value, recipient may have reverted");
                              }
                              /**
                               * @dev Performs a Solidity function call using a low level `call`. A
                               * plain `call` is an unsafe replacement for a function call: use this
                               * function instead.
                               *
                               * If `target` reverts with a revert reason, it is bubbled up by this
                               * function (like regular Solidity function calls).
                               *
                               * Returns the raw returned data. To convert to the expected return value,
                               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                               *
                               * Requirements:
                               *
                               * - `target` must be a contract.
                               * - calling `target` with `data` must not revert.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                  return functionCall(target, data, "Address: low-level call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                               * `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, 0, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but also transferring `value` wei to `target`.
                               *
                               * Requirements:
                               *
                               * - the calling contract must have an ETH balance of at least `value`.
                               * - the called Solidity function must be `payable`.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(
                                  address target,
                                  bytes memory data,
                                  uint256 value
                              ) internal returns (bytes memory) {
                                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                               * with `errorMessage` as a fallback revert reason when `target` reverts.
                               *
                               * _Available since v3.1._
                               */
                              function functionCallWithValue(
                                  address target,
                                  bytes memory data,
                                  uint256 value,
                                  string memory errorMessage
                              ) internal returns (bytes memory) {
                                  require(address(this).balance >= value, "Address: insufficient balance for call");
                                  require(isContract(target), "Address: call to non-contract");
                                  (bool success, bytes memory returndata) = target.call{value: value}(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                  return functionStaticCall(target, data, "Address: low-level static call failed");
                              }
                              /**
                               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                               * but performing a static call.
                               *
                               * _Available since v3.3._
                               */
                              function functionStaticCall(
                                  address target,
                                  bytes memory data,
                                  string memory errorMessage
                              ) internal view returns (bytes memory) {
                                  require(isContract(target), "Address: static call to non-contract");
                                  (bool success, bytes memory returndata) = target.staticcall(data);
                                  return verifyCallResult(success, returndata, errorMessage);
                              }
                              /**
                               * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                               * revert reason using the provided one.
                               *
                               * _Available since v4.3._
                               */
                              function verifyCallResult(
                                  bool success,
                                  bytes memory returndata,
                                  string memory errorMessage
                              ) internal pure returns (bytes memory) {
                                  if (success) {
                                      return returndata;
                                  } else {
                                      // Look for revert reason and bubble it up if present
                                      if (returndata.length > 0) {
                                          // The easiest way to bubble the revert reason is using memory via assembly
                                          assembly {
                                              let returndata_size := mload(returndata)
                                              revert(add(32, returndata), returndata_size)
                                          }
                                      } else {
                                          revert(errorMessage);
                                      }
                                  }
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          pragma solidity 0.8.7;
                          interface ICallProxy {
                              /// @dev Chain from which the current submission is received
                              function submissionChainIdFrom() external returns (uint256);
                              /// @dev Native sender of the current submission
                              function submissionNativeSender() external returns (bytes memory);
                              /// @dev Used for calls where native asset transfer is involved.
                              /// @param _reserveAddress Receiver of the tokens if the call to _receiver fails
                              /// @param _receiver Contract to be called
                              /// @param _data Call data
                              /// @param _flags Flags to change certain behavior of this function, see Flags library for more details
                              /// @param _nativeSender Native sender
                              /// @param _chainIdFrom Id of a chain that originated the request
                              function call(
                                  address _reserveAddress,
                                  address _receiver,
                                  bytes memory _data,
                                  uint256 _flags,
                                  bytes memory _nativeSender,
                                  uint256 _chainIdFrom
                              ) external payable returns (bool);
                              /// @dev Used for calls where ERC20 transfer is involved.
                              /// @param _token Asset address
                              /// @param _reserveAddress Receiver of the tokens if the call to _receiver fails
                              /// @param _receiver Contract to be called
                              /// @param _data Call data
                              /// @param _flags Flags to change certain behavior of this function, see Flags library for more details
                              /// @param _nativeSender Native sender
                              /// @param _chainIdFrom Id of a chain that originated the request
                              function callERC20(
                                  address _token,
                                  address _reserveAddress,
                                  address _receiver,
                                  bytes memory _data,
                                  uint256 _flags,
                                  bytes memory _nativeSender,
                                  uint256 _chainIdFrom
                              ) external returns (bool);
                          }// SPDX-License-Identifier: BUSL-1.1
                          pragma solidity 0.8.7;
                          library Flags {
                              /* ========== FLAGS ========== */
                              /// @dev Flag to unwrap ETH
                              uint256 public constant UNWRAP_ETH = 0;
                              /// @dev Flag to revert if external call fails
                              uint256 public constant REVERT_IF_EXTERNAL_FAIL = 1;
                              /// @dev Flag to call proxy with a sender contract
                              uint256 public constant PROXY_WITH_SENDER = 2;
                              /// @dev Data is hash in DeBridgeGate send method
                              uint256 public constant SEND_HASHED_DATA = 3;
                              /// @dev First 24 bytes from data is gas limit for external call
                              uint256 public constant SEND_EXTERNAL_CALL_GAS_LIMIT = 4;
                              /// @dev Support multi send for externall call
                              uint256 public constant MULTI_SEND = 5;
                              /// @dev Get flag
                              /// @param _packedFlags Flags packed to uint256
                              /// @param _flag Flag to check
                              function getFlag(
                                  uint256 _packedFlags,
                                  uint256 _flag
                              ) internal pure returns (bool) {
                                  uint256 flag = (_packedFlags >> _flag) & uint256(1);
                                  return flag == 1;
                              }
                              /// @dev Set flag
                              /// @param _packedFlags Flags packed to uint256
                              /// @param _flag Flag to set
                              /// @param _value Is set or not set
                               function setFlag(
                                   uint256 _packedFlags,
                                   uint256 _flag,
                                   bool _value
                               ) internal pure returns (uint256) {
                                   if (_value)
                                       return _packedFlags | uint256(1) << _flag;
                                   else
                                       return _packedFlags & ~(uint256(1) << _flag);
                               }
                          }
                          // SPDX-License-Identifier: Unlicense
                          /*
                           * @title Solidity Bytes Arrays Utils
                           * @author Gonçalo Sá <[email protected]>
                           *
                           * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
                           *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
                           */
                          pragma solidity >=0.8.0 <0.9.0;
                          library BytesLib {
                              function concat(
                                  bytes memory _preBytes,
                                  bytes memory _postBytes
                              )
                                  internal
                                  pure
                                  returns (bytes memory)
                              {
                                  bytes memory tempBytes;
                                  assembly {
                                      // Get a location of some free memory and store it in tempBytes as
                                      // Solidity does for memory variables.
                                      tempBytes := mload(0x40)
                                      // Store the length of the first bytes array at the beginning of
                                      // the memory for tempBytes.
                                      let length := mload(_preBytes)
                                      mstore(tempBytes, length)
                                      // Maintain a memory counter for the current write location in the
                                      // temp bytes array by adding the 32 bytes for the array length to
                                      // the starting location.
                                      let mc := add(tempBytes, 0x20)
                                      // Stop copying when the memory counter reaches the length of the
                                      // first bytes array.
                                      let end := add(mc, length)
                                      for {
                                          // Initialize a copy counter to the start of the _preBytes data,
                                          // 32 bytes into its memory.
                                          let cc := add(_preBytes, 0x20)
                                      } lt(mc, end) {
                                          // Increase both counters by 32 bytes each iteration.
                                          mc := add(mc, 0x20)
                                          cc := add(cc, 0x20)
                                      } {
                                          // Write the _preBytes data into the tempBytes memory 32 bytes
                                          // at a time.
                                          mstore(mc, mload(cc))
                                      }
                                      // Add the length of _postBytes to the current length of tempBytes
                                      // and store it as the new length in the first 32 bytes of the
                                      // tempBytes memory.
                                      length := mload(_postBytes)
                                      mstore(tempBytes, add(length, mload(tempBytes)))
                                      // Move the memory counter back from a multiple of 0x20 to the
                                      // actual end of the _preBytes data.
                                      mc := end
                                      // Stop copying when the memory counter reaches the new combined
                                      // length of the arrays.
                                      end := add(mc, length)
                                      for {
                                          let cc := add(_postBytes, 0x20)
                                      } lt(mc, end) {
                                          mc := add(mc, 0x20)
                                          cc := add(cc, 0x20)
                                      } {
                                          mstore(mc, mload(cc))
                                      }
                                      // Update the free-memory pointer by padding our last write location
                                      // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
                                      // next 32 byte block, then round down to the nearest multiple of
                                      // 32. If the sum of the length of the two arrays is zero then add
                                      // one before rounding down to leave a blank 32 bytes (the length block with 0).
                                      mstore(0x40, and(
                                        add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                                        not(31) // Round down to the nearest 32 bytes.
                                      ))
                                  }
                                  return tempBytes;
                              }
                              function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
                                  assembly {
                                      // Read the first 32 bytes of _preBytes storage, which is the length
                                      // of the array. (We don't need to use the offset into the slot
                                      // because arrays use the entire slot.)
                                      let fslot := sload(_preBytes.slot)
                                      // Arrays of 31 bytes or less have an even value in their slot,
                                      // while longer arrays have an odd value. The actual length is
                                      // the slot divided by two for odd values, and the lowest order
                                      // byte divided by two for even values.
                                      // If the slot is even, bitwise and the slot with 255 and divide by
                                      // two to get the length. If the slot is odd, bitwise and the slot
                                      // with -1 and divide by two.
                                      let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                                      let mlength := mload(_postBytes)
                                      let newlength := add(slength, mlength)
                                      // slength can contain both the length and contents of the array
                                      // if length < 32 bytes so let's prepare for that
                                      // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                                      switch add(lt(slength, 32), lt(newlength, 32))
                                      case 2 {
                                          // Since the new array still fits in the slot, we just need to
                                          // update the contents of the slot.
                                          // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                                          sstore(
                                              _preBytes.slot,
                                              // all the modifications to the slot are inside this
                                              // next block
                                              add(
                                                  // we can just add to the slot contents because the
                                                  // bytes we want to change are the LSBs
                                                  fslot,
                                                  add(
                                                      mul(
                                                          div(
                                                              // load the bytes from memory
                                                              mload(add(_postBytes, 0x20)),
                                                              // zero all bytes to the right
                                                              exp(0x100, sub(32, mlength))
                                                          ),
                                                          // and now shift left the number of bytes to
                                                          // leave space for the length in the slot
                                                          exp(0x100, sub(32, newlength))
                                                      ),
                                                      // increase length by the double of the memory
                                                      // bytes length
                                                      mul(mlength, 2)
                                                  )
                                              )
                                          )
                                      }
                                      case 1 {
                                          // The stored value fits in the slot, but the combined value
                                          // will exceed it.
                                          // get the keccak hash to get the contents of the array
                                          mstore(0x0, _preBytes.slot)
                                          let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                                          // save new length
                                          sstore(_preBytes.slot, add(mul(newlength, 2), 1))
                                          // The contents of the _postBytes array start 32 bytes into
                                          // the structure. Our first read should obtain the `submod`
                                          // bytes that can fit into the unused space in the last word
                                          // of the stored array. To get this, we read 32 bytes starting
                                          // from `submod`, so the data we read overlaps with the array
                                          // contents by `submod` bytes. Masking the lowest-order
                                          // `submod` bytes allows us to add that value directly to the
                                          // stored value.
                                          let submod := sub(32, slength)
                                          let mc := add(_postBytes, submod)
                                          let end := add(_postBytes, mlength)
                                          let mask := sub(exp(0x100, submod), 1)
                                          sstore(
                                              sc,
                                              add(
                                                  and(
                                                      fslot,
                                                      0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                                                  ),
                                                  and(mload(mc), mask)
                                              )
                                          )
                                          for {
                                              mc := add(mc, 0x20)
                                              sc := add(sc, 1)
                                          } lt(mc, end) {
                                              sc := add(sc, 1)
                                              mc := add(mc, 0x20)
                                          } {
                                              sstore(sc, mload(mc))
                                          }
                                          mask := exp(0x100, sub(mc, end))
                                          sstore(sc, mul(div(mload(mc), mask), mask))
                                      }
                                      default {
                                          // get the keccak hash to get the contents of the array
                                          mstore(0x0, _preBytes.slot)
                                          // Start copying to the last used word of the stored array.
                                          let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                                          // save new length
                                          sstore(_preBytes.slot, add(mul(newlength, 2), 1))
                                          // Copy over the first `submod` bytes of the new data as in
                                          // case 1 above.
                                          let slengthmod := mod(slength, 32)
                                          let mlengthmod := mod(mlength, 32)
                                          let submod := sub(32, slengthmod)
                                          let mc := add(_postBytes, submod)
                                          let end := add(_postBytes, mlength)
                                          let mask := sub(exp(0x100, submod), 1)
                                          sstore(sc, add(sload(sc), and(mload(mc), mask)))
                                          for {
                                              sc := add(sc, 1)
                                              mc := add(mc, 0x20)
                                          } lt(mc, end) {
                                              sc := add(sc, 1)
                                              mc := add(mc, 0x20)
                                          } {
                                              sstore(sc, mload(mc))
                                          }
                                          mask := exp(0x100, sub(mc, end))
                                          sstore(sc, mul(div(mload(mc), mask), mask))
                                      }
                                  }
                              }
                              function slice(
                                  bytes memory _bytes,
                                  uint256 _start,
                                  uint256 _length
                              )
                                  internal
                                  pure
                                  returns (bytes memory)
                              {
                                  require(_length + 31 >= _length, "slice_overflow");
                                  require(_bytes.length >= _start + _length, "slice_outOfBounds");
                                  bytes memory tempBytes;
                                  assembly {
                                      switch iszero(_length)
                                      case 0 {
                                          // Get a location of some free memory and store it in tempBytes as
                                          // Solidity does for memory variables.
                                          tempBytes := mload(0x40)
                                          // The first word of the slice result is potentially a partial
                                          // word read from the original array. To read it, we calculate
                                          // the length of that partial word and start copying that many
                                          // bytes into the array. The first word we copy will start with
                                          // data we don't care about, but the last `lengthmod` bytes will
                                          // land at the beginning of the contents of the new array. When
                                          // we're done copying, we overwrite the full first word with
                                          // the actual length of the slice.
                                          let lengthmod := and(_length, 31)
                                          // The multiplication in the next line is necessary
                                          // because when slicing multiples of 32 bytes (lengthmod == 0)
                                          // the following copy loop was copying the origin's length
                                          // and then ending prematurely not copying everything it should.
                                          let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                                          let end := add(mc, _length)
                                          for {
                                              // The multiplication in the next line has the same exact purpose
                                              // as the one above.
                                              let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                                          } lt(mc, end) {
                                              mc := add(mc, 0x20)
                                              cc := add(cc, 0x20)
                                          } {
                                              mstore(mc, mload(cc))
                                          }
                                          mstore(tempBytes, _length)
                                          //update free-memory pointer
                                          //allocating the array padded to 32 bytes like the compiler does now
                                          mstore(0x40, and(add(mc, 31), not(31)))
                                      }
                                      //if we want a zero-length slice let's just return a zero-length array
                                      default {
                                          tempBytes := mload(0x40)
                                          //zero out the 32 bytes slice we are about to return
                                          //we need to do it because Solidity does not garbage collect
                                          mstore(tempBytes, 0)
                                          mstore(0x40, add(tempBytes, 0x20))
                                      }
                                  }
                                  return tempBytes;
                              }
                              function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
                                  require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
                                  address tempAddress;
                                  assembly {
                                      tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
                                  }
                                  return tempAddress;
                              }
                              function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
                                  require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
                                  uint8 tempUint;
                                  assembly {
                                      tempUint := mload(add(add(_bytes, 0x1), _start))
                                  }
                                  return tempUint;
                              }
                              function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
                                  require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
                                  uint16 tempUint;
                                  assembly {
                                      tempUint := mload(add(add(_bytes, 0x2), _start))
                                  }
                                  return tempUint;
                              }
                              function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
                                  require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
                                  uint32 tempUint;
                                  assembly {
                                      tempUint := mload(add(add(_bytes, 0x4), _start))
                                  }
                                  return tempUint;
                              }
                              function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
                                  require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
                                  uint64 tempUint;
                                  assembly {
                                      tempUint := mload(add(add(_bytes, 0x8), _start))
                                  }
                                  return tempUint;
                              }
                              function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
                                  require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
                                  uint96 tempUint;
                                  assembly {
                                      tempUint := mload(add(add(_bytes, 0xc), _start))
                                  }
                                  return tempUint;
                              }
                              function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
                                  require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
                                  uint128 tempUint;
                                  assembly {
                                      tempUint := mload(add(add(_bytes, 0x10), _start))
                                  }
                                  return tempUint;
                              }
                              function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
                                  require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
                                  uint256 tempUint;
                                  assembly {
                                      tempUint := mload(add(add(_bytes, 0x20), _start))
                                  }
                                  return tempUint;
                              }
                              function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
                                  require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
                                  bytes32 tempBytes32;
                                  assembly {
                                      tempBytes32 := mload(add(add(_bytes, 0x20), _start))
                                  }
                                  return tempBytes32;
                              }
                              function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
                                  bool success = true;
                                  assembly {
                                      let length := mload(_preBytes)
                                      // if lengths don't match the arrays are not equal
                                      switch eq(length, mload(_postBytes))
                                      case 1 {
                                          // cb is a circuit breaker in the for loop since there's
                                          //  no said feature for inline assembly loops
                                          // cb = 1 - don't breaker
                                          // cb = 0 - break
                                          let cb := 1
                                          let mc := add(_preBytes, 0x20)
                                          let end := add(mc, length)
                                          for {
                                              let cc := add(_postBytes, 0x20)
                                          // the next line is the loop condition:
                                          // while(uint256(mc < end) + cb == 2)
                                          } eq(add(lt(mc, end), cb), 2) {
                                              mc := add(mc, 0x20)
                                              cc := add(cc, 0x20)
                                          } {
                                              // if any of these checks fails then arrays are not equal
                                              if iszero(eq(mload(mc), mload(cc))) {
                                                  // unsuccess:
                                                  success := 0
                                                  cb := 0
                                              }
                                          }
                                      }
                                      default {
                                          // unsuccess:
                                          success := 0
                                      }
                                  }
                                  return success;
                              }
                              function equalStorage(
                                  bytes storage _preBytes,
                                  bytes memory _postBytes
                              )
                                  internal
                                  view
                                  returns (bool)
                              {
                                  bool success = true;
                                  assembly {
                                      // we know _preBytes_offset is 0
                                      let fslot := sload(_preBytes.slot)
                                      // Decode the length of the stored array like in concatStorage().
                                      let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                                      let mlength := mload(_postBytes)
                                      // if lengths don't match the arrays are not equal
                                      switch eq(slength, mlength)
                                      case 1 {
                                          // slength can contain both the length and contents of the array
                                          // if length < 32 bytes so let's prepare for that
                                          // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                                          if iszero(iszero(slength)) {
                                              switch lt(slength, 32)
                                              case 1 {
                                                  // blank the last byte which is the length
                                                  fslot := mul(div(fslot, 0x100), 0x100)
                                                  if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                                                      // unsuccess:
                                                      success := 0
                                                  }
                                              }
                                              default {
                                                  // cb is a circuit breaker in the for loop since there's
                                                  //  no said feature for inline assembly loops
                                                  // cb = 1 - don't breaker
                                                  // cb = 0 - break
                                                  let cb := 1
                                                  // get the keccak hash to get the contents of the array
                                                  mstore(0x0, _preBytes.slot)
                                                  let sc := keccak256(0x0, 0x20)
                                                  let mc := add(_postBytes, 0x20)
                                                  let end := add(mc, mlength)
                                                  // the next line is the loop condition:
                                                  // while(uint256(mc < end) + cb == 2)
                                                  for {} eq(add(lt(mc, end), cb), 2) {
                                                      sc := add(sc, 1)
                                                      mc := add(mc, 0x20)
                                                  } {
                                                      if iszero(eq(sload(sc), mload(mc))) {
                                                          // unsuccess:
                                                          success := 0
                                                          cb := 0
                                                      }
                                                  }
                                              }
                                          }
                                      }
                                      default {
                                          // unsuccess:
                                          success := 0
                                      }
                                  }
                                  return success;
                              }
                          }// SPDX-License-Identifier: LGPL-3.0-only
                          pragma solidity >=0.7.0 <0.9.0;
                          /// @title Multi Send Call Only - Allows to batch multiple transactions into one, but only calls
                          /// @author Stefan George - <[email protected]>
                          /// @author Richard Meissner - <[email protected]>
                          /// @notice The guard logic is not required here as this contract doesn't support nested delegate calls
                          contract MultiSendCallOnly {
                              /// @dev Sends multiple transactions and reverts all if one fails.
                              /// @param transactions Encoded transactions. Each transaction is encoded as a packed bytes of
                              ///                     operation has to be uint8(0) in this version (=> 1 byte),
                              ///                     to as a address (=> 20 bytes),
                              ///                     value as a uint256 (=> 32 bytes),
                              ///                     data length as a uint256 (=> 32 bytes),
                              ///                     data as bytes.
                              ///                     see abi.encodePacked for more information on packed encoding
                              /// @notice The code is for most part the same as the normal MultiSend (to keep compatibility),
                              ///         but reverts if a transaction tries to use a delegatecall.
                              /// @notice This method is payable as delegatecalls keep the msg.value from the previous call
                              ///         If the calling method (e.g. execTransaction) received ETH this would revert otherwise
                              function _multiSend(bytes memory transactions) internal {
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly {
                                      let length := mload(transactions)
                                      let i := 0x20
                                      for {
                                          // Pre block is not used in "while mode"
                                      } lt(i, length) {
                                          // Post block is not used in "while mode"
                                      } {
                                          // First byte of the data is the operation.
                                          // We shift by 248 bits (256 - 8 [operation byte]) it right since mload will always load 32 bytes (a word).
                                          // This will also zero out unused data.
                                          let operation := shr(0xf8, mload(add(transactions, i)))
                                          // We offset the load address by 1 byte (operation byte)
                                          // We shift it right by 96 bits (256 - 160 [20 address bytes]) to right-align the data and zero out unused data.
                                          let to := shr(0x60, mload(add(transactions, add(i, 0x01))))
                                          // We offset the load address by 21 byte (operation byte + 20 address bytes)
                                          let value := mload(add(transactions, add(i, 0x15)))
                                          // We offset the load address by 53 byte (operation byte + 20 address bytes + 32 value bytes)
                                          let dataLength := mload(add(transactions, add(i, 0x35)))
                                          // We offset the load address by 85 byte (operation byte + 20 address bytes + 32 value bytes + 32 data length bytes)
                                          let data := add(transactions, add(i, 0x55))
                                          let success := 0
                                          switch operation
                                              case 0 {
                                                  success := call(gas(), to, value, data, dataLength, 0, 0)
                                              }
                                              // This version does not allow delegatecalls
                                              case 1 {
                                                  revert(0, 0)
                                              }
                                          if eq(success, 0) {
                                              revert(0, 0)
                                          }
                                          // Next entry starts at 85 byte + data length
                                          i := add(i, add(0x55, dataLength))
                                      }
                                  }
                              }
                          }// SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (access/IAccessControl.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev External interface of AccessControl declared to support ERC165 detection.
                           */
                          interface IAccessControlUpgradeable {
                              /**
                               * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                               *
                               * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                               * {RoleAdminChanged} not being emitted signaling this.
                               *
                               * _Available since v3.1._
                               */
                              event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
                              /**
                               * @dev Emitted when `account` is granted `role`.
                               *
                               * `sender` is the account that originated the contract call, an admin role
                               * bearer except when using {AccessControl-_setupRole}.
                               */
                              event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Emitted when `account` is revoked `role`.
                               *
                               * `sender` is the account that originated the contract call:
                               *   - if using `revokeRole`, it is the admin role bearer
                               *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                               */
                              event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
                              /**
                               * @dev Returns `true` if `account` has been granted `role`.
                               */
                              function hasRole(bytes32 role, address account) external view returns (bool);
                              /**
                               * @dev Returns the admin role that controls `role`. See {grantRole} and
                               * {revokeRole}.
                               *
                               * To change a role's admin, use {AccessControl-_setRoleAdmin}.
                               */
                              function getRoleAdmin(bytes32 role) external view returns (bytes32);
                              /**
                               * @dev Grants `role` to `account`.
                               *
                               * If `account` had not been already granted `role`, emits a {RoleGranted}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function grantRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from `account`.
                               *
                               * If `account` had been granted `role`, emits a {RoleRevoked} event.
                               *
                               * Requirements:
                               *
                               * - the caller must have ``role``'s admin role.
                               */
                              function revokeRole(bytes32 role, address account) external;
                              /**
                               * @dev Revokes `role` from the calling account.
                               *
                               * Roles are often managed via {grantRole} and {revokeRole}: this function's
                               * purpose is to provide a mechanism for accounts to lose their privileges
                               * if they are compromised (such as when a trusted device is misplaced).
                               *
                               * If the calling account had been granted `role`, emits a {RoleRevoked}
                               * event.
                               *
                               * Requirements:
                               *
                               * - the caller must be `account`.
                               */
                              function renounceRole(bytes32 role, address account) external;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Context.sol)
                          pragma solidity ^0.8.0;
                          import "../proxy/utils/Initializable.sol";
                          /**
                           * @dev Provides information about the current execution context, including the
                           * sender of the transaction and its data. While these are generally available
                           * via msg.sender and msg.data, they should not be accessed in such a direct
                           * manner, since when dealing with meta-transactions the account sending and
                           * paying for execution may not be the actual sender (as far as an application
                           * is concerned).
                           *
                           * This contract is only required for intermediate, library-like contracts.
                           */
                          abstract contract ContextUpgradeable is Initializable {
                              function __Context_init() internal initializer {
                                  __Context_init_unchained();
                              }
                              function __Context_init_unchained() internal initializer {
                              }
                              function _msgSender() internal view virtual returns (address) {
                                  return msg.sender;
                              }
                              function _msgData() internal view virtual returns (bytes calldata) {
                                  return msg.data;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/Strings.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev String operations.
                           */
                          library StringsUpgradeable {
                              bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                               */
                              function toString(uint256 value) internal pure returns (string memory) {
                                  // Inspired by OraclizeAPI's implementation - MIT licence
                                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                                  if (value == 0) {
                                      return "0";
                                  }
                                  uint256 temp = value;
                                  uint256 digits;
                                  while (temp != 0) {
                                      digits++;
                                      temp /= 10;
                                  }
                                  bytes memory buffer = new bytes(digits);
                                  while (value != 0) {
                                      digits -= 1;
                                      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                                      value /= 10;
                                  }
                                  return string(buffer);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                               */
                              function toHexString(uint256 value) internal pure returns (string memory) {
                                  if (value == 0) {
                                      return "0x00";
                                  }
                                  uint256 temp = value;
                                  uint256 length = 0;
                                  while (temp != 0) {
                                      length++;
                                      temp >>= 8;
                                  }
                                  return toHexString(value, length);
                              }
                              /**
                               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                               */
                              function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                                  bytes memory buffer = new bytes(2 * length + 2);
                                  buffer[0] = "0";
                                  buffer[1] = "x";
                                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                                      buffer[i] = _HEX_SYMBOLS[value & 0xf];
                                      value >>= 4;
                                  }
                                  require(value == 0, "Strings: hex length insufficient");
                                  return string(buffer);
                              }
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/introspection/ERC165.sol)
                          pragma solidity ^0.8.0;
                          import "./IERC165Upgradeable.sol";
                          import "../../proxy/utils/Initializable.sol";
                          /**
                           * @dev Implementation of the {IERC165} interface.
                           *
                           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
                           * for the additional interface id that will be supported. For example:
                           *
                           * ```solidity
                           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
                           * }
                           * ```
                           *
                           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
                           */
                          abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
                              function __ERC165_init() internal initializer {
                                  __ERC165_init_unchained();
                              }
                              function __ERC165_init_unchained() internal initializer {
                              }
                              /**
                               * @dev See {IERC165-supportsInterface}.
                               */
                              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                                  return interfaceId == type(IERC165Upgradeable).interfaceId;
                              }
                              uint256[50] private __gap;
                          }
                          // SPDX-License-Identifier: MIT
                          // OpenZeppelin Contracts v4.4.0 (utils/introspection/IERC165.sol)
                          pragma solidity ^0.8.0;
                          /**
                           * @dev Interface of the ERC165 standard, as defined in the
                           * https://eips.ethereum.org/EIPS/eip-165[EIP].
                           *
                           * Implementers can declare support of contract interfaces, which can then be
                           * queried by others ({ERC165Checker}).
                           *
                           * For an implementation, see {ERC165}.
                           */
                          interface IERC165Upgradeable {
                              /**
                               * @dev Returns true if this contract implements the interface defined by
                               * `interfaceId`. See the corresponding
                               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                               * to learn more about how these ids are created.
                               *
                               * This function call must use less than 30 000 gas.
                               */
                              function supportsInterface(bytes4 interfaceId) external view returns (bool);
                          }