ETH Price: $2,311.89 (+1.66%)

Transaction Decoder

Block:
22215098 at Apr-07-2025 06:00:11 AM +UTC
Transaction Fee:
0.000598067969491748 ETH $1.38
Gas Used:
324,716 Gas / 1.841818603 Gwei

Emitted Events:

578 ERC1967Proxy.0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec( 0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec, 0xf9c96a45784d0ce4390825a43a313149da787e6a6c66076f3a3f83e92501baeb, 0000000000000000000000000000000000000000000000000000000067f369df, 00000000000000000000000000000000000000000000000000000000059b86f9, 00000000000000000000000000000000000000000000000000000000000369e9 )
579 0xcb26c67ece9d7bbdb0205ee4c33f8503a0346134.0x8f8f4d49bbb03ffac818a5d588ec1786a4d2d17269871cbf5b1745f58b64c15d( 0x8f8f4d49bbb03ffac818a5d588ec1786a4d2d17269871cbf5b1745f58b64c15d, 0x00000000000000000000000020d12300b4805708d4293d29cb83c1e01d6f8913, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000002710, 0000000000000000000000000000000000000000000000000000000000000640, 00000000000000000000000000000000000000000000000000000000000005a4, bc36c0a900000000000000000000000000000000000000000000000000000000, 0000002000000000000000000000000000000000000000000000000000000000, 0000000100000000000000000000000000000000000000000000000000000000, 0000002000000000000000000000000000000000000000000000000000000000, 0000050b504e41550100000003b801000000040d00780afaba14204f0f5751b7, 4e7ec43eeac39851ce11fd9bdafc3cfebee94a5df40382100a326c132c694a44, e75afb933d3681a82b8fc3ca5330d5a7c309531dcd0102a6982c128c9af4b0a1, 5e94e1f000c0aa19253a9f69971b309d13385a4b075e2c4e0eddb61dfe21fdd2, 7c4164919e1b61b54257c0257b6863550599076dbe023601031c891e87ee8ac2, f2dd7d7d035c3b10d9dce137d8a0373e43a68274d26189a39c2ba3ea14ca9d6f, 4e601db1f1d09734c4bd97a5d4dd3f14ea58e4845ab8a66d5100047970933091, e0abcdd69a9b259125d46bb1597d1ec55b9e9d9709f0541ea6b5064313343c3e, b4f33d4843b71ebad32eca73150945548d38e26068600862e8d0d70106c3cb2c, 3111b618d6a24ce1c269b77864511284a53177249282b04a11404b72d9168f35, 8bdbf042d02ffbb646574e1176c9881531b4291b450363092035fe2e39000882, 8bf5b912ee7083450a7aa9980402207a1c87fca5fd9792b2d55f060c4492c201, 8811efae0a4e4452b57af652ed2a6237e4a4a8802150359151ebb45bdf832d00, 0a1b5d6105ad894a585a4bfba745c32b3400ee6fbf718090b554d0ebd7e0b80f, 3039619c96d4bb1ee5aeda0af06842a58b43f4a5456e62f3ea77a4c19f2f1538, c6010ba02465dfc657a6d52137a2d14f707786cee03d2a1c1aa0de1bff772625, 20ea5a7629b6a5848c1036b22823edcb6aaf56e5110caa6bcd3afec9e70002b9, 1e062f000de24e893b40e7a6114e0a353060bf2a5409b324bf981d724071f9be, e4cb10b4691c3570419ef1d43b1fb96cce5e3b10f8aaf9e814228ae469beb9e8, cd0875f903010e8777dd603acc398447e4d1d354ae4f873df1ef132ea7740e89, 66f3ac93281dc40ae2350308dbfb7844792778ea2d8c8f61fcc4775c3f3a08f0, 8e8151d5a2e9e6000f0b988eaaf946987c9506c92fd2c84f0b18ae288de52268, 18e5110d2ef5cd47a96e891d629a05bf8650a898181421b555b74803a84e31d2, 06f4093ae5919e0a1a0010c86940c999d121dce9eb0b51e16566117c02b9235a, 45dde2d96181373371a5ae68394ca567775c1947997b5808ba716780100b8a63, 821fc541eeec7cb4cb76d00111003fd3c3599a8ed5127bb438392b328f2f1200, d7276bedc6245d2b482918e9960dafc85b097dcd66e46cdb0470349ccad6c01c, 76978e77720f8460d0c005cf2d0167f369df00000000001ae101faedac5851e3, 2b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000767a366, 014155575600000000000c74ec3a000027102a3f705e7618035f3210f1e82fc3, bf957d14f25501005500f9c96a45784d0ce4390825a43a313149da787e6a6c66, 076f3a3f83e92501baeb00000000059b86f900000000000369e9fffffff80000, 000067f369df0000000067f369df00000000059b44d60000000000032e620c64, befef33fc88e9699514884748cf1e78e4496fa0ae60d2298a27d7cda37d4533b, cb293fe4bece2ee7a7a17996dd321afaa980230c1c0745c823e6846d5eebb217, db849a04a46378d74afbe5620b61d9b65a613d98a274e8b30c63702aa8acb1d1, 403d55fe996e25039ecec5c59a72b5dce4e42dbe46435dc89e06cfd11cbb7b64, cb3932c0f9cd0d3d3fb9333abd13f27c746f9d835b5980093d92e5293355d037, 495fc91c4f4296b033a13a1304c1f99f6780f30d48052502d53a231a49959800, 9dccf3a810d5d9a018f1bcbb77b49875f797b7450a3fa11c49b0a97a01d47fdf, 0417b9845358c3c3ec2367600936fe0000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
580 EIP173Proxy.0x6bc93adab97dd835bee818087939b726558bc8d9177650a0018dd05eb00e56c8( 0x6bc93adab97dd835bee818087939b726558bc8d9177650a0018dd05eb00e56c8, 372ef793ce7f4c5830a8d9aa136e0c1b3c11c3db0ab96e3910de8dea1fb7e397, 37717b1710ec8bb427c7a0a1bf880e3c6336f6bf92a3bd3345a5e22ce2ad1471, 0000000000000000000000000000000000000000000000000000000000000001 )
581 Gelato.0xc6cfec28363edf86fe132edcedb30ccc6dbb89a7ec5f428aaeeb8ae5d901537d( 0xc6cfec28363edf86fe132edcedb30ccc6dbb89a7ec5f428aaeeb8ae5d901537d, 37717b1710ec8bb427c7a0a1bf880e3c6336f6bf92a3bd3345a5e22ce2ad1471, 0000000000000000000000002a6c106ae13b558bb9e2ec64bd2f1f7beff3a5e0, 000000000000000000000000df8f2aeea963803140df7b4ddd11216e584577b4, 000000000000000000000000417b4adc279743fc49f047c323fc668db9e600d8 )

Account State Difference:

  Address   Before After State Difference Code
0x20D12300...01d6f8913 0.010000000002189757 Eth0.010000000002199756 Eth0.000000000000009999
0x3CACa7b4...9180E83b6
0x417B4Adc...db9E600D8
(Bundler: 0x417...0d8)
6.290462320694787695 Eth
Nonce: 31993
6.289864252725295947 Eth
Nonce: 31994
0.000598067969491748
0x4305FB66...90A4c69C6
(Angle Protocol: Pyth Oracle)
0.000000908717056804 Eth0.000000908717056805 Eth0.000000000000000001
(beaverbuild)
13.496037976586367252 Eth13.496435063608691384 Eth0.000397087022324132
0xCB26C67e...3a0346134 0.00999999999781 Eth0.0099999999978 Eth0.00000000000001

Execution Trace

Gelato.09c56431( )
  • 0x1c410b318a26c0d6223e8f79ce8c5fd099c529d4.09c56431( )
    • Null: 0x000...001.07c9e498( )
    • EIP173Proxy.80381407( )
      • Automate.execBypassModule( _taskCreator=0x0F6e98A756A40dD050dC78959f45559F98d3289d, _execAddress=0xCB26C67eCE9d7Bbdb0205ee4C33f8503a0346134, _taskId=372EF793CE7F4C5830A8D9AA136E0C1B3C11C3DB0AB96E3910DE8DEA1FB7E397, _correlationId=37717B1710EC8BB427C7A0A1BF880E3C6336F6BF92A3BD3345A5E22CE2AD1471, _execData=0x54132D7800000000000000000000000020D12300B4805708D4293D29CB83C1E01D6F89130000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000005A4BC36C0A9000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000050B504E41550100000003B801000000040D00780AFABA14204F0F5751B74E7EC43EEAC39851CE11FD9BDAFC3CFEBEE94A5DF40382100A326C132C694A44E75AFB933D3681A82B8FC3CA5330D5A7C309531DCD0102A6982C128C9AF4B0A15E94E1F000C0AA19253A9F69971B309D13385A4B075E2C4E0EDDB61DFE21FDD27C4164919E1B61B54257C0257B6863550599076DBE023601031C891E87EE8AC2F2DD7D7D035C3B10D9DCE137D8A0373E43A68274D26189A39C2BA3EA14CA9D6F4E601DB1F1D09734C4BD97A5D4DD3F14EA58E4845AB8A66D5100047970933091E0ABCDD69A9B259125D46BB1597D1EC55B9E9D9709F0541EA6B5064313343C3EB4F33D4843B71EBAD32ECA73150945548D38E26068600862E8D0D70106C3CB2C3111B618D6A24CE1C269B77864511284A53177249282B04A11404B72D9168F358BDBF042D02FFBB646574E1176C9881531B4291B450363092035FE2E390008828BF5B912EE7083450A7AA9980402207A1C87FCA5FD9792B2D55F060C4492C2018811EFAE0A4E4452B57AF652ED2A6237E4A4A8802150359151EBB45BDF832D000A1B5D6105AD894A585A4BFBA745C32B3400EE6FBF718090B554D0EBD7E0B80F3039619C96D4BB1EE5AEDA0AF06842A58B43F4A5456E62F3EA77A4C19F2F1538C6010BA02465DFC657A6D52137A2D14F707786CEE03D2A1C1AA0DE1BFF77262520EA5A7629B6A5848C1036B22823EDCB6AAF56E5110CAA6BCD3AFEC9E70002B91E062F000DE24E893B40E7A6114E0A353060BF2A5409B324BF981D724071F9BEE4CB10B4691C3570419EF1D43B1FB96CCE5E3B10F8AAF9E814228AE469BEB9E8CD0875F903010E8777DD603ACC398447E4D1D354AE4F873DF1EF132EA7740E8966F3AC93281DC40AE2350308DBFB7844792778EA2D8C8F61FCC4775C3F3A08F08E8151D5A2E9E6000F0B988EAAF946987C9506C92FD2C84F0B18AE288DE5226818E5110D2EF5CD47A96E891D629A05BF8650A898181421B555B74803A84E31D206F4093AE5919E0A1A0010C86940C999D121DCE9EB0B51E16566117C02B9235A45DDE2D96181373371A5AE68394CA567775C1947997B5808BA716780100B8A63821FC541EEEC7CB4CB76D00111003FD3C3599A8ED5127BB438392B328F2F1200D7276BEDC6245D2B482918E9960DAFC85B097DCD66E46CDB0470349CCAD6C01C76978E77720F8460D0C005CF2D0167F369DF00000000001AE101FAEDAC5851E32B9B23B5F9411A8C2BAC4AAE3ED4DD7B811DD1A72EA4AA71000000000767A366014155575600000000000C74EC3A000027102A3F705E7618035F3210F1E82FC3BF957D14F25501005500F9C96A45784D0CE4390825A43A313149DA787E6A6C66076F3A3F83E92501BAEB00000000059B86F900000000000369E9FFFFFFF80000000067F369DF0000000067F369DF00000000059B44D60000000000032E620C64BEFEF33FC88E9699514884748CF1E78E4496FA0AE60D2298A27D7CDA37D4533BCB293FE4BECE2EE7A7A17996DD321AFAA980230C1C0745C823E6846D5EEBB217DB849A04A46378D74AFBE5620B61D9B65A613D98A274E8B30C63702AA8ACB1D1403D55FE996E25039ECEC5C59A72B5DCE4E42DBE46435DC89E06CFD11CBB7B64CB3932C0F9CD0D3D3FB9333ABD13F27C746F9D835B5980093D92E5293355D037495FC91C4F4296B033A13A1304C1F99F6780F30D48052502D53A231A499598009DCCF3A810D5D9A018F1BCBB77B49875F797B7450A3FA11C49B0A97A01D47FDF0417B9845358C3C3EC2367600936FE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, _revertOnFailure=True, _singleExec=False )
        • 0xcb26c67ece9d7bbdb0205ee4c33f8503a0346134.54132d78( )
          • OpsProxy.executeCall( _target=0x20D12300B4805708d4293d29cb83c1e01d6f8913, _data=0xBC36C0A9000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000050B504E41550100000003B801000000040D00780AFABA14204F0F5751B74E7EC43EEAC39851CE11FD9BDAFC3CFEBEE94A5DF40382100A326C132C694A44E75AFB933D3681A82B8FC3CA5330D5A7C309531DCD0102A6982C128C9AF4B0A15E94E1F000C0AA19253A9F69971B309D13385A4B075E2C4E0EDDB61DFE21FDD27C4164919E1B61B54257C0257B6863550599076DBE023601031C891E87EE8AC2F2DD7D7D035C3B10D9DCE137D8A0373E43A68274D26189A39C2BA3EA14CA9D6F4E601DB1F1D09734C4BD97A5D4DD3F14EA58E4845AB8A66D5100047970933091E0ABCDD69A9B259125D46BB1597D1EC55B9E9D9709F0541EA6B5064313343C3EB4F33D4843B71EBAD32ECA73150945548D38E26068600862E8D0D70106C3CB2C3111B618D6A24CE1C269B77864511284A53177249282B04A11404B72D9168F358BDBF042D02FFBB646574E1176C9881531B4291B450363092035FE2E390008828BF5B912EE7083450A7AA9980402207A1C87FCA5FD9792B2D55F060C4492C2018811EFAE0A4E4452B57AF652ED2A6237E4A4A8802150359151EBB45BDF832D000A1B5D6105AD894A585A4BFBA745C32B3400EE6FBF718090B554D0EBD7E0B80F3039619C96D4BB1EE5AEDA0AF06842A58B43F4A5456E62F3EA77A4C19F2F1538C6010BA02465DFC657A6D52137A2D14F707786CEE03D2A1C1AA0DE1BFF77262520EA5A7629B6A5848C1036B22823EDCB6AAF56E5110CAA6BCD3AFEC9E70002B91E062F000DE24E893B40E7A6114E0A353060BF2A5409B324BF981D724071F9BEE4CB10B4691C3570419EF1D43B1FB96CCE5E3B10F8AAF9E814228AE469BEB9E8CD0875F903010E8777DD603ACC398447E4D1D354AE4F873DF1EF132EA7740E8966F3AC93281DC40AE2350308DBFB7844792778EA2D8C8F61FCC4775C3F3A08F08E8151D5A2E9E6000F0B988EAAF946987C9506C92FD2C84F0B18AE288DE5226818E5110D2EF5CD47A96E891D629A05BF8650A898181421B555B74803A84E31D206F4093AE5919E0A1A0010C86940C999D121DCE9EB0B51E16566117C02B9235A45DDE2D96181373371A5AE68394CA567775C1947997B5808BA716780100B8A63821FC541EEEC7CB4CB76D00111003FD3C3599A8ED5127BB438392B328F2F1200D7276BEDC6245D2B482918E9960DAFC85B097DCD66E46CDB0470349CCAD6C01C76978E77720F8460D0C005CF2D0167F369DF00000000001AE101FAEDAC5851E32B9B23B5F9411A8C2BAC4AAE3ED4DD7B811DD1A72EA4AA71000000000767A366014155575600000000000C74EC3A000027102A3F705E7618035F3210F1E82FC3BF957D14F25501005500F9C96A45784D0CE4390825A43A313149DA787E6A6C66076F3A3F83E92501BAEB00000000059B86F900000000000369E9FFFFFFF80000000067F369DF0000000067F369DF00000000059B44D60000000000032E620C64BEFEF33FC88E9699514884748CF1E78E4496FA0AE60D2298A27D7CDA37D4533BCB293FE4BECE2EE7A7A17996DD321AFAA980230C1C0745C823E6846D5EEBB217DB849A04A46378D74AFBE5620B61D9B65A613D98A274E8B30C63702AA8ACB1D1403D55FE996E25039ECEC5C59A72B5DCE4E42DBE46435DC89E06CFD11CBB7B64CB3932C0F9CD0D3D3FB9333ABD13F27C746F9D835B5980093D92E5293355D037495FC91C4F4296B033A13A1304C1F99F6780F30D48052502D53A231A499598009DCCF3A810D5D9A018F1BCBB77B49875F797B7450A3FA11C49B0A97A01D47FDF0417B9845358C3C3EC2367600936FE000000000000000000000000000000000000000000, _value=10000 )
            • ETH 0.00000000000001 PythUpdater.updateFeeds( priceUpdateData=[UE5BVQEAAAADuAEAAAAEDQB4Cvq6FCBPD1dRt05+xD7qw5hRzhH9m9r8PP6+6Upd9AOCEAoybBMsaUpE51r7kz02gagrj8PKUzDVp8MJUx3NAQKmmCwSjJr0sKFelOHwAMCqGSU6n2mXGzCdEzhaSwdeLE4O3bYd/iH90nxBZJGeG2G1QlfAJXtoY1UFmQdtvgI2AQMciR6H7orC8t19fQNcOxDZ3OE32KA3PkOmgnTSYYmjnCuj6hTKnW9OYB2x8dCXNMS9l6XU3T8U6ljkhFq4pm1RAAR5cJMwkeCrzdaamyWRJdRrsVl9HsVbnp2XCfBUHqa1BkMTNDw+tPM9SEO3HrrTLspzFQlFVI044mBoYAhi6NDXAQbDyywxEbYY1qJM4cJpt3hkURKEpTF3JJKCsEoRQEty2RaPNYvb8ELQL/u2RldOEXbJiBUxtCkbRQNjCSA1/i45AAiCi/W5Eu5wg0UKeqmYBAIgehyH/KX9l5Ky1V8GDESSwgGIEe+uCk5EUrV69lLtKmI35KSogCFQNZFR67Rb34MtAAobXWEFrYlKWFpL+6dFwys0AO5vv3GAkLVU0OvX4LgPMDlhnJbUux7lrtoK8GhCpYtD9KVFbmLz6nekwZ8vFTjGAQugJGXfxlem1SE3otFPcHeGzuA9KhwaoN4b/3cmJSDqWnYptqWEjBA2sigj7ctqr1blEQyqa806/snnAAK5HgYvAA3iTok7QOemEU4KNTBgvypUCbMkv5gdckBx+b7kyxC0aRw1cEGe8dQ7H7lszl47EPiq+egUIorkab656M0IdfkDAQ6Hd91gOsw5hEfk0dNUrk+HPfHvEy6ndA6JZvOskygdxAriNQMI2/t4RHkneOotjI9h/MR3XD86CPCOgVHVounmAA8LmI6q+UaYfJUGyS/SyE8LGK4ojeUiaBjlEQ0u9c1HqW6JHWKaBb+GUKiYGBQhtVW3SAOoTjHSBvQJOuWRngoaABDIaUDJmdEh3OnrC1HhZWYRfAK5I1pF3eLZYYE3M3Glrmg5TKVnd1wZR5l7WAi6cWeAEAuKY4IfxUHu7Hy0y3bQAREAP9PDWZqO1RJ7tDg5KzKPLxIA1ydr7cYkXStIKRjplg2vyFsJfc1m5GzbBHA0nMrWwBx2l453cg+EYNDABc8tAWfzad8AAAAAABrhAfrtrFhR4yubI7X5QRqMK6xKrj7U3XuBHdGnLqSqcQAAAAAHZ6NmAUFVV1YAAAAAAAx07DoAACcQKj9wXnYYA18yEPHoL8O/lX0U8lUBAFUA+clqRXhNDOQ5CCWkOjExSdp4fmpsZgdvOj+D6SUBuusAAAAABZuG+QAAAAAAA2np////+AAAAABn82nfAAAAAGfzad8AAAAABZtE1gAAAAAAAy5iDGS+/vM/yI6WmVFIhHSM8eeORJb6CuYNIpiifXzaN9RTO8spP+S+zi7np6F5lt0yGvqpgCMMHAdFyCPmhG1e67IX24SaBKRjeNdK++ViC2HZtlphPZiidOizDGNwKqissdFAPVX+mW4lA57OxcWacrXc5OQtvkZDXcieBs/RHLt7ZMs5MsD5zQ09P7kzOr0T8nx0b52DW1mACT2S5SkzVdA3SV/JHE9ClrAzoToTBMH5n2eA8w1IBSUC1TojGkmVmACdzPOoENXZoBjxvLt3tJh195e3RQo/oRxJsKl6AdR/3wQXuYRTWMPD7CNnYAk2/g==] )
              File 1 of 6: Gelato
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.0;
              import {LibDiamond} from "./libraries/standard/LibDiamond.sol";
              import {IDiamondLoupe} from "./interfaces/standard/IDiamondLoupe.sol";
              import {IDiamondCut} from "./interfaces/standard/IDiamondCut.sol";
              import {IERC173} from "./interfaces/standard/IERC173.sol";
              import {IERC165} from "./interfaces/standard/IERC165.sol";
              contract Gelato {
                  // more arguments are added to this struct
                  // this avoids stack too deep errors
                  struct DiamondArgs {
                      address owner;
                  }
                  constructor(
                      IDiamondCut.FacetCut[] memory _diamondCut,
                      DiamondArgs memory _args
                  ) payable {
                      LibDiamond.diamondCut(_diamondCut, address(0), new bytes(0));
                      LibDiamond.setContractOwner(_args.owner);
                      LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
                      // adding ERC165 data
                      ds.supportedInterfaces[type(IERC165).interfaceId] = true;
                      ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true;
                      ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true;
                      ds.supportedInterfaces[type(IERC173).interfaceId] = true;
                  }
                  // Find facet for function that is called and execute the
                  // function if a facet is found and return any value.
                  // solhint-disable-next-line no-complex-fallback
                  fallback() external payable {
                      LibDiamond.DiamondStorage storage ds;
                      bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
                      assembly {
                          ds.slot := position
                      }
                      address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress;
                      require(facet != address(0), "Gelato: Function does not exist");
                      assembly {
                          calldatacopy(0, 0, calldatasize())
                          let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
                          returndatacopy(0, 0, returndatasize())
                          switch result
                              case 0 {
                                  revert(0, returndatasize())
                              }
                              default {
                                  return(0, returndatasize())
                              }
                      }
                  }
                  // solhint-disable-next-line no-empty-blocks, ordering
                  receive() external payable {}
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.0;
              /******************************************************************************\\
              * Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)
              * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535
              /******************************************************************************/
              interface IDiamondCut {
                  enum FacetCutAction {Add, Replace, Remove}
                  // Add=0, Replace=1, Remove=2
                  struct FacetCut {
                      address facetAddress;
                      FacetCutAction action;
                      bytes4[] functionSelectors;
                  }
                  event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
                  /// @notice Add/replace/remove any number of functions and optionally execute
                  ///         a function with delegatecall
                  /// @param _diamondCut Contains the facet addresses and function selectors
                  /// @param _init The address of the contract or facet to execute _calldata
                  /// @param _calldata A function call, including function selector and arguments
                  ///                  _calldata is executed with delegatecall on _init
                  function diamondCut(
                      FacetCut[] calldata _diamondCut,
                      address _init,
                      bytes calldata _calldata
                  ) external;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.0;
              /******************************************************************************\\
              * Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)
              * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535
              /******************************************************************************/
              // A loupe is a small magnifying glass used to look at diamonds.
              // These functions look at diamonds
              interface IDiamondLoupe {
                  /// These functions are expected to be called frequently
                  /// by tools.
                  struct Facet {
                      address facetAddress;
                      bytes4[] functionSelectors;
                  }
                  /// @notice Gets all facet addresses and their four byte function selectors.
                  /// @return facets_ Facet
                  function facets() external view returns (Facet[] memory facets_);
                  /// @notice Gets all the function selectors supported by a specific facet.
                  /// @param _facet The facet address.
                  /// @return facetFunctionSelectors_
                  function facetFunctionSelectors(address _facet)
                      external
                      view
                      returns (bytes4[] memory facetFunctionSelectors_);
                  /// @notice Get all the facet addresses used by a diamond.
                  /// @return facetAddresses_
                  function facetAddresses()
                      external
                      view
                      returns (address[] memory facetAddresses_);
                  /// @notice Gets the facet that supports the given selector.
                  /// @dev If facet is not found return address(0).
                  /// @param _functionSelector The function selector.
                  /// @return facetAddress_ The facet address.
                  function facetAddress(bytes4 _functionSelector)
                      external
                      view
                      returns (address facetAddress_);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.0;
              interface IERC165 {
                  /// @notice Query if a contract implements an interface
                  /// @param interfaceId The interface identifier, as specified in ERC-165
                  /// @dev Interface identification is specified in ERC-165. This function
                  ///  uses less than 30,000 gas.
                  /// @return `true` if the contract implements `interfaceID` and
                  ///  `interfaceID` is not 0xffffffff, `false` otherwise
                  function supportsInterface(bytes4 interfaceId) external view returns (bool);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.0;
              /// @title ERC-173 Contract Ownership Standard
              ///  Note: the ERC-165 identifier for this interface is 0x7f5828d0
              /* is ERC165 */
              interface IERC173 {
                  /// @dev This emits when ownership of a contract changes.
                  event OwnershipTransferred(
                      address indexed previousOwner,
                      address indexed newOwner
                  );
                  /// @notice Set the address of the new owner of the contract
                  /// @dev Set _newOwner to address(0) to renounce any ownership.
                  /// @param _newOwner The address of the new owner of the contract
                  function transferOwnership(address _newOwner) external;
                  /// @notice Get the address of the owner
                  /// @return owner_ The address of the owner.
                  function owner() external view returns (address owner_);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.0;
              // https://github.com/mudgen/diamond-3/blob/b009cd08b7822bad727bbcc47aa1b50d8b50f7f0/contracts/libraries/LibDiamond.sol#L1
              /******************************************************************************\\
              * Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)
              * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535
              /******************************************************************************/
              import "../../interfaces/standard/IDiamondCut.sol";
              // Custom due to incorrect string casting (non UTF-8 formatted)
              import {GelatoBytes} from "../../../../lib/GelatoBytes.sol";
              library LibDiamond {
                  bytes32 constant DIAMOND_STORAGE_POSITION =
                      keccak256("diamond.standard.diamond.storage");
                  struct FacetAddressAndPosition {
                      address facetAddress;
                      uint16 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
                  }
                  struct FacetFunctionSelectors {
                      bytes4[] functionSelectors;
                      uint16 facetAddressPosition; // position of facetAddress in facetAddresses array
                  }
                  struct DiamondStorage {
                      // maps function selector to the facet address and
                      // the position of the selector in the facetFunctionSelectors.selectors array
                      mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
                      // maps facet addresses to function selectors
                      mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
                      // facet addresses
                      address[] facetAddresses;
                      // Used to query if a contract implements an interface.
                      // Used to implement ERC-165.
                      mapping(bytes4 => bool) supportedInterfaces;
                      // owner of the contract
                      address contractOwner;
                  }
                  function diamondStorage()
                      internal
                      pure
                      returns (DiamondStorage storage ds)
                  {
                      bytes32 position = DIAMOND_STORAGE_POSITION;
                      assembly {
                          ds.slot := position
                      }
                  }
                  event OwnershipTransferred(
                      address indexed previousOwner,
                      address indexed newOwner
                  );
                  function setContractOwner(address _newOwner) internal {
                      DiamondStorage storage ds = diamondStorage();
                      address previousOwner = ds.contractOwner;
                      ds.contractOwner = _newOwner;
                      emit OwnershipTransferred(previousOwner, _newOwner);
                  }
                  function contractOwner() internal view returns (address contractOwner_) {
                      contractOwner_ = diamondStorage().contractOwner;
                  }
                  function isContractOwner(address _guy) internal view returns (bool) {
                      return _guy == contractOwner();
                  }
                  function enforceIsContractOwner() internal view {
                      require(
                          msg.sender == diamondStorage().contractOwner,
                          "LibDiamond: Must be contract owner"
                      );
                  }
                  event DiamondCut(
                      IDiamondCut.FacetCut[] _diamondCut,
                      address _init,
                      bytes _calldata
                  );
                  // Internal function version of diamondCut
                  function diamondCut(
                      IDiamondCut.FacetCut[] memory _diamondCut,
                      address _init,
                      bytes memory _calldata
                  ) internal {
                      for (
                          uint256 facetIndex;
                          facetIndex < _diamondCut.length;
                          facetIndex++
                      ) {
                          IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
                          if (action == IDiamondCut.FacetCutAction.Add) {
                              addFunctions(
                                  _diamondCut[facetIndex].facetAddress,
                                  _diamondCut[facetIndex].functionSelectors
                              );
                          } else if (action == IDiamondCut.FacetCutAction.Replace) {
                              replaceFunctions(
                                  _diamondCut[facetIndex].facetAddress,
                                  _diamondCut[facetIndex].functionSelectors
                              );
                          } else if (action == IDiamondCut.FacetCutAction.Remove) {
                              removeFunctions(
                                  _diamondCut[facetIndex].facetAddress,
                                  _diamondCut[facetIndex].functionSelectors
                              );
                          } else {
                              revert("LibDiamondCut: Incorrect FacetCutAction");
                          }
                      }
                      emit DiamondCut(_diamondCut, _init, _calldata);
                      initializeDiamondCut(_init, _calldata);
                  }
                  function addFunctions(
                      address _facetAddress,
                      bytes4[] memory _functionSelectors
                  ) internal {
                      require(
                          _functionSelectors.length > 0,
                          "LibDiamondCut: No selectors in facet to cut"
                      );
                      DiamondStorage storage ds = diamondStorage();
                      // uint16 selectorCount = uint16(diamondStorage().selectors.length);
                      require(
                          _facetAddress != address(0),
                          "LibDiamondCut: Add facet can't be address(0)"
                      );
                      uint16 selectorPosition =
                          uint16(
                              ds.facetFunctionSelectors[_facetAddress]
                                  .functionSelectors
                                  .length
                          );
                      // add new facet address if it does not exist
                      if (selectorPosition == 0) {
                          enforceHasContractCode(
                              _facetAddress,
                              "LibDiamondCut: New facet has no code"
                          );
                          ds.facetFunctionSelectors[_facetAddress]
                              .facetAddressPosition = uint16(ds.facetAddresses.length);
                          ds.facetAddresses.push(_facetAddress);
                      }
                      for (
                          uint256 selectorIndex;
                          selectorIndex < _functionSelectors.length;
                          selectorIndex++
                      ) {
                          bytes4 selector = _functionSelectors[selectorIndex];
                          address oldFacetAddress =
                              ds.selectorToFacetAndPosition[selector].facetAddress;
                          require(
                              oldFacetAddress == address(0),
                              "LibDiamondCut: Can't add function that already exists"
                          );
                          ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(
                              selector
                          );
                          ds.selectorToFacetAndPosition[selector]
                              .facetAddress = _facetAddress;
                          ds.selectorToFacetAndPosition[selector]
                              .functionSelectorPosition = selectorPosition;
                          selectorPosition++;
                      }
                  }
                  function replaceFunctions(
                      address _facetAddress,
                      bytes4[] memory _functionSelectors
                  ) internal {
                      require(
                          _functionSelectors.length > 0,
                          "LibDiamondCut: No selectors in facet to cut"
                      );
                      DiamondStorage storage ds = diamondStorage();
                      require(
                          _facetAddress != address(0),
                          "LibDiamondCut: Add facet can't be address(0)"
                      );
                      uint16 selectorPosition =
                          uint16(
                              ds.facetFunctionSelectors[_facetAddress]
                                  .functionSelectors
                                  .length
                          );
                      // add new facet address if it does not exist
                      if (selectorPosition == 0) {
                          enforceHasContractCode(
                              _facetAddress,
                              "LibDiamondCut: New facet has no code"
                          );
                          ds.facetFunctionSelectors[_facetAddress]
                              .facetAddressPosition = uint16(ds.facetAddresses.length);
                          ds.facetAddresses.push(_facetAddress);
                      }
                      for (
                          uint256 selectorIndex;
                          selectorIndex < _functionSelectors.length;
                          selectorIndex++
                      ) {
                          bytes4 selector = _functionSelectors[selectorIndex];
                          address oldFacetAddress =
                              ds.selectorToFacetAndPosition[selector].facetAddress;
                          require(
                              oldFacetAddress != _facetAddress,
                              "LibDiamondCut: Can't replace function with same function"
                          );
                          removeFunction(oldFacetAddress, selector);
                          // add function
                          ds.selectorToFacetAndPosition[selector]
                              .functionSelectorPosition = selectorPosition;
                          ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(
                              selector
                          );
                          ds.selectorToFacetAndPosition[selector]
                              .facetAddress = _facetAddress;
                          selectorPosition++;
                      }
                  }
                  function removeFunctions(
                      address _facetAddress,
                      bytes4[] memory _functionSelectors
                  ) internal {
                      require(
                          _functionSelectors.length > 0,
                          "LibDiamondCut: No selectors in facet to cut"
                      );
                      DiamondStorage storage ds = diamondStorage();
                      // if function does not exist then do nothing and return
                      require(
                          _facetAddress == address(0),
                          "LibDiamondCut: Remove facet address must be address(0)"
                      );
                      for (
                          uint256 selectorIndex;
                          selectorIndex < _functionSelectors.length;
                          selectorIndex++
                      ) {
                          bytes4 selector = _functionSelectors[selectorIndex];
                          address oldFacetAddress =
                              ds.selectorToFacetAndPosition[selector].facetAddress;
                          removeFunction(oldFacetAddress, selector);
                      }
                  }
                  function removeFunction(address _facetAddress, bytes4 _selector) internal {
                      DiamondStorage storage ds = diamondStorage();
                      require(
                          _facetAddress != address(0),
                          "LibDiamondCut: Can't remove function that doesn't exist"
                      );
                      // an immutable function is a function defined directly in a diamond
                      require(
                          _facetAddress != address(this),
                          "LibDiamondCut: Can't remove immutable function"
                      );
                      // replace selector with last selector, then delete last selector
                      uint256 selectorPosition =
                          ds.selectorToFacetAndPosition[_selector].functionSelectorPosition;
                      uint256 lastSelectorPosition =
                          ds.facetFunctionSelectors[_facetAddress].functionSelectors.length -
                              1;
                      // if not the same then replace _selector with lastSelector
                      if (selectorPosition != lastSelectorPosition) {
                          bytes4 lastSelector =
                              ds.facetFunctionSelectors[_facetAddress].functionSelectors[
                                  lastSelectorPosition
                              ];
                          ds.facetFunctionSelectors[_facetAddress].functionSelectors[
                              selectorPosition
                          ] = lastSelector;
                          ds.selectorToFacetAndPosition[lastSelector]
                              .functionSelectorPosition = uint16(selectorPosition);
                      }
                      // delete the last selector
                      ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
                      delete ds.selectorToFacetAndPosition[_selector];
                      // if no more selectors for facet address then delete the facet address
                      if (lastSelectorPosition == 0) {
                          // replace facet address with last facet address and delete last facet address
                          uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
                          uint256 facetAddressPosition =
                              ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
                          if (facetAddressPosition != lastFacetAddressPosition) {
                              address lastFacetAddress =
                                  ds.facetAddresses[lastFacetAddressPosition];
                              ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                              ds.facetFunctionSelectors[lastFacetAddress]
                                  .facetAddressPosition = uint16(facetAddressPosition);
                          }
                          ds.facetAddresses.pop();
                          delete ds.facetFunctionSelectors[_facetAddress]
                              .facetAddressPosition;
                      }
                  }
                  function initializeDiamondCut(address _init, bytes memory _calldata)
                      internal
                  {
                      if (_init == address(0)) {
                          require(
                              _calldata.length == 0,
                              "LibDiamondCut: _init is address(0) but_calldata is not empty"
                          );
                      } else {
                          require(
                              _calldata.length > 0,
                              "LibDiamondCut: _calldata is empty but _init is not address(0)"
                          );
                          if (_init != address(this)) {
                              enforceHasContractCode(
                                  _init,
                                  "LibDiamondCut: _init address has no code"
                              );
                          }
                          (bool success, bytes memory error) = _init.delegatecall(_calldata);
                          if (!success) {
                              if (error.length > 0) {
                                  // bubble up the error
                                  GelatoBytes.revertWithError(error, "LibDiamondCut:_init:");
                              } else {
                                  revert("LibDiamondCut: _init function reverted");
                              }
                          }
                      }
                  }
                  function enforceHasContractCode(
                      address _contract,
                      string memory _errorMessage
                  ) internal view {
                      uint256 contractSize;
                      assembly {
                          contractSize := extcodesize(_contract)
                      }
                      require(contractSize > 0, _errorMessage);
                  }
              }
              // "SPDX-License-Identifier: UNLICENSED"
              pragma solidity 0.8.0;
              library GelatoBytes {
                  function calldataSliceSelector(bytes calldata _bytes)
                      internal
                      pure
                      returns (bytes4 selector)
                  {
                      selector =
                          _bytes[0] |
                          (bytes4(_bytes[1]) >> 8) |
                          (bytes4(_bytes[2]) >> 16) |
                          (bytes4(_bytes[3]) >> 24);
                  }
                  function memorySliceSelector(bytes memory _bytes)
                      internal
                      pure
                      returns (bytes4 selector)
                  {
                      selector =
                          _bytes[0] |
                          (bytes4(_bytes[1]) >> 8) |
                          (bytes4(_bytes[2]) >> 16) |
                          (bytes4(_bytes[3]) >> 24);
                  }
                  function revertWithError(bytes memory _bytes, string memory _tracingInfo)
                      internal
                      pure
                  {
                      // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err
                      if (_bytes.length % 32 == 4) {
                          bytes4 selector;
                          assembly {
                              selector := mload(add(0x20, _bytes))
                          }
                          if (selector == 0x08c379a0) {
                              // Function selector for Error(string)
                              assembly {
                                  _bytes := add(_bytes, 68)
                              }
                              revert(string(abi.encodePacked(_tracingInfo, string(_bytes))));
                          } else {
                              revert(
                                  string(abi.encodePacked(_tracingInfo, "NoErrorSelector"))
                              );
                          }
                      } else {
                          revert(
                              string(abi.encodePacked(_tracingInfo, "UnexpectedReturndata"))
                          );
                      }
                  }
                  function returnError(bytes memory _bytes, string memory _tracingInfo)
                      internal
                      pure
                      returns (string memory)
                  {
                      // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err
                      if (_bytes.length % 32 == 4) {
                          bytes4 selector;
                          assembly {
                              selector := mload(add(0x20, _bytes))
                          }
                          if (selector == 0x08c379a0) {
                              // Function selector for Error(string)
                              assembly {
                                  _bytes := add(_bytes, 68)
                              }
                              return string(abi.encodePacked(_tracingInfo, string(_bytes)));
                          } else {
                              return
                                  string(abi.encodePacked(_tracingInfo, "NoErrorSelector"));
                          }
                      } else {
                          return
                              string(abi.encodePacked(_tracingInfo, "UnexpectedReturndata"));
                      }
                  }
              }
              

              File 2 of 6: ERC1967Proxy
              // 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 {
                  }
              }
              
              
              /**
               * @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._
               *
               */
              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;
                  }
              }
              
              /**
               * @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);
              }
              
              /**
               * @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);
                          }
                      }
                  }
              }
              
              /**
               * @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
                      }
                  }
              }
              
              /*
               * @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;
                  }
              }
              
              /**
               * @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;
                  }
              }
              
              /**
               * @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);
                  }
              }
              
              
              /**
               * @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;
              }
              
              
              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 {}
              }
              
              
              /**
               * @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();
                  }
              }
              
              /**
               * @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();
                  }
              }
              
              
              // 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) {}
              }

              File 3 of 6: EIP173Proxy
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.7.0;
              import "./Proxy.sol";
              interface ERC165 {
                  function supportsInterface(bytes4 id) external view returns (bool);
              }
              ///@notice Proxy implementing EIP173 for ownership management
              contract EIP173Proxy is Proxy {
                  // ////////////////////////// EVENTS ///////////////////////////////////////////////////////////////////////
                  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                  // /////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////
                  constructor(
                      address implementationAddress,
                      address ownerAddress,
                      bytes memory data
                  ) payable {
                      _setImplementation(implementationAddress, data);
                      _setOwner(ownerAddress);
                  }
                  // ///////////////////// EXTERNAL ///////////////////////////////////////////////////////////////////////////
                  function owner() external view returns (address) {
                      return _owner();
                  }
                  function supportsInterface(bytes4 id) external view returns (bool) {
                      if (id == 0x01ffc9a7 || id == 0x7f5828d0) {
                          return true;
                      }
                      if (id == 0xFFFFFFFF) {
                          return false;
                      }
                      ERC165 implementation;
                      // solhint-disable-next-line security/no-inline-assembly
                      assembly {
                          implementation := sload(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)
                      }
                      // Technically this is not standard compliant as ERC-165 require 30,000 gas which that call cannot ensure
                      // because it is itself inside `supportsInterface` that might only get 30,000 gas.
                      // In practise this is unlikely to be an issue.
                      try implementation.supportsInterface(id) returns (bool support) {
                          return support;
                      } catch {
                          return false;
                      }
                  }
                  function transferOwnership(address newOwner) external onlyOwner {
                      _setOwner(newOwner);
                  }
                  function upgradeTo(address newImplementation) external onlyOwner {
                      _setImplementation(newImplementation, "");
                  }
                  function upgradeToAndCall(address newImplementation, bytes calldata data) external payable onlyOwner {
                      _setImplementation(newImplementation, data);
                  }
                  // /////////////////////// MODIFIERS ////////////////////////////////////////////////////////////////////////
                  modifier onlyOwner() {
                      require(msg.sender == _owner(), "NOT_AUTHORIZED");
                      _;
                  }
                  // ///////////////////////// INTERNAL //////////////////////////////////////////////////////////////////////
                  function _owner() internal view returns (address adminAddress) {
                      // solhint-disable-next-line security/no-inline-assembly
                      assembly {
                          adminAddress := sload(0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103)
                      }
                  }
                  function _setOwner(address newOwner) internal {
                      address previousOwner = _owner();
                      // solhint-disable-next-line security/no-inline-assembly
                      assembly {
                          sstore(0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103, newOwner)
                      }
                      emit OwnershipTransferred(previousOwner, newOwner);
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.7.0;
              // EIP-1967
              abstract contract Proxy {
                  // /////////////////////// EVENTS ///////////////////////////////////////////////////////////////////////////
                  event ProxyImplementationUpdated(address indexed previousImplementation, address indexed newImplementation);
                  // ///////////////////// EXTERNAL ///////////////////////////////////////////////////////////////////////////
                  receive() external payable virtual {
                      revert("ETHER_REJECTED"); // explicit reject by default
                  }
                  fallback() external payable {
                      _fallback();
                  }
                  // ///////////////////////// INTERNAL //////////////////////////////////////////////////////////////////////
                  function _fallback() internal {
                      // solhint-disable-next-line security/no-inline-assembly
                      assembly {
                          let implementationAddress := sload(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)
                          calldatacopy(0x0, 0x0, calldatasize())
                          let success := delegatecall(gas(), implementationAddress, 0x0, calldatasize(), 0, 0)
                          let retSz := returndatasize()
                          returndatacopy(0, 0, retSz)
                          switch success
                              case 0 {
                                  revert(0, retSz)
                              }
                              default {
                                  return(0, retSz)
                              }
                      }
                  }
                  function _setImplementation(address newImplementation, bytes memory data) internal {
                      address previousImplementation;
                      // solhint-disable-next-line security/no-inline-assembly
                      assembly {
                          previousImplementation := sload(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)
                      }
                      // solhint-disable-next-line security/no-inline-assembly
                      assembly {
                          sstore(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc, newImplementation)
                      }
                      emit ProxyImplementationUpdated(previousImplementation, newImplementation);
                      if (data.length > 0) {
                          (bool success, ) = newImplementation.delegatecall(data);
                          if (!success) {
                              assembly {
                                  // This assembly ensure the revert contains the exact string data
                                  let returnDataSize := returndatasize()
                                  returndatacopy(0, 0, returnDataSize)
                                  revert(0, returnDataSize)
                              }
                          }
                      }
                  }
              }
              

              File 4 of 6: Automate
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v4.5.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 `to`.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transfer(address to, 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 `from` to `to` 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 from,
                      address to,
                      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.1 (token/ERC20/utils/SafeERC20.sol)
              pragma solidity ^0.8.0;
              import "../IERC20.sol";
              import "../../../utils/Address.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 SafeERC20 {
                  using Address for address;
                  function safeTransfer(
                      IERC20 token,
                      address to,
                      uint256 value
                  ) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                  }
                  function safeTransferFrom(
                      IERC20 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(
                      IERC20 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(
                      IERC20 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(
                      IERC20 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(IERC20 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 (last updated v4.5.0) (utils/Address.sol)
              pragma solidity ^0.8.1;
              /**
               * @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
                   * ====
                   *
                   * [IMPORTANT]
                   * ====
                   * You shouldn't rely on `isContract` to protect against flash loan attacks!
                   *
                   * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                   * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                   * constructor.
                   * ====
                   */
                  function isContract(address account) internal view returns (bool) {
                      // This method relies on extcodesize/address.code.length, which returns 0
                      // for contracts in construction, since the code is only stored at the end
                      // of the constructor execution.
                      return account.code.length > 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.1 (utils/structs/EnumerableSet.sol)
              pragma solidity ^0.8.0;
              /**
               * @dev Library for managing
               * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
               * types.
               *
               * Sets have the following properties:
               *
               * - Elements are added, removed, and checked for existence in constant time
               * (O(1)).
               * - Elements are enumerated in O(n). No guarantees are made on the ordering.
               *
               * ```
               * contract Example {
               *     // Add the library methods
               *     using EnumerableSet for EnumerableSet.AddressSet;
               *
               *     // Declare a set state variable
               *     EnumerableSet.AddressSet private mySet;
               * }
               * ```
               *
               * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
               * and `uint256` (`UintSet`) are supported.
               */
              library EnumerableSet {
                  // To implement this library for multiple types with as little code
                  // repetition as possible, we write it in terms of a generic Set type with
                  // bytes32 values.
                  // The Set implementation uses private functions, and user-facing
                  // implementations (such as AddressSet) are just wrappers around the
                  // underlying Set.
                  // This means that we can only create new EnumerableSets for types that fit
                  // in bytes32.
                  struct Set {
                      // Storage of set values
                      bytes32[] _values;
                      // Position of the value in the `values` array, plus 1 because index 0
                      // means a value is not in the set.
                      mapping(bytes32 => uint256) _indexes;
                  }
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function _add(Set storage set, bytes32 value) private returns (bool) {
                      if (!_contains(set, value)) {
                          set._values.push(value);
                          // The value is stored at length-1, but we add 1 to all indexes
                          // and use 0 as a sentinel value
                          set._indexes[value] = set._values.length;
                          return true;
                      } else {
                          return false;
                      }
                  }
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function _remove(Set storage set, bytes32 value) private returns (bool) {
                      // We read and store the value's index to prevent multiple reads from the same storage slot
                      uint256 valueIndex = set._indexes[value];
                      if (valueIndex != 0) {
                          // Equivalent to contains(set, value)
                          // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                          // the array, and then remove the last element (sometimes called as 'swap and pop').
                          // This modifies the order of the array, as noted in {at}.
                          uint256 toDeleteIndex = valueIndex - 1;
                          uint256 lastIndex = set._values.length - 1;
                          if (lastIndex != toDeleteIndex) {
                              bytes32 lastvalue = set._values[lastIndex];
                              // Move the last value to the index where the value to delete is
                              set._values[toDeleteIndex] = lastvalue;
                              // Update the index for the moved value
                              set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
                          }
                          // Delete the slot where the moved value was stored
                          set._values.pop();
                          // Delete the index for the deleted slot
                          delete set._indexes[value];
                          return true;
                      } else {
                          return false;
                      }
                  }
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function _contains(Set storage set, bytes32 value) private view returns (bool) {
                      return set._indexes[value] != 0;
                  }
                  /**
                   * @dev Returns the number of values on the set. O(1).
                   */
                  function _length(Set storage set) private view returns (uint256) {
                      return set._values.length;
                  }
                  /**
                   * @dev Returns the value stored at position `index` in the set. O(1).
                   *
                   * Note that there are no guarantees on the ordering of values inside the
                   * array, and it may change when more values are added or removed.
                   *
                   * Requirements:
                   *
                   * - `index` must be strictly less than {length}.
                   */
                  function _at(Set storage set, uint256 index) private view returns (bytes32) {
                      return set._values[index];
                  }
                  /**
                   * @dev Return the entire set in an array
                   *
                   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                   * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                   */
                  function _values(Set storage set) private view returns (bytes32[] memory) {
                      return set._values;
                  }
                  // Bytes32Set
                  struct Bytes32Set {
                      Set _inner;
                  }
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                      return _add(set._inner, value);
                  }
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                      return _remove(set._inner, value);
                  }
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
                      return _contains(set._inner, value);
                  }
                  /**
                   * @dev Returns the number of values in the set. O(1).
                   */
                  function length(Bytes32Set storage set) internal view returns (uint256) {
                      return _length(set._inner);
                  }
                  /**
                   * @dev Returns the value stored at position `index` in the set. O(1).
                   *
                   * Note that there are no guarantees on the ordering of values inside the
                   * array, and it may change when more values are added or removed.
                   *
                   * Requirements:
                   *
                   * - `index` must be strictly less than {length}.
                   */
                  function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
                      return _at(set._inner, index);
                  }
                  /**
                   * @dev Return the entire set in an array
                   *
                   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                   * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                   */
                  function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
                      return _values(set._inner);
                  }
                  // AddressSet
                  struct AddressSet {
                      Set _inner;
                  }
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(AddressSet storage set, address value) internal returns (bool) {
                      return _add(set._inner, bytes32(uint256(uint160(value))));
                  }
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(AddressSet storage set, address value) internal returns (bool) {
                      return _remove(set._inner, bytes32(uint256(uint160(value))));
                  }
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(AddressSet storage set, address value) internal view returns (bool) {
                      return _contains(set._inner, bytes32(uint256(uint160(value))));
                  }
                  /**
                   * @dev Returns the number of values in the set. O(1).
                   */
                  function length(AddressSet storage set) internal view returns (uint256) {
                      return _length(set._inner);
                  }
                  /**
                   * @dev Returns the value stored at position `index` in the set. O(1).
                   *
                   * Note that there are no guarantees on the ordering of values inside the
                   * array, and it may change when more values are added or removed.
                   *
                   * Requirements:
                   *
                   * - `index` must be strictly less than {length}.
                   */
                  function at(AddressSet storage set, uint256 index) internal view returns (address) {
                      return address(uint160(uint256(_at(set._inner, index))));
                  }
                  /**
                   * @dev Return the entire set in an array
                   *
                   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                   * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                   */
                  function values(AddressSet storage set) internal view returns (address[] memory) {
                      bytes32[] memory store = _values(set._inner);
                      address[] memory result;
                      assembly {
                          result := store
                      }
                      return result;
                  }
                  // UintSet
                  struct UintSet {
                      Set _inner;
                  }
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(UintSet storage set, uint256 value) internal returns (bool) {
                      return _add(set._inner, bytes32(value));
                  }
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(UintSet storage set, uint256 value) internal returns (bool) {
                      return _remove(set._inner, bytes32(value));
                  }
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(UintSet storage set, uint256 value) internal view returns (bool) {
                      return _contains(set._inner, bytes32(value));
                  }
                  /**
                   * @dev Returns the number of values on the set. O(1).
                   */
                  function length(UintSet storage set) internal view returns (uint256) {
                      return _length(set._inner);
                  }
                  /**
                   * @dev Returns the value stored at position `index` in the set. O(1).
                   *
                   * Note that there are no guarantees on the ordering of values inside the
                   * array, and it may change when more values are added or removed.
                   *
                   * Requirements:
                   *
                   * - `index` must be strictly less than {length}.
                   */
                  function at(UintSet storage set, uint256 index) internal view returns (uint256) {
                      return uint256(_at(set._inner, index));
                  }
                  /**
                   * @dev Return the entire set in an array
                   *
                   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                   * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                   */
                  function values(UintSet storage set) internal view returns (uint256[] memory) {
                      bytes32[] memory store = _values(set._inner);
                      uint256[] memory result;
                      assembly {
                          result := store
                      }
                      return result;
                  }
              }
              // SPDX-License-Identifier: UNLICENSED
              pragma solidity ^0.8.14;
              import {
                  EnumerableSet
              } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
              import {Gelatofied} from "./vendor/gelato/Gelatofied.sol";
              import {GelatoBytes} from "./vendor/gelato/GelatoBytes.sol";
              import {Proxied} from "./vendor/proxy/EIP173/Proxied.sol";
              import {AutomateStorage} from "./AutomateStorage.sol";
              import {LibDataTypes} from "./libraries/LibDataTypes.sol";
              import {LibEvents} from "./libraries/LibEvents.sol";
              import {LibTaskId} from "./libraries/LibTaskId.sol";
              import {LibTaskModule} from "./libraries/LibTaskModule.sol";
              import {LibBypassModule} from "./libraries/LibBypassModule.sol";
              import {IAutomate} from "./interfaces/IAutomate.sol";
              /**
               * @notice Automate enables everyone to have Gelato monitor and execute transactions.
               * @notice ExecAddress refers to the contract that has the function which Gelato will call.
               * @notice Modules allow users to customise conditions and specifications when creating a task.
               */
              //solhint-disable function-max-lines
              //solhint-disable no-empty-blocks
              contract Automate is Gelatofied, Proxied, AutomateStorage, IAutomate {
                  using GelatoBytes for bytes;
                  using EnumerableSet for EnumerableSet.Bytes32Set;
                  // solhint-disable const-name-snakecase
                  string public constant version = "7";
                  constructor(address payable _gelato) Gelatofied(_gelato) {}
                  ///@inheritdoc IAutomate
                  function createTask(
                      address _execAddress,
                      bytes calldata _execDataOrSelector,
                      LibDataTypes.ModuleData calldata _moduleData,
                      address _feeToken
                  ) external override returns (bytes32 taskId) {
                      address taskCreator;
                      (taskCreator, _execAddress) = LibTaskModule.preCreateTask(
                          msg.sender,
                          _execAddress,
                          taskModuleAddresses
                      );
                      taskId = _createTask(
                          taskCreator,
                          _execAddress,
                          _execDataOrSelector,
                          _moduleData,
                          _feeToken
                      );
                  }
                  ///@inheritdoc IAutomate
                  function cancelTask(bytes32 _taskId) external {
                      address _taskCreator = LibTaskModule.preCancelTask(
                          _taskId,
                          msg.sender,
                          taskModuleAddresses
                      );
                      _cancelTask(_taskCreator, _taskId);
                  }
                  ///@inheritdoc IAutomate
                  function exec(
                      address _taskCreator,
                      address _execAddress,
                      bytes memory _execData,
                      LibDataTypes.ModuleData calldata _moduleData,
                      uint256 _txFee,
                      address _feeToken,
                      bool _revertOnFailure
                  ) external onlyGelato {
                      bytes32 taskId = LibTaskId.getTaskId(
                          _taskCreator,
                          _execAddress,
                          _execData.memorySliceSelector(),
                          _moduleData,
                          _feeToken
                      );
                      require(
                          _createdTasks[_taskCreator].contains(taskId),
                          "Automate.exec: Task not found"
                      );
                      fee = _txFee;
                      feeToken = _feeToken;
                      bool success = LibTaskModule.onExecTask(
                          taskId,
                          _taskCreator,
                          _execAddress,
                          _execData,
                          _moduleData.modules,
                          _revertOnFailure,
                          taskModuleAddresses
                      );
                      delete fee;
                      delete feeToken;
                      emit LibEvents.ExecSuccess(
                          _txFee,
                          _feeToken,
                          _execAddress,
                          _execData,
                          taskId,
                          success
                      );
                  }
                  ///@inheritdoc IAutomate
                  function exec1Balance(
                      address _taskCreator,
                      address _execAddress,
                      bytes memory _execData,
                      LibDataTypes.ModuleData calldata _moduleData,
                      Gelato1BalanceParam calldata _oneBalanceParam,
                      bool _revertOnFailure
                  ) external onlyGelato {
                      bytes32 taskId = LibTaskId.getTaskId(
                          _taskCreator,
                          _execAddress,
                          _execData.memorySliceSelector(),
                          _moduleData,
                          address(0)
                      );
                      require(
                          _createdTasks[_taskCreator].contains(taskId),
                          "Automate.exec: Task not found"
                      );
                      bool success = LibTaskModule.onExecTask(
                          taskId,
                          _taskCreator,
                          _execAddress,
                          _execData,
                          _moduleData.modules,
                          _revertOnFailure,
                          taskModuleAddresses
                      );
                      emit LibEvents.ExecSuccess(
                          0,
                          address(0),
                          _execAddress,
                          _execData,
                          taskId,
                          success
                      );
                      emit LogUseGelato1Balance(
                          _oneBalanceParam.sponsor,
                          _execAddress,
                          _oneBalanceParam.feeToken,
                          _oneBalanceParam.oneBalanceChainId,
                          _oneBalanceParam.nativeToFeeTokenXRateNumerator,
                          _oneBalanceParam.nativeToFeeTokenXRateDenominator,
                          _oneBalanceParam.correlationId
                      );
                  }
                  function execBypassModuleSyncFee(
                      address _taskCreator,
                      address _execAddress,
                      bytes32 _taskId,
                      uint256 _txFee,
                      address _feeToken,
                      bytes memory _execData,
                      bool _revertOnFailure,
                      bool _singleExec
                  ) external onlyGelato {
                      require(
                          _createdTasks[_taskCreator].contains(_taskId),
                          "Automate.exec: Task not found"
                      );
                      fee = _txFee;
                      feeToken = _feeToken;
                      bool success = LibBypassModule.onExecTask(
                          _taskId,
                          _taskCreator,
                          _execAddress,
                          _execData,
                          _revertOnFailure,
                          _singleExec,
                          _createdTasks
                      );
                      delete fee;
                      delete feeToken;
                      emit LibEvents.ExecBypassModuleSyncFeeSuccess(
                          _taskId,
                          _txFee,
                          _feeToken,
                          success
                      );
                  }
                  ///@inheritdoc IAutomate
                  function execBypassModule(
                      address _taskCreator,
                      address _execAddress,
                      bytes32 _taskId,
                      bytes32 _correlationId,
                      bytes memory _execData,
                      bool _revertOnFailure,
                      bool _singleExec
                  ) external onlyGelato {
                      require(
                          _createdTasks[_taskCreator].contains(_taskId),
                          "Automate.exec: Task not found"
                      );
                      bool success = LibBypassModule.onExecTask(
                          _taskId,
                          _taskCreator,
                          _execAddress,
                          _execData,
                          _revertOnFailure,
                          _singleExec,
                          _createdTasks
                      );
                      emit LibEvents.ExecBypassModuleSuccess(
                          _taskId,
                          _correlationId,
                          success
                      );
                  }
                  ///@inheritdoc IAutomate
                  function setModule(
                      LibDataTypes.Module[] calldata _modules,
                      address[] calldata _moduleAddresses
                  ) external onlyProxyAdmin {
                      uint256 length = _modules.length;
                      for (uint256 i; i < length; i++) {
                          taskModuleAddresses[_modules[i]] = _moduleAddresses[i];
                      }
                  }
                  ///@inheritdoc IAutomate
                  function getFeeDetails() external view returns (uint256, address) {
                      return (fee, feeToken);
                  }
                  ///@inheritdoc IAutomate
                  function getTaskIdsByUser(address _taskCreator)
                      external
                      view
                      returns (bytes32[] memory)
                  {
                      bytes32[] memory taskIds = _createdTasks[_taskCreator].values();
                      return taskIds;
                  }
                  ///@inheritdoc IAutomate
                  function getTaskId(
                      address taskCreator,
                      address execAddress,
                      bytes4 execSelector,
                      LibDataTypes.ModuleData memory moduleData,
                      address feeToken
                  ) external pure returns (bytes32 taskId) {
                      taskId = LibTaskId.getTaskId(
                          taskCreator,
                          execAddress,
                          execSelector,
                          moduleData,
                          feeToken
                      );
                  }
                  function _createTask(
                      address _taskCreator,
                      address _execAddress,
                      bytes memory _execDataOrSelector,
                      LibDataTypes.ModuleData memory _moduleData,
                      address _feeToken
                  ) private returns (bytes32 taskId) {
                      taskId = LibTaskId.getTaskId(
                          _taskCreator,
                          _execAddress,
                          _execDataOrSelector.memorySliceSelector(),
                          _moduleData,
                          _feeToken
                      );
                      require(
                          !_createdTasks[_taskCreator].contains(taskId),
                          "Automate.createTask: Duplicate task"
                      );
                      LibTaskModule.onCreateTask(
                          taskId,
                          _taskCreator,
                          _execAddress,
                          _execDataOrSelector,
                          _moduleData,
                          taskModuleAddresses
                      );
                      _createdTasks[_taskCreator].add(taskId);
                      emit LibEvents.TaskCreated(
                          _taskCreator,
                          _execAddress,
                          _execDataOrSelector,
                          _moduleData,
                          _feeToken,
                          taskId
                      );
                  }
                  function _cancelTask(address _taskCreator, bytes32 _taskId) private {
                      require(
                          _createdTasks[_taskCreator].contains(_taskId),
                          "Automate.cancelTask: Task not found"
                      );
                      _createdTasks[_taskCreator].remove(_taskId);
                      emit LibEvents.TaskCancelled(_taskId, _taskCreator);
                  }
              }
              // SPDX-License-Identifier: UNLICENSED
              pragma solidity ^0.8.12;
              import {
                  EnumerableSet
              } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
              import {LibDataTypes} from "./libraries/LibDataTypes.sol";
              /**
               * @notice Storage layout of Automate smart contract.
               */
              // solhint-disable max-states-count
              abstract contract AutomateStorage {
                  mapping(bytes32 => address) public taskCreator; ///@dev Deprecated
                  mapping(bytes32 => address) public execAddresses; ///@dev Deprecated
                  mapping(address => EnumerableSet.Bytes32Set) internal _createdTasks;
                  uint256 public fee;
                  address public feeToken;
                  ///@dev Appended State
                  mapping(bytes32 => LibDataTypes.Time) public timedTask; ///@dev Deprecated
                  mapping(LibDataTypes.Module => address) public taskModuleAddresses;
                  mapping(bytes32 => uint256) public nonce1Balance; ///@dev Deprecated
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.12;
              import {GelatoBytes} from "../vendor/gelato/GelatoBytes.sol";
              // solhint-disable private-vars-leading-underscore
              // solhint-disable func-visibility
              function _call(
                  address _add,
                  bytes memory _data,
                  uint256 _value,
                  bool _revertOnFailure,
                  string memory _tracingInfo
              ) returns (bool success, bytes memory returnData) {
                  (success, returnData) = _add.call{value: _value}(_data);
                  if (!success && _revertOnFailure)
                      GelatoBytes.revertWithError(returnData, _tracingInfo);
              }
              function _delegateCall(
                  address _add,
                  bytes memory _data,
                  string memory _tracingInfo
              ) returns (bool success, bytes memory returnData) {
                  (success, returnData) = _add.delegatecall(_data);
                  if (!success) GelatoBytes.revertWithError(returnData, _tracingInfo);
              }
              // SPDX-License-Identifier: UNLICENSED
              pragma solidity ^0.8.12;
              import {
                  SafeERC20,
                  IERC20
              } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
              address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
              // solhint-disable private-vars-leading-underscore
              // solhint-disable func-visibility
              function _transfer(
                  address payable _to,
                  address _paymentToken,
                  uint256 _amount
              ) {
                  if (_paymentToken == ETH) {
                      (bool success, ) = _to.call{value: _amount}("");
                      require(success, "_transfer: ETH transfer failed");
                  } else {
                      SafeERC20.safeTransfer(IERC20(_paymentToken), _to, _amount);
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              import {LibDataTypes} from "../libraries/LibDataTypes.sol";
              import {IGelato1Balance} from "./IGelato1Balance.sol";
              // solhint-disable max-line-length
              interface IAutomate is IGelato1Balance {
                  /**
                   * @notice Initiates a task with conditions which Gelato will monitor and execute when conditions are met.
                   *
                   * @param execAddress Address of contract that should be called by Gelato.
                   * @param execData Execution data to be called with / function selector if execution data is yet to be determined.
                   * @param moduleData Conditional modules that will be used. {See LibDataTypes-ModuleData}
                   * @param feeToken Address of token to be used as payment. Use address(0) if Gelato 1Balance is being used, 0xeeeeee... for ETH or native tokens.
                   *
                   * @return taskId Unique hash of the task created.
                   */
                  function createTask(
                      address execAddress,
                      bytes calldata execData,
                      LibDataTypes.ModuleData calldata moduleData,
                      address feeToken
                  ) external returns (bytes32 taskId);
                  /**
                   * @notice Terminates a task that was created and Gelato can no longer execute it.
                   *
                   * @param taskId Unique hash of the task that is being cancelled. {See LibTaskId-getTaskId}
                   */
                  function cancelTask(bytes32 taskId) external;
                  /**
                   * @notice Execution API called by Gelato, using Sync Fee as fee payment method
                   *
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that should be called by Gelato.
                   * @param execData Execution data to be called with / function selector if execution data is yet to be determined.
                   * @param moduleData Conditional modules that will be used. {See LibDataTypes-ModuleData}
                   * @param txFee Fee paid to Gelato for execution, transfered to Gelato.feeCollector().
                   * @param feeToken Token used to pay for the execution. ETH = 0xeeeeee...
                   * @param revertOnFailure To revert or not if call to execAddress fails. (Used for off-chain simulations)
                   */
                  function exec(
                      address taskCreator,
                      address execAddress,
                      bytes memory execData,
                      LibDataTypes.ModuleData calldata moduleData,
                      uint256 txFee,
                      address feeToken,
                      bool revertOnFailure
                  ) external;
                  /**
                   * @notice Execution API called by Gelato, using Gelato 1Balance as fee payment method.
                   *
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that should be called by Gelato.
                   * @param execData Execution data to be called with / function selector if execution data is yet to be determined.
                   * @param moduleData Conditional modules that will be used. {See LibDataTypes-ModuleData}
                   * @param oneBalanceParam Parameters required for fee payment with Gelato 1Balance.
                   * @param revertOnFailure To revert or not if call to execAddress fails. (Used for off-chain simulations)
                   */
                  function exec1Balance(
                      address taskCreator,
                      address execAddress,
                      bytes memory execData,
                      LibDataTypes.ModuleData calldata moduleData,
                      Gelato1BalanceParam calldata oneBalanceParam,
                      bool revertOnFailure
                  ) external;
                  /**
                   * @notice Execution API called by Gelato, using Gelato 1Balance as fee payment method.
                   *
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that should be called by Gelato.
                   * @param taskId Unique hash of the task.
                   * @param correlationId Id of the execution to be used for 1Balance settlement.
                   * @param execData Execution data to be called with / function selector if execution data is yet to be determined.
                   * @param revertOnFailure To revert or not if call to execAddress fails. (Used for off-chain simulations)
                   * @param singleExec If the task is a SingleExec task. If true, task will be cancelled after execution.
                   */
                  function execBypassModule(
                      address taskCreator,
                      address execAddress,
                      bytes32 taskId,
                      bytes32 correlationId,
                      bytes memory execData,
                      bool revertOnFailure,
                      bool singleExec
                  ) external;
                  /**
                   * @notice Execution API called by Gelato, using Gelato Sync fee as fee payment method.
                   *
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that should be called by Gelato.
                   * @param taskId Unique hash of the task.
                   * @param txFee Fee paid to Gelato for execution, transfered to Gelato.feeCollector().
                   * @param feeToken Token used to pay for the execution. ETH = 0xeeeeee...
                   * @param execData Execution data to be called with / function selector if execution data is yet to be determined.
                   * @param revertOnFailure To revert or not if call to execAddress fails. (Used for off-chain simulations)
                   * @param singleExec If the task is a SingleExec task. If true, task will be cancelled after execution.
                   */
                  function execBypassModuleSyncFee(
                      address taskCreator,
                      address execAddress,
                      bytes32 taskId,
                      uint256 txFee,
                      address feeToken,
                      bytes memory execData,
                      bool revertOnFailure,
                      bool singleExec
                  ) external;
                  /**
                   * @notice Sets the address of task modules. Only callable by proxy admin.
                   *
                   * @param modules List of modules to be set
                   * @param moduleAddresses List of addresses for respective modules.
                   */
                  function setModule(
                      LibDataTypes.Module[] calldata modules,
                      address[] calldata moduleAddresses
                  ) external;
                  /**
                   * @notice Helper function to query fee and feeToken to be used for payment. (For executions which pays itself)
                   *
                   * @return uint256 Fee amount to be paid.
                   * @return address Token to be paid. (Determined and passed by taskCreator during createTask)
                   */
                  function getFeeDetails() external view returns (uint256, address);
                  /**
                   * @notice Helper func to query all open tasks by a task creator.
                   *
                   * @param taskCreator Address of task creator to query.
                   *
                   * @return bytes32[] List of taskIds created.
                   */
                  function getTaskIdsByUser(address taskCreator)
                      external
                      view
                      returns (bytes32[] memory);
                  /**
                   * @notice Helper function to compute task id with module arguments
                   *
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that will be called by Gelato.
                   * @param execSelector Signature of the function which will be called by Gelato.
                   * @param moduleData  Conditional modules that will be used. {See LibDataTypes-ModuleData}
                   * @param feeToken Address of token to be used as payment. Use address(0) if Gelato 1Balance is being used, 0xeeeeee... for ETH or native tokens.
                   */
                  function getTaskId(
                      address taskCreator,
                      address execAddress,
                      bytes4 execSelector,
                      LibDataTypes.ModuleData memory moduleData,
                      address feeToken
                  ) external pure returns (bytes32 taskId);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              interface IGelato1Balance {
                  struct Gelato1BalanceParam {
                      address sponsor;
                      address feeToken;
                      uint256 oneBalanceChainId;
                      uint256 nativeToFeeTokenXRateNumerator;
                      uint256 nativeToFeeTokenXRateDenominator;
                      bytes32 correlationId;
                  }
                  event LogUseGelato1Balance(
                      address indexed sponsor,
                      address indexed target,
                      address indexed feeToken,
                      uint256 oneBalanceChainId,
                      uint256 nativeToFeeTokenXRateNumerator,
                      uint256 nativeToFeeTokenXRateDenominator,
                      bytes32 correlationId
                  );
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.12;
              // solhint-disable max-line-length
              interface ITaskModule {
                  /**
                   * @notice Called before generating taskId.
                   * @dev Modules can override execAddress or taskCreator. {See ProxyModule-preCreateTask}
                   *
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that should be called.
                   *
                   * @return address Overriden or original taskCreator.
                   * @return address Overriden or original execAddress.
                   */
                  function preCreateTask(address taskCreator, address execAddress)
                      external
                      returns (address, address);
                  /**
                   * @notice Initiates task module whenever `createTask` is being called.
                   *
                   * @param taskId Unique hash of the task created.
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that should be called.
                   * @param execData Execution data to be called with / function selector if execution data is yet to be determined.
                   * @param initModuleArg Encoded arguments for module if any.
                   */
                  function onCreateTask(
                      bytes32 taskId,
                      address taskCreator,
                      address execAddress,
                      bytes calldata execData,
                      bytes calldata initModuleArg
                  ) external;
                  /**
                   * @notice Called before taskId is removed from _createdTasks[].
                   * @dev Modules can override taskCreator.
                   *
                   * @param taskId Unique hash of the task created.
                   * @param taskCreator The address which created the task.
                   *
                   * @return address Overriden or original taskCreator.
                   */
                  function preCancelTask(bytes32 taskId, address taskCreator)
                      external
                      returns (address);
                  /**
                   * @notice Called during `exec` and before execAddress is called.
                   *
                   * @param taskId Unique hash of the task created.
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that should be called.
                   * @param execData Execution data to be called with / function selector if execution data is yet to be determined.
                   *
                   * @return address Overriden or original execution address.
                   * @return bytes Overriden or original execution data.
                   */
                  function preExecCall(
                      bytes32 taskId,
                      address taskCreator,
                      address execAddress,
                      bytes calldata execData
                  ) external returns (address, bytes memory);
                  /**
                   * @notice Called during `exec` and after execAddress is called.
                   *
                   * @param taskId Unique hash of the task created.
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that should be called.
                   * @param execData Execution data to be called with / function selector if execution data is yet to be determined.
                   */
                  function postExecCall(
                      bytes32 taskId,
                      address taskCreator,
                      address execAddress,
                      bytes calldata execData
                  ) external;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.12;
              import {
                  EnumerableSet
              } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
              import {_call, _delegateCall} from "../functions/FExec.sol";
              import {LibDataTypes} from "./LibDataTypes.sol";
              import {LibEvents} from "./LibEvents.sol";
              import {LibTaskModule} from "./LibTaskModule.sol";
              import {LibTaskModuleConfig} from "./LibTaskModuleConfig.sol";
              import {ITaskModule} from "../interfaces/ITaskModule.sol";
              // solhint-disable function-max-lines
              /// @notice Simplified library for task executions
              library LibBypassModule {
                  using EnumerableSet for EnumerableSet.Bytes32Set;
                  using LibTaskModuleConfig for LibDataTypes.Module;
                  /**
                   * @notice Delegate calls SingleExecModule on exec for single exec tasks.
                   *
                   * @param _taskId Unique hash of the task. {See LibTaskId-getTaskId}
                   * @param _taskCreator Address which created the task.
                   * @param _execAddress Address of contract that will be called by Gelato.
                   * @param _execData Execution data to be called with / function selector.
                   * @param _revertOnFailure To revert or not if call to execAddress fails.
                   * @param _singleExec If task is a single exec task.
                   * @param _createdTasks The storage reference of owner to the taskIds created mapping.
                   */
                  function onExecTask(
                      bytes32 _taskId,
                      address _taskCreator,
                      address _execAddress,
                      bytes memory _execData,
                      bool _revertOnFailure,
                      bool _singleExec,
                      mapping(address => EnumerableSet.Bytes32Set) storage _createdTasks
                  ) internal returns (bool callSuccess) {
                      (callSuccess, ) = _call(
                          _execAddress,
                          abi.encodePacked(_execData, _taskCreator),
                          0,
                          _revertOnFailure,
                          "Automate.exec: "
                      );
                      if (_singleExec) {
                          _createdTasks[_taskCreator].remove(_taskId);
                          emit LibEvents.TaskCancelled(_taskId, _taskCreator);
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.12;
              // solhint-disable max-line-length
              library LibDataTypes {
                  /**
                   * @notice Whitelisted modules that are available for users to customise conditions and specifications of their tasks.
                   *
                   * @param RESOLVER Use dynamic condition & input data for execution. {See ResolverModule.sol}
                   * @param DEPRECATED_TIME deprecated
                   * @param PROXY Creates a dedicated caller (msg.sender) to be used when executing the task. {See ProxyModule.sol}
                   * @param SINGLE_EXEC Task is cancelled after one execution. {See SingleExecModule.sol}
                   * @param WEB3_FUNCTION Use off-chain condition & input data for execution. {See Web3FunctionModule.sol}
                   * @param TRIGGER Repeated execution of task ata a specified timing and interval or cron. {See TriggerModule.sol}
                   */
                  enum Module {
                      RESOLVER,
                      DEPRECATED_TIME, // @deprecated
                      PROXY,
                      SINGLE_EXEC,
                      WEB3_FUNCTION,
                      TRIGGER
                  }
                  /**
                   * @notice Struct to contain modules and their relative arguments that are used for task creation.
                   *
                   * @param modules List of selected modules.
                   * @param args Arguments of modules if any. Pass "0x" for modules which does not require args {See encodeModuleArg}
                   */
                  struct ModuleData {
                      Module[] modules;
                      bytes[] args;
                  }
                  /**
                   * @notice Struct for time module.
                   *
                   * @param nextExec Time when the next execution should occur.
                   * @param interval Time interval between each execution.
                   */
                  struct Time {
                      uint128 nextExec;
                      uint128 interval;
                  }
                  /**
                   * @notice Types of trigger
                   *
                   * @param TIME Time triggered tasks, starting at a specific time and triggered intervally
                   * @param CRON Cron triggered tasks, triggered according to the cron conditions
                   */
                  enum TriggerType {
                      TIME,
                      CRON,
                      EVENT,
                      BLOCK
                  }
                  /**
                   * @notice Struct for trigger module
                   *
                   * @param triggerType Type of the trigger
                   * @param triggerConfig Trigger configuration that shuold be parsed according to triggerType
                   */
                  struct TriggerModuleData {
                      TriggerType triggerType;
                      bytes triggerConfig;
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.12;
              import {LibDataTypes} from "./LibDataTypes.sol";
              library LibEvents {
                  /**
                   * @notice Emitted when `createTask` is called.
                   *
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that is called by Gelato.
                   * @param execDataOrSelector Execution data / function selector.
                   * @param moduleData Conditional modules used. {See LibDataTypes-ModuleData}
                   * @param feeToken Token used to pay for the execution. ETH = 0xeeeeee...
                   * @param taskId Unique hash of the task. {See LibTaskId-getTaskId}
                   */
                  event TaskCreated(
                      address indexed taskCreator,
                      address indexed execAddress,
                      bytes execDataOrSelector,
                      LibDataTypes.ModuleData moduleData,
                      address feeToken,
                      bytes32 indexed taskId
                  );
                  /**
                   * @notice Emitted when `cancelTask` is called.
                   *
                   * @param taskId Unique hash of the task. {See LibTaskId-getTaskId}
                   * @param taskCreator The address which owned the task.
                   */
                  event TaskCancelled(bytes32 taskId, address taskCreator);
                  /**
                   * @notice Emitted when `exec` is called.
                   *
                   * @param txFee Fee paid to Gelato for execution
                   * @param feeToken Token used to pay for the execution. ETH = 0xeeeeee...
                   * @param execAddress Address of contract that will be called by Gelato.
                   * @param execData Execution data / function selector.
                   * @param taskId Unique hash of the task. {See LibTaskId-getTaskId}
                   * @param callSuccess Status of the call to execAddress.
                   */
                  event ExecSuccess(
                      uint256 indexed txFee,
                      address indexed feeToken,
                      address indexed execAddress,
                      bytes execData,
                      bytes32 taskId,
                      bool callSuccess
                  );
                  /**
                   * @notice Emitted when `execBypassModule` is called.
                   *
                   * @param taskId Unique hash of the task. {See LibTaskId-getTaskId}
                   * @param correlationId Id of the execution to be used for 1Balance settlement.
                   * @param callSuccess Status of the call to execAddress.
                   */
                  event ExecBypassModuleSuccess(
                      bytes32 taskId,
                      bytes32 correlationId,
                      bool callSuccess
                  );
                  /**
                   * @notice Emitted when `execBypassModuleSyncFee` is called.
                   *
                   * @param taskId Unique hash of the task. {See LibTaskId-getTaskId}
                   * @param txFee Fee paid to Gelato for execution
                   * @param feeToken Token used to pay for the execution. ETH = 0xeeeeee...
                   * @param callSuccess Status of the call to execAddress.
                   */
                  event ExecBypassModuleSyncFeeSuccess(
                      bytes32 taskId,
                      uint256 txFee,
                      address feeToken,
                      bool callSuccess
                  );
              }
              // SPDX-License-Identifier: UNLICENSED
              pragma solidity ^0.8.0;
              import {LibDataTypes} from "./LibDataTypes.sol";
              /**
               * @notice Library to compute taskId of tasks.
               */
              // solhint-disable max-line-length
              library LibTaskId {
                  /**
                   * @notice Returns taskId of taskCreator.
                   *
                   * @param taskCreator The address which created the task.
                   * @param execAddress Address of contract that will be called by Gelato.
                   * @param execSelector Signature of the function which will be called by Gelato.
                   * @param moduleData  Conditional modules that will be used. {See LibDataTypes-ModuleData}
                   * @param feeToken Address of token to be used as payment. Use address(0) if Gelato 1Balance is being used, 0xeeeeee... for ETH or native tokens.
                   */
                  function getTaskId(
                      address taskCreator,
                      address execAddress,
                      bytes4 execSelector,
                      LibDataTypes.ModuleData memory moduleData,
                      address feeToken
                  ) internal pure returns (bytes32 taskId) {
                      taskId = keccak256(
                          abi.encode(
                              taskCreator,
                              execAddress,
                              execSelector,
                              moduleData,
                              feeToken
                          )
                      );
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.12;
              import {_call, _delegateCall} from "../functions/FExec.sol";
              import {LibDataTypes} from "./LibDataTypes.sol";
              import {LibTaskModuleConfig} from "./LibTaskModuleConfig.sol";
              import {ITaskModule} from "../interfaces/ITaskModule.sol";
              // solhint-disable function-max-lines
              /// @notice Library to call task modules on task creation and execution.
              library LibTaskModule {
                  using LibTaskModuleConfig for LibDataTypes.Module;
                  /**
                   * @notice Delegate calls task modules before generating taskId.
                   *
                   * @param _execAddress Address of contract that will be called by Gelato.
                   * @param _taskCreator The address which created the task.
                   * @param taskModuleAddresses The storage reference to the mapping of modules to their address.
                   */
                  function preCreateTask(
                      address _taskCreator,
                      address _execAddress,
                      mapping(LibDataTypes.Module => address) storage taskModuleAddresses
                  ) internal returns (address, address) {
                      uint256 length = uint256(type(LibDataTypes.Module).max) + 1;
                      for (uint256 i; i < length; i++) {
                          LibDataTypes.Module module = LibDataTypes.Module(i);
                          if (!module.requirePreCreate()) continue;
                          address moduleAddress = taskModuleAddresses[module];
                          _moduleInitialised(moduleAddress);
                          bytes memory delegatecallData = abi.encodeWithSelector(
                              ITaskModule.preCreateTask.selector,
                              _taskCreator,
                              _execAddress
                          );
                          (, bytes memory returnData) = _delegateCall(
                              moduleAddress,
                              delegatecallData,
                              "Automate.preCreateTask: "
                          );
                          (_taskCreator, _execAddress) = abi.decode(
                              returnData,
                              (address, address)
                          );
                      }
                      return (_taskCreator, _execAddress);
                  }
                  /**
                   * @notice Delegate calls task modules on create task to initialise them.
                   *
                   * @param _taskId Unique hash of the task. {See LibTaskId-getTaskId}
                   * @param _taskCreator The address which created the task.
                   * @param _execAddress Address of contract that will be called by Gelato.
                   * @param _execData Execution data to be called with / function selector.
                   * @param _moduleData Modules that will be used for the task. {See LibDataTypes-ModuleData}
                   * @param taskModuleAddresses The storage reference to the mapping of modules to their address.
                   */
                  function onCreateTask(
                      bytes32 _taskId,
                      address _taskCreator,
                      address _execAddress,
                      bytes memory _execData,
                      LibDataTypes.ModuleData memory _moduleData,
                      mapping(LibDataTypes.Module => address) storage taskModuleAddresses
                  ) internal {
                      uint256 length = _moduleData.modules.length;
                      _validModules(_moduleData.modules);
                      for (uint256 i; i < length; i++) {
                          LibDataTypes.Module module = _moduleData.modules[i];
                          if (!module.requireOnCreate()) continue;
                          address moduleAddress = taskModuleAddresses[module];
                          _moduleInitialised(moduleAddress);
                          bytes memory delegatecallData = abi.encodeWithSelector(
                              ITaskModule.onCreateTask.selector,
                              _taskId,
                              _taskCreator,
                              _execAddress,
                              _execData,
                              _moduleData.args[i]
                          );
                          _delegateCall(
                              moduleAddress,
                              delegatecallData,
                              "Automate.onCreateTask: "
                          );
                      }
                  }
                  /**
                   * @notice Delegate calls task modules before removing task.
                   *
                   * @param _taskId Unique hash of the task. {See LibTaskId-getTaskId}
                   * @param _taskCreator The address which created the task.
                   * @param taskModuleAddresses The storage reference to the mapping of modules to their address.
                   */
                  function preCancelTask(
                      bytes32 _taskId,
                      address _taskCreator,
                      mapping(LibDataTypes.Module => address) storage taskModuleAddresses
                  ) internal returns (address) {
                      uint256 length = uint256(type(LibDataTypes.Module).max);
                      for (uint256 i; i <= length; i++) {
                          LibDataTypes.Module module = LibDataTypes.Module(i);
                          if (!module.requirePreCancel()) continue;
                          address moduleAddress = taskModuleAddresses[module];
                          _moduleInitialised(moduleAddress);
                          bytes memory delegatecallData = abi.encodeWithSelector(
                              ITaskModule.preCancelTask.selector,
                              _taskId,
                              _taskCreator
                          );
                          (, bytes memory returnData) = _delegateCall(
                              moduleAddress,
                              delegatecallData,
                              "Automate.preCancelTask: "
                          );
                          (_taskCreator) = abi.decode(returnData, (address));
                      }
                      return _taskCreator;
                  }
                  /**
                   * @notice Delegate calls task modules on exec.
                   *
                   * @param _taskId Unique hash of the task. {See LibTaskId-getTaskId}
                   * @param _taskCreator Address which created the task.
                   * @param _execAddress Address of contract that will be called by Gelato.
                   * @param _execData Execution data to be called with / function selector.
                   * @param _modules Modules that is used for the task. {See LibDataTypes-Module}
                   * @param _revertOnFailure To revert or not if call to execAddress fails.
                   * @param taskModuleAddresses The storage reference to the mapping of modules to their address.
                   */
                  function onExecTask(
                      bytes32 _taskId,
                      address _taskCreator,
                      address _execAddress,
                      bytes memory _execData,
                      LibDataTypes.Module[] memory _modules,
                      bool _revertOnFailure,
                      mapping(LibDataTypes.Module => address) storage taskModuleAddresses
                  ) internal returns (bool callSuccess) {
                      address[] memory moduleAddresses = _getModuleAddresses(
                          _modules,
                          taskModuleAddresses
                      );
                      (_execAddress, _execData) = preExecCall(
                          _taskId,
                          _taskCreator,
                          _execAddress,
                          _execData,
                          _modules,
                          moduleAddresses
                      );
                      (callSuccess, ) = _call(
                          _execAddress,
                          abi.encodePacked(_execData, _taskCreator),
                          0,
                          _revertOnFailure,
                          "Automate.exec: "
                      );
                      postExecCall(
                          _taskId,
                          _taskCreator,
                          _execAddress,
                          _execData,
                          _modules,
                          moduleAddresses
                      );
                  }
                  function preExecCall(
                      bytes32 _taskId,
                      address _taskCreator,
                      address _execAddress,
                      bytes memory _execData,
                      LibDataTypes.Module[] memory _modules,
                      address[] memory _moduleAddresses
                  ) internal returns (address, bytes memory) {
                      uint256 length = _modules.length;
                      for (uint256 i; i < length; i++) {
                          if (!_modules[i].requirePreExec()) continue;
                          bytes memory delegatecallData = abi.encodeWithSelector(
                              ITaskModule.preExecCall.selector,
                              _taskId,
                              _taskCreator,
                              _execAddress,
                              _execData
                          );
                          (, bytes memory returnData) = _delegateCall(
                              _moduleAddresses[i],
                              delegatecallData,
                              "Automate.preExecCall: "
                          );
                          (_execAddress, _execData) = abi.decode(
                              returnData,
                              (address, bytes)
                          );
                      }
                      return (_execAddress, _execData);
                  }
                  function postExecCall(
                      bytes32 _taskId,
                      address _taskCreator,
                      address _execAddress,
                      bytes memory _execData,
                      LibDataTypes.Module[] memory _modules,
                      address[] memory _moduleAddresses
                  ) internal {
                      uint256 length = _moduleAddresses.length;
                      for (uint256 i; i < length; i++) {
                          if (!_modules[i].requirePostExec()) continue;
                          bytes memory delegatecallData = abi.encodeWithSelector(
                              ITaskModule.postExecCall.selector,
                              _taskId,
                              _taskCreator,
                              _execAddress,
                              _execData
                          );
                          _delegateCall(
                              _moduleAddresses[i],
                              delegatecallData,
                              "Automate.postExecCall: "
                          );
                      }
                  }
                  function _getModuleAddresses(
                      LibDataTypes.Module[] memory _modules,
                      mapping(LibDataTypes.Module => address) storage taskModuleAddresses
                  ) private view returns (address[] memory) {
                      uint256 length = _modules.length;
                      address[] memory moduleAddresses = new address[](length);
                      for (uint256 i; i < length; i++) {
                          moduleAddresses[i] = taskModuleAddresses[_modules[i]];
                      }
                      return moduleAddresses;
                  }
                  function _moduleInitialised(address _moduleAddress) private pure {
                      require(
                          _moduleAddress != address(0),
                          "Automate._moduleInitialised: Not init"
                      );
                  }
                  /**
                   * @dev
                   * - No duplicate modules
                   * - No deprecated TIME
                   * - No RESOLVER && WEB3_FUNCTION
                   * - PROXY is required
                   */
                  function _validModules(LibDataTypes.Module[] memory _modules) private pure {
                      uint256 length = _modules.length;
                      uint256 existsLength = uint256(type(LibDataTypes.Module).max) + 1;
                      bool[] memory exists = new bool[](existsLength);
                      for (uint256 i = 0; i < length; i++) {
                          if (i > 0) {
                              require(
                                  _modules[i] > _modules[i - 1],
                                  "Automate._validModules: Asc only"
                              );
                          }
                          exists[uint256(_modules[i])] = true;
                      }
                      require(
                          !exists[uint256(LibDataTypes.Module.DEPRECATED_TIME)],
                          "Automate._validModules: TIME is deprecated"
                      );
                      require(
                          !(exists[uint256(LibDataTypes.Module.RESOLVER)] &&
                              exists[uint256(LibDataTypes.Module.WEB3_FUNCTION)]),
                          "Automate._validModules: Only RESOLVER or WEB3_FUNCTION"
                      );
                      require(
                          exists[uint256(LibDataTypes.Module.PROXY)],
                          "Automate._validModules: PROXY is required"
                      );
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.12;
              import {LibDataTypes} from "./LibDataTypes.sol";
              /**
               * @notice Library to determine wether to call task modules to reduce unnecessary calls.
               */
              library LibTaskModuleConfig {
                  function requirePreCreate(LibDataTypes.Module _module)
                      internal
                      pure
                      returns (bool)
                  {
                      if (_module == LibDataTypes.Module.PROXY) return true;
                      return false;
                  }
                  function requirePreCancel(LibDataTypes.Module _module)
                      internal
                      pure
                      returns (bool)
                  {
                      if (_module == LibDataTypes.Module.PROXY) return true;
                      return false;
                  }
                  function requireOnCreate(LibDataTypes.Module _module)
                      internal
                      pure
                      returns (bool)
                  {
                      if (_module == LibDataTypes.Module.PROXY) return true;
                      return false;
                  }
                  function requirePreExec(LibDataTypes.Module _module)
                      internal
                      pure
                      returns (bool)
                  {
                      if (_module == LibDataTypes.Module.PROXY) return true;
                      return false;
                  }
                  function requirePostExec(LibDataTypes.Module _module)
                      internal
                      pure
                      returns (bool)
                  {
                      if (_module == LibDataTypes.Module.SINGLE_EXEC) return true;
                      return false;
                  }
              }
              // SPDX-License-Identifier: UNLICENSED
              pragma solidity ^0.8.12;
              library GelatoBytes {
                  function calldataSliceSelector(bytes calldata _bytes)
                      internal
                      pure
                      returns (bytes4 selector)
                  {
                      selector =
                          _bytes[0] |
                          (bytes4(_bytes[1]) >> 8) |
                          (bytes4(_bytes[2]) >> 16) |
                          (bytes4(_bytes[3]) >> 24);
                  }
                  function memorySliceSelector(bytes memory _bytes)
                      internal
                      pure
                      returns (bytes4 selector)
                  {
                      selector =
                          _bytes[0] |
                          (bytes4(_bytes[1]) >> 8) |
                          (bytes4(_bytes[2]) >> 16) |
                          (bytes4(_bytes[3]) >> 24);
                  }
                  function revertWithError(bytes memory _bytes, string memory _tracingInfo)
                      internal
                      pure
                  {
                      // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err
                      if (_bytes.length % 32 == 4) {
                          bytes4 selector;
                          assembly {
                              selector := mload(add(0x20, _bytes))
                          }
                          if (selector == 0x08c379a0) {
                              // Function selector for Error(string)
                              assembly {
                                  _bytes := add(_bytes, 68)
                              }
                              revert(string(abi.encodePacked(_tracingInfo, string(_bytes))));
                          } else {
                              revert(
                                  string(abi.encodePacked(_tracingInfo, "NoErrorSelector"))
                              );
                          }
                      } else {
                          revert(
                              string(abi.encodePacked(_tracingInfo, "UnexpectedReturndata"))
                          );
                      }
                  }
                  function returnError(bytes memory _bytes, string memory _tracingInfo)
                      internal
                      pure
                      returns (string memory)
                  {
                      // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err
                      if (_bytes.length % 32 == 4) {
                          bytes4 selector;
                          assembly {
                              selector := mload(add(0x20, _bytes))
                          }
                          if (selector == 0x08c379a0) {
                              // Function selector for Error(string)
                              assembly {
                                  _bytes := add(_bytes, 68)
                              }
                              return string(abi.encodePacked(_tracingInfo, string(_bytes)));
                          } else {
                              return
                                  string(abi.encodePacked(_tracingInfo, "NoErrorSelector"));
                          }
                      } else {
                          return
                              string(abi.encodePacked(_tracingInfo, "UnexpectedReturndata"));
                      }
                  }
              }
              // SPDX-License-Identifier: UNLICENSED
              pragma solidity ^0.8.12;
              import {
                  SafeERC20,
                  IERC20
              } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
              import {_transfer, ETH} from "../../functions/FUtils.sol";
              abstract contract Gelatofied {
                  address payable public immutable gelato;
                  modifier gelatofy(uint256 _amount, address _paymentToken) {
                      require(msg.sender == gelato, "Gelatofied: Only gelato");
                      _;
                      _transfer(gelato, _paymentToken, _amount);
                  }
                  modifier onlyGelato() {
                      require(msg.sender == gelato, "Gelatofied: Only gelato");
                      _;
                  }
                  constructor(address payable _gelato) {
                      gelato = _gelato;
                  }
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity ^0.8.12;
              abstract contract Proxied {
                  /// @notice to be used by initialisation / postUpgrade function so that only the proxy's admin can execute them
                  /// It also allows these functions to be called inside a contructor
                  /// even if the contract is meant to be used without proxy
                  modifier proxied() {
                      address proxyAdminAddress = _proxyAdmin();
                      // With hardhat-deploy proxies
                      // the proxyAdminAddress is zero only for the implementation contract
                      // if the implementation contract want to be used as a standalone/immutable contract
                      // it simply has to execute the `proxied` function
                      // This ensure the proxyAdminAddress is never zero post deployment
                      // And allow you to keep the same code for both proxied contract and immutable contract
                      if (proxyAdminAddress == address(0)) {
                          // ensure can not be called twice when used outside of proxy : no admin
                          // solhint-disable-next-line security/no-inline-assembly
                          assembly {
                              sstore(
                                  0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103,
                                  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
                              )
                          }
                      } else {
                          require(msg.sender == proxyAdminAddress);
                      }
                      _;
                  }
                  modifier onlyProxyAdmin() {
                      require(msg.sender == _proxyAdmin(), "NOT_AUTHORIZED");
                      _;
                  }
                  function _proxyAdmin() internal view returns (address adminAddress) {
                      // solhint-disable-next-line security/no-inline-assembly
                      assembly {
                          adminAddress := sload(
                              0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103
                          )
                      }
                  }
              }
              

              File 5 of 6: OpsProxy
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.12;
              import {GelatoBytes} from "../vendor/gelato/GelatoBytes.sol";
              // solhint-disable private-vars-leading-underscore
              // solhint-disable func-visibility
              function _call(
                  address _add,
                  bytes memory _data,
                  uint256 _value,
                  bool _revertOnFailure,
                  string memory _tracingInfo
              ) returns (bool success, bytes memory returnData) {
                  (success, returnData) = _add.call{value: _value}(_data);
                  if (!success && _revertOnFailure)
                      GelatoBytes.revertWithError(returnData, _tracingInfo);
              }
              function _delegateCall(
                  address _add,
                  bytes memory _data,
                  string memory _tracingInfo
              ) returns (bool success, bytes memory returnData) {
                  (success, returnData) = _add.delegatecall(_data);
                  if (!success) GelatoBytes.revertWithError(returnData, _tracingInfo);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.12;
              interface IOpsProxy {
                  /**
                   * @notice Emitted when proxy calls a contract successfully in `executeCall`
                   *
                   * @param target Address of contract that is called
                   * @param data Data used in the call.
                   * @param value Native token value used in the call.
                   * @param returnData Data returned by the call.
                   */
                  event ExecuteCall(
                      address indexed target,
                      bytes data,
                      uint256 value,
                      bytes returnData
                  );
                  /**
                   * @notice Multicall to different contracts with different datas.
                   *
                   * @param targets Addresses of contracts to be called.
                   * @param datas Datas for each contract call.
                   * @param values Native token value for each contract call.
                   */
                  function batchExecuteCall(
                      address[] calldata targets,
                      bytes[] calldata datas,
                      uint256[] calldata values
                  ) external payable;
                  /**
                   * @notice Call to a single contract.
                   *
                   * @param target Address of contracts to be called.
                   * @param data Data for contract call.
                   * @param value Native token value for contract call.
                   */
                  function executeCall(
                      address target,
                      bytes calldata data,
                      uint256 value
                  ) external payable;
                  /**
                   * @return address Ops smart contract address
                   */
                  function ops() external view returns (address);
                  /**
                   * @return address Owner of the proxy
                   */
                  function owner() external view returns (address);
                  /**
                   * @return uint256 version of OpsProxy.
                   */
                  function version() external view returns (uint256);
              }
              // SPDX-License-Identifier: UNLICENSED
              pragma solidity ^0.8.12;
              import {Proxied} from "../vendor/proxy/EIP173/Proxied.sol";
              import {_call} from "../functions/FExec.sol";
              import {IOpsProxy} from "../interfaces/IOpsProxy.sol";
              contract OpsProxy is Proxied, IOpsProxy {
                  // solhint-disable const-name-snakecase
                  uint256 public constant override version = 1;
                  address public immutable override ops;
                  modifier onlyAuth() {
                      address proxyOwner = owner();
                      if (msg.sender != proxyOwner) {
                          require(msg.sender == ops, "OpsProxy: Not authorised");
                          require(
                              _getTaskCreator() == proxyOwner,
                              "OpsProxy: Only tasks created by owner"
                          );
                      } // else msg.sender == proxyOwner
                      _;
                  }
                  // solhint-disable no-empty-blocks
                  constructor(address _ops) {
                      ops = _ops;
                  }
                  receive() external payable {}
                  ///@inheritdoc IOpsProxy
                  function batchExecuteCall(
                      address[] calldata _targets,
                      bytes[] calldata _datas,
                      uint256[] calldata _values
                  ) external payable override onlyAuth {
                      uint256 length = _targets.length;
                      require(
                          length == _datas.length && length == _values.length,
                          "OpsProxy: Length mismatch"
                      );
                      for (uint256 i; i < length; i++)
                          _executeCall(_targets[i], _datas[i], _values[i]);
                  }
                  ///@inheritdoc IOpsProxy
                  function executeCall(
                      address _target,
                      bytes calldata _data,
                      uint256 _value
                  ) external payable override onlyAuth {
                      _executeCall(_target, _data, _value);
                  }
                  function owner() public view returns (address) {
                      return _proxyAdmin();
                  }
                  function _executeCall(
                      address _target,
                      bytes calldata _data,
                      uint256 _value
                  ) private {
                      (, bytes memory returnData) = _call(
                          _target,
                          _data,
                          _value,
                          true,
                          "OpsProxy.executeCall: "
                      );
                      emit ExecuteCall(_target, _data, _value, returnData);
                  }
                  function _getTaskCreator() private pure returns (address taskCreator) {
                      assembly {
                          taskCreator := shr(96, calldataload(sub(calldatasize(), 20)))
                      }
                  }
              }
              // SPDX-License-Identifier: UNLICENSED
              pragma solidity ^0.8.12;
              library GelatoBytes {
                  function calldataSliceSelector(bytes calldata _bytes)
                      internal
                      pure
                      returns (bytes4 selector)
                  {
                      selector =
                          _bytes[0] |
                          (bytes4(_bytes[1]) >> 8) |
                          (bytes4(_bytes[2]) >> 16) |
                          (bytes4(_bytes[3]) >> 24);
                  }
                  function memorySliceSelector(bytes memory _bytes)
                      internal
                      pure
                      returns (bytes4 selector)
                  {
                      selector =
                          _bytes[0] |
                          (bytes4(_bytes[1]) >> 8) |
                          (bytes4(_bytes[2]) >> 16) |
                          (bytes4(_bytes[3]) >> 24);
                  }
                  function revertWithError(bytes memory _bytes, string memory _tracingInfo)
                      internal
                      pure
                  {
                      // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err
                      if (_bytes.length % 32 == 4) {
                          bytes4 selector;
                          assembly {
                              selector := mload(add(0x20, _bytes))
                          }
                          if (selector == 0x08c379a0) {
                              // Function selector for Error(string)
                              assembly {
                                  _bytes := add(_bytes, 68)
                              }
                              revert(string(abi.encodePacked(_tracingInfo, string(_bytes))));
                          } else {
                              revert(
                                  string(abi.encodePacked(_tracingInfo, "NoErrorSelector"))
                              );
                          }
                      } else {
                          revert(
                              string(abi.encodePacked(_tracingInfo, "UnexpectedReturndata"))
                          );
                      }
                  }
                  function returnError(bytes memory _bytes, string memory _tracingInfo)
                      internal
                      pure
                      returns (string memory)
                  {
                      // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err
                      if (_bytes.length % 32 == 4) {
                          bytes4 selector;
                          assembly {
                              selector := mload(add(0x20, _bytes))
                          }
                          if (selector == 0x08c379a0) {
                              // Function selector for Error(string)
                              assembly {
                                  _bytes := add(_bytes, 68)
                              }
                              return string(abi.encodePacked(_tracingInfo, string(_bytes)));
                          } else {
                              return
                                  string(abi.encodePacked(_tracingInfo, "NoErrorSelector"));
                          }
                      } else {
                          return
                              string(abi.encodePacked(_tracingInfo, "UnexpectedReturndata"));
                      }
                  }
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity ^0.8.12;
              abstract contract Proxied {
                  /// @notice to be used by initialisation / postUpgrade function so that only the proxy's admin can execute them
                  /// It also allows these functions to be called inside a contructor
                  /// even if the contract is meant to be used without proxy
                  modifier proxied() {
                      address proxyAdminAddress = _proxyAdmin();
                      // With hardhat-deploy proxies
                      // the proxyAdminAddress is zero only for the implementation contract
                      // if the implementation contract want to be used as a standalone/immutable contract
                      // it simply has to execute the `proxied` function
                      // This ensure the proxyAdminAddress is never zero post deployment
                      // And allow you to keep the same code for both proxied contract and immutable contract
                      if (proxyAdminAddress == address(0)) {
                          // ensure can not be called twice when used outside of proxy : no admin
                          // solhint-disable-next-line security/no-inline-assembly
                          assembly {
                              sstore(
                                  0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103,
                                  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
                              )
                          }
                      } else {
                          require(msg.sender == proxyAdminAddress);
                      }
                      _;
                  }
                  modifier onlyProxyAdmin() {
                      require(msg.sender == _proxyAdmin(), "NOT_AUTHORIZED");
                      _;
                  }
                  function _proxyAdmin() internal view returns (address adminAddress) {
                      // solhint-disable-next-line security/no-inline-assembly
                      assembly {
                          adminAddress := sload(
                              0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103
                          )
                      }
                  }
              }
              

              File 6 of 6: PythUpdater
              // SPDX-License-Identifier: Apache-2.0
              pragma solidity ^0.8.0;
              import "./PythStructs.sol";
              import "./IPythEvents.sol";
              /// @title Consume prices from the Pyth Network (https://pyth.network/).
              /// @dev Please refer to the guidance at https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices for how to consume prices safely.
              /// @author Pyth Data Association
              interface IPyth is IPythEvents {
                  /// @notice Returns the price of a price feed without any sanity checks.
                  /// @dev This function returns the most recent price update in this contract without any recency checks.
                  /// This function is unsafe as the returned price update may be arbitrarily far in the past.
                  ///
                  /// Users of this function should check the `publishTime` in the price to ensure that the returned price is
                  /// sufficiently recent for their application. If you are considering using this function, it may be
                  /// safer / easier to use `getPriceNoOlderThan`.
                  /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
                  function getPriceUnsafe(
                      bytes32 id
                  ) external view returns (PythStructs.Price memory price);
                  /// @notice Returns the price that is no older than `age` seconds of the current time.
                  /// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in
                  /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
                  /// recently.
                  /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
                  function getPriceNoOlderThan(
                      bytes32 id,
                      uint age
                  ) external view returns (PythStructs.Price memory price);
                  /// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks.
                  /// @dev This function returns the same price as `getEmaPrice` in the case where the price is available.
                  /// However, if the price is not recent this function returns the latest available price.
                  ///
                  /// The returned price can be from arbitrarily far in the past; this function makes no guarantees that
                  /// the returned price is recent or useful for any particular application.
                  ///
                  /// Users of this function should check the `publishTime` in the price to ensure that the returned price is
                  /// sufficiently recent for their application. If you are considering using this function, it may be
                  /// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`.
                  /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
                  function getEmaPriceUnsafe(
                      bytes32 id
                  ) external view returns (PythStructs.Price memory price);
                  /// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds
                  /// of the current time.
                  /// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in
                  /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
                  /// recently.
                  /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
                  function getEmaPriceNoOlderThan(
                      bytes32 id,
                      uint age
                  ) external view returns (PythStructs.Price memory price);
                  /// @notice Update price feeds with given update messages.
                  /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
                  /// `getUpdateFee` with the length of the `updateData` array.
                  /// Prices will be updated if they are more recent than the current stored prices.
                  /// The call will succeed even if the update is not the most recent.
                  /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid.
                  /// @param updateData Array of price update data.
                  function updatePriceFeeds(bytes[] calldata updateData) external payable;
                  /// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is
                  /// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the
                  /// given `publishTimes` for the price feeds and does not read the actual price update publish time within `updateData`.
                  ///
                  /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
                  /// `getUpdateFee` with the length of the `updateData` array.
                  ///
                  /// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime
                  /// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have
                  /// a newer or equal publish time than the given publish time, it will reject the transaction to save gas.
                  /// Otherwise, it calls updatePriceFeeds method to update the prices.
                  ///
                  /// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid.
                  /// @param updateData Array of price update data.
                  /// @param priceIds Array of price ids.
                  /// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]`
                  function updatePriceFeedsIfNecessary(
                      bytes[] calldata updateData,
                      bytes32[] calldata priceIds,
                      uint64[] calldata publishTimes
                  ) external payable;
                  /// @notice Returns the required fee to update an array of price updates.
                  /// @param updateData Array of price update data.
                  /// @return feeAmount The required fee in Wei.
                  function getUpdateFee(
                      bytes[] calldata updateData
                  ) external view returns (uint feeAmount);
                  /// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published
                  /// within `minPublishTime` and `maxPublishTime`.
                  ///
                  /// You can use this method if you want to use a Pyth price at a fixed time and not the most recent price;
                  /// otherwise, please consider using `updatePriceFeeds`. This method may store the price updates on-chain, if they
                  /// are more recent than the current stored prices.
                  ///
                  /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
                  /// `getUpdateFee` with the length of the `updateData` array.
                  ///
                  ///
                  /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is
                  /// no update for any of the given `priceIds` within the given time range.
                  /// @param updateData Array of price update data.
                  /// @param priceIds Array of price ids.
                  /// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
                  /// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
                  /// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
                  function parsePriceFeedUpdates(
                      bytes[] calldata updateData,
                      bytes32[] calldata priceIds,
                      uint64 minPublishTime,
                      uint64 maxPublishTime
                  ) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
                  /// @notice Similar to `parsePriceFeedUpdates` but ensures the updates returned are
                  /// the first updates published in minPublishTime. That is, if there are multiple updates for a given timestamp,
                  /// this method will return the first update. This method may store the price updates on-chain, if they
                  /// are more recent than the current stored prices.
                  ///
                  ///
                  /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is
                  /// no update for any of the given `priceIds` within the given time range and uniqueness condition.
                  /// @param updateData Array of price update data.
                  /// @param priceIds Array of price ids.
                  /// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
                  /// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
                  /// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
                  function parsePriceFeedUpdatesUnique(
                      bytes[] calldata updateData,
                      bytes32[] calldata priceIds,
                      uint64 minPublishTime,
                      uint64 maxPublishTime
                  ) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
              }
              // SPDX-License-Identifier: Apache-2.0
              pragma solidity ^0.8.0;
              /// @title IPythEvents contains the events that Pyth contract emits.
              /// @dev This interface can be used for listening to the updates for off-chain and testing purposes.
              interface IPythEvents {
                  /// @dev Emitted when the price feed with `id` has received a fresh update.
                  /// @param id The Pyth Price Feed ID.
                  /// @param publishTime Publish time of the given price update.
                  /// @param price Price of the given price update.
                  /// @param conf Confidence interval of the given price update.
                  event PriceFeedUpdate(
                      bytes32 indexed id,
                      uint64 publishTime,
                      int64 price,
                      uint64 conf
                  );
              }
              // SPDX-License-Identifier: Apache-2.0
              pragma solidity ^0.8.0;
              contract PythStructs {
                  // A price with a degree of uncertainty, represented as a price +- a confidence interval.
                  //
                  // The confidence interval roughly corresponds to the standard error of a normal distribution.
                  // Both the price and confidence are stored in a fixed-point numeric representation,
                  // `x * (10^expo)`, where `expo` is the exponent.
                  //
                  // Please refer to the documentation at https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices for how
                  // to how this price safely.
                  struct Price {
                      // Price
                      int64 price;
                      // Confidence interval around the price
                      uint64 conf;
                      // Price exponent
                      int32 expo;
                      // Unix timestamp describing when the price was published
                      uint publishTime;
                  }
                  // PriceFeed represents a current aggregate price from pyth publisher feeds.
                  struct PriceFeed {
                      // The price ID.
                      bytes32 id;
                      // Latest available price
                      Price price;
                      // Latest available exponentially-weighted moving average price
                      Price emaPrice;
                  }
              }
              //SPDX-License-Identifier: Unlicense
              pragma solidity ^0.8.0;
              import {IPyth} from "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
              /**
               * @title A port of a chainlink aggregator powered by pyth network feeds
               * @author Deadshot Ryker
               * @notice This does not store any roundId information on-chain. Please review the code before using this implementation.
               */
              contract PythUpdater {
                  IPyth public pyth;
                  constructor(address _pyth) {
                      pyth = IPyth(_pyth);
                  }
                  function updateFeeds(bytes[] calldata priceUpdateData) public payable {
                      // Update the prices to the latest available values and pay the required fee for it. The `priceUpdateData` data
                      // should be retrieved from our off-chain Price Service API using the `pyth-evm-js` package.
                      // See section "How Pyth Works on EVM Chains" below for more information.
                      uint fee = pyth.getUpdateFee(priceUpdateData);
                      pyth.updatePriceFeeds{value: fee}(priceUpdateData);
                  }
                  receive() external payable {
                      // do nothing
                  }
              }