ETH Price: $4,271.93 (+3.06%)

Transaction Decoder

Block:
12391624 at May-08-2021 04:55:16 AM +UTC
Transaction Fee:
0.04092542743115876 ETH $174.83
Gas Used:
794,360 Gas / 51.520000291 Gwei

Emitted Events:

54 DepositContract.DepositEvent( pubkey=0xB3DDCA4B0C6767326F5DAFFB93778E1ECCCEDA7240B0151CC42EA469602B14C0EB01463C873D9694FDBD427AB4DB12D7, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, amount=0x0040597307000000, signature=0x99F4092ABAB878E29237F8C0815807409FF6715399A2BD4753519F315B06F9DC42098325DE99CF3A9DF039DC5C32BF4E12A9DF890B6793AEDC7F6DD5AE4BFB1517420A84C02A46CE7E03E39D2C35F3D6BF7DD6A4551907B4E5647A403D07F14A, index=0xEF17020000000000 )
55 DepositContract.DepositEvent( pubkey=0x8A106310EA872243CA70E0293DC27405CB246E102087FB6D769CF8BA3DE11EFF08ADA89271FE218641CB3BF43D2A32D8, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, amount=0x0040597307000000, signature=0xB37C2DF25F914B7B928C52A708173B70950E262710DC7E5210720B5825538BCE273F6F6823E706A006DB8A742FA2010D12F0E120879B6873FAB2B93F95A91E166EEFDB023BA58746D06AF7B8038E13BD2B312F358059ABCB03F6492EF8AFE14C, index=0xF017020000000000 )
56 DepositContract.DepositEvent( pubkey=0x971FB132B8681F389546681974292D935BDDBA92CEF3EB45C27067605E11991C28C491783F187C0637BAA5B9448D7179, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, amount=0x0040597307000000, signature=0x82903C917E88DEC0B25C8449AA94E26627643448D9051E96A71ED2C983A0C781A6D6DB9D5EE17F04C41C0253D1AF454E00CECCAD6736BF863CB06131126B8BD4D7142646B96ECE2AE9682F84897EA399A1D224DB7360560BFB2DECB1912875B8, index=0xF117020000000000 )
57 DepositContract.DepositEvent( pubkey=0x8BC4380D41C7C47A25801A2402AD575FD5941CABA37E316C654067F56D28DD0AA3ED9EFDC3B36DEC81037D5EAB27EC62, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, amount=0x0040597307000000, signature=0x9060CFF3685FFC1E5DB0BDC53B690FD5FF1E271AEA8E4C5294622B38D3A901FAC40FA0758A7A62C78C1F30227761E81F04D8548983733BAEA598CA33131AE4D224F336615CA28C255B7187D94483426F1DA3B673EC214D9A710F9B8B4F0CEFA5, index=0xF217020000000000 )
58 DepositContract.DepositEvent( pubkey=0x8755B300E2C27A6B82FE7BC4AF3B29C66CE83D10B1273A7DA48802FA3E81D045C9EE0282C6A72DF86BBDE20531E675C0, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, amount=0x0040597307000000, signature=0xA7A48AE8858C5D18A1DDCFDE768B282B8F6B059F7C98132EC069F775BDCEA41FEA54C91491701E2E928B457AF5863489170460529CC03CDFD1FAE0CFF22CD7F0860CCEDB48F0A1437BCDEE28300F556D9A282D6EF78302DB11DF86F6A2E15DB1, index=0xF317020000000000 )
59 DepositContract.DepositEvent( pubkey=0x9547CFE126F6C14C14183992055E7374FE6B995F21FF55B0C1AF9219D0C1CA6F37452B4B2C260F0D775D19AF0DECA6C3, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, amount=0x0040597307000000, signature=0xA0AC9D146079E34F9783AA816CE44401ED8B5387B7A1E2A3865D27EF8FA648916A55C726051A5DB0D148C58A8AF72E7E048D33895B28D456ECEBD290E0E7B8033950A347B6C4B3576819EACE75B620BC754E397DD2FE7F2DB886A456C1A80706, index=0xF417020000000000 )
60 DepositContract.DepositEvent( pubkey=0x82CE713881473857C2E6F42DE9D211D8CEFD08D9B4D1A1DAC534CB6A52986BDEE017B62853548232D55E4153BF1D9FF7, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, amount=0x0040597307000000, signature=0x8835BC988A802516A5255CBF68D8D9E3FC9316223FBA55C346A97CC5319C457A1D9EA6A4623785834303F68019EA8FBF10FC222BC1CE2258402CD9430BB478E2F454368E263EE653FCCA4DBABCE5E45903B0CA512E4BFCF682E578DDF2B6B2A6, index=0xF517020000000000 )
61 DepositContract.DepositEvent( pubkey=0xA18DDB4746340181D78A91094BF9030F12F8B0E634D21FC12DCD171C64580FBB153B46CD7CA9206F6A6F65CDFCF9C5EC, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, amount=0x0040597307000000, signature=0x84C4FEAB39F3DB0E9FF93CEA72D7642647FC8F23EBC4C3238DA15BBF85D4DBA4BB7F8B05C7212DFBD011B2013953932C149885ABBC230735B01F18139AC1A7C2F2BAB8DD4BCFB1962DDE0DCE0AF4ECAE51F019A5F0098059976840162FD7AA61, index=0xF617020000000000 )
62 DepositContract.DepositEvent( pubkey=0x9794738A1074AE051F121D0EBAAA6420E53E93D5D11B6CE671D1A2A4A7F4A002EB87A60F041F3148D588D2B0C743BA96, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, amount=0x0040597307000000, signature=0x8D7BC56FE7F3DEFE9972319C4F7B805D4F7F1E0A1EB5CC9DF3E8E64380215ECC95EC18F92CA3043BC8E9553E9D23A4C303D28453C0D4EBF7BE42CA0D1BA2B6F071FCCCCD57B1FAA095624F5BAF3D15E2E7617C2266BFA6A05B46567CD7C44F72, index=0xF717020000000000 )
63 AppProxyUpgradeable.0x76a397bea5768d4fca97ef47792796e35f98dc81b16c1de84e28a818e1f97108( 0x76a397bea5768d4fca97ef47792796e35f98dc81b16c1de84e28a818e1f97108, 00000000000000000000000000000000000000000000000f9ccd8a1c50800000 )
64 Keep3rV1.Transfer( from=[Receiver] Vyper_contract, to=[Sender] 0x6352f8c749954c9df198cf72976e48994a77cce2, amount=780219353335772372 )
65 Keep3rV1.KeeperWorked( credit=Keep3rV1, job=[Receiver] Vyper_contract, keeper=[Sender] 0x6352f8c749954c9df198cf72976e48994a77cce2, block=12391624, amount=780219353335772372 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...03d7705Fa
(Beacon Deposit Contract)
4,389,666.000069000000000069 Eth4,389,954.000069000000000069 Eth288
0x1cEB5cB5...A33185A44
0x55032650...Af2e028d5
(Lido: Curated Staking Module)
0x6352f8C7...94A77cCE2
(Lido: Eth2 Depositor 13)
2.269222570371680731 Eth
Nonce: 1908
2.228297142940521971 Eth
Nonce: 1909
0.04092542743115876
(Miner: 0x6eb...31a)
1,516.331681143522251959 Eth1,516.372606570953410719 Eth0.04092542743115876
0xae7ab965...312D7fE84 298.319786226590241489 Eth10.319786226590241489 Eth288

Execution Trace

Vyper_contract.CALL( )
  • Keep3rV1.isKeeper( keeper=0x6352f8C749954c9Df198cf72976E48994A77cCE2 ) => ( True )
  • AppProxyUpgradeable.STATICCALL( )
    • KernelProxy.be00bbd8( )
      • Kernel.getApp( _namespace=F1F3EB40F5BC1AD1344716CED8B8A0431D840B5783AEA1FD01786BC26F35AC0F, _appId=3CA7C3E38968823CCB4C78EA688DF41356F182AE1D159E4EE608D30D68CEF320 ) => ( 0x20dC62D5904633cC6a5E34bEc87A048E80C92e97 )
      • Lido.DELEGATECALL( )
      • AppProxyUpgradeable.STATICCALL( )
        • KernelProxy.be00bbd8( )
          • Kernel.getApp( _namespace=F1F3EB40F5BC1AD1344716CED8B8A0431D840B5783AEA1FD01786BC26F35AC0F, _appId=3CA7C3E38968823CCB4C78EA688DF41356F182AE1D159E4EE608D30D68CEF320 ) => ( 0x20dC62D5904633cC6a5E34bEc87A048E80C92e97 )
          • Lido.DELEGATECALL( )
          • AppProxyUpgradeable.STATICCALL( )
            • KernelProxy.be00bbd8( )
              • Kernel.getApp( _namespace=F1F3EB40F5BC1AD1344716CED8B8A0431D840B5783AEA1FD01786BC26F35AC0F, _appId=3CA7C3E38968823CCB4C78EA688DF41356F182AE1D159E4EE608D30D68CEF320 ) => ( 0x20dC62D5904633cC6a5E34bEc87A048E80C92e97 )
              • Lido.DELEGATECALL( )
              • AppProxyUpgradeable.90adc83b( )
                • KernelProxy.be00bbd8( )
                  • Kernel.getApp( _namespace=F1F3EB40F5BC1AD1344716CED8B8A0431D840B5783AEA1FD01786BC26F35AC0F, _appId=3CA7C3E38968823CCB4C78EA688DF41356F182AE1D159E4EE608D30D68CEF320 ) => ( 0x20dC62D5904633cC6a5E34bEc87A048E80C92e97 )
                  • Lido.depositBufferedEther( _maxDeposits=9 )
                    • AppProxyUpgradeable.41bc716f( )
                      • KernelProxy.be00bbd8( )
                        • Kernel.getApp( _namespace=F1F3EB40F5BC1AD1344716CED8B8A0431D840B5783AEA1FD01786BC26F35AC0F, _appId=7071F283424072341F856AC9E947E7EC0EB68719F757A7E785979B6B8717579D ) => ( 0x203e0B2Ae692669EC2a6f980401A8239596346Cb )
                        • NodeOperatorsRegistry.assignNextSigningKeys( _numKeys=9 ) => ( pubkeys=0xB3DDCA4B0C6767326F5DAFFB93778E1ECCCEDA7240B0151CC42EA469602B14C0EB01463C873D9694FDBD427AB4DB12D78A106310EA872243CA70E0293DC27405CB246E102087FB6D769CF8BA3DE11EFF08ADA89271FE218641CB3BF43D2A32D8971FB132B8681F389546681974292D935BDDBA92CEF3EB45C27067605E11991C28C491783F187C0637BAA5B9448D71798BC4380D41C7C47A25801A2402AD575FD5941CABA37E316C654067F56D28DD0AA3ED9EFDC3B36DEC81037D5EAB27EC628755B300E2C27A6B82FE7BC4AF3B29C66CE83D10B1273A7DA48802FA3E81D045C9EE0282C6A72DF86BBDE20531E675C09547CFE126F6C14C14183992055E7374FE6B995F21FF55B0C1AF9219D0C1CA6F37452B4B2C260F0D775D19AF0DECA6C382CE713881473857C2E6F42DE9D211D8CEFD08D9B4D1A1DAC534CB6A52986BDEE017B62853548232D55E4153BF1D9FF7A18DDB4746340181D78A91094BF9030F12F8B0E634D21FC12DCD171C64580FBB153B46CD7CA9206F6A6F65CDFCF9C5EC9794738A1074AE051F121D0EBAAA6420E53E93D5D11B6CE671D1A2A4A7F4A002EB87A60F041F3148D588D2B0C743BA96, signatures=0x99F4092ABAB878E29237F8C0815807409FF6715399A2BD4753519F315B06F9DC42098325DE99CF3A9DF039DC5C32BF4E12A9DF890B6793AEDC7F6DD5AE4BFB1517420A84C02A46CE7E03E39D2C35F3D6BF7DD6A4551907B4E5647A403D07F14AB37C2DF25F914B7B928C52A708173B70950E262710DC7E5210720B5825538BCE273F6F6823E706A006DB8A742FA2010D12F0E120879B6873FAB2B93F95A91E166EEFDB023BA58746D06AF7B8038E13BD2B312F358059ABCB03F6492EF8AFE14C82903C917E88DEC0B25C8449AA94E26627643448D9051E96A71ED2C983A0C781A6D6DB9D5EE17F04C41C0253D1AF454E00CECCAD6736BF863CB06131126B8BD4D7142646B96ECE2AE9682F84897EA399A1D224DB7360560BFB2DECB1912875B89060CFF3685FFC1E5DB0BDC53B690FD5FF1E271AEA8E4C5294622B38D3A901FAC40FA0758A7A62C78C1F30227761E81F04D8548983733BAEA598CA33131AE4D224F336615CA28C255B7187D94483426F1DA3B673EC214D9A710F9B8B4F0CEFA5A7A48AE8858C5D18A1DDCFDE768B282B8F6B059F7C98132EC069F775BDCEA41FEA54C91491701E2E928B457AF5863489170460529CC03CDFD1FAE0CFF22CD7F0860CCEDB48F0A1437BCDEE28300F556D9A282D6EF78302DB11DF86F6A2E15DB1A0AC9D146079E34F9783AA816CE44401ED8B5387B7A1E2A3865D27EF8FA648916A55C726051A5DB0D148C58A8AF72E7E048D33895B28D456ECEBD290E0E7B8033950A347B6C4B3576819EACE75B620BC754E397DD2FE7F2DB886A456C1A807068835BC988A802516A5255CBF68D8D9E3FC9316223FBA55C346A97CC5319C457A1D9EA6A4623785834303F68019EA8FBF10FC222BC1CE2258402CD9430BB478E2F454368E263EE653FCCA4DBABCE5E45903B0CA512E4BFCF682E578DDF2B6B2A684C4FEAB39F3DB0E9FF93CEA72D7642647FC8F23EBC4C3238DA15BBF85D4DBA4BB7F8B05C7212DFBD011B2013953932C149885ABBC230735B01F18139AC1A7C2F2BAB8DD4BCFB1962DDE0DCE0AF4ECAE51F019A5F0098059976840162FD7AA618D7BC56FE7F3DEFE9972319C4F7B805D4F7F1E0A1EB5CC9DF3E8E64380215ECC95EC18F92CA3043BC8E9553E9D23A4C303D28453C0D4EBF7BE42CA0D1BA2B6F071FCCCCD57B1FAA095624F5BAF3D15E2E7617C2266BFA6A05B46567CD7C44F72 )
                        • Null: 0x000...002.b3ddca4b( )
                        • Null: 0x000...002.99f4092a( )
                        • Null: 0x000...002.17420a84( )
                        • Null: 0x000...002.76f0055d( )
                        • Null: 0x000...002.f29c7006( )
                        • Null: 0x000...002.00405973( )
                        • Null: 0x000...002.99f93196( )
                        • ETH 32 DepositContract.deposit( pubkey=0xB3DDCA4B0C6767326F5DAFFB93778E1ECCCEDA7240B0151CC42EA469602B14C0EB01463C873D9694FDBD427AB4DB12D7, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, signature=0x99F4092ABAB878E29237F8C0815807409FF6715399A2BD4753519F315B06F9DC42098325DE99CF3A9DF039DC5C32BF4E12A9DF890B6793AEDC7F6DD5AE4BFB1517420A84C02A46CE7E03E39D2C35F3D6BF7DD6A4551907B4E5647A403D07F14A, deposit_data_root=E8ED8AE4826F6289861F15B065B0BA006B2C69CE1B0B2781B7007544187CE3F2 )
                          • Null: 0x000...002.b3ddca4b( )
                          • Null: 0x000...002.99f4092a( )
                          • Null: 0x000...002.17420a84( )
                          • Null: 0x000...002.76f0055d( )
                          • Null: 0x000...002.f29c7006( )
                          • Null: 0x000...002.00405973( )
                          • Null: 0x000...002.99f93196( )
                          • Null: 0x000...002.5769444f( )
                          • Null: 0x000...002.8be5ac6e( )
                          • Null: 0x000...002.5dc8229f( )
                          • Null: 0x000...002.73d6425d( )
                          • Null: 0x000...002.8a106310( )
                          • Null: 0x000...002.b37c2df2( )
                          • Null: 0x000...002.6eefdb02( )
                          • Null: 0x000...002.d8bf8466( )
                          • Null: 0x000...002.212b3068( )
                          • Null: 0x000...002.00405973( )
                          • Null: 0x000...002.2e1d681f( )
                          • ETH 32 DepositContract.deposit( pubkey=0x8A106310EA872243CA70E0293DC27405CB246E102087FB6D769CF8BA3DE11EFF08ADA89271FE218641CB3BF43D2A32D8, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, signature=0xB37C2DF25F914B7B928C52A708173B70950E262710DC7E5210720B5825538BCE273F6F6823E706A006DB8A742FA2010D12F0E120879B6873FAB2B93F95A91E166EEFDB023BA58746D06AF7B8038E13BD2B312F358059ABCB03F6492EF8AFE14C, deposit_data_root=0A02E212578A614F012006ED1301642670347DA4E6B75D59C71F6B8F06D77919 )
                            • Null: 0x000...002.8a106310( )
                            • Null: 0x000...002.b37c2df2( )
                            • Null: 0x000...002.6eefdb02( )
                            • Null: 0x000...002.d8bf8466( )
                            • Null: 0x000...002.212b3068( )
                            • Null: 0x000...002.00405973( )
                            • Null: 0x000...002.2e1d681f( )
                            • Null: 0x000...002.971fb132( )
                            • Null: 0x000...002.82903c91( )
                            • Null: 0x000...002.d7142646( )
                            • Null: 0x000...002.d22c61d7( )
                            • Null: 0x000...002.25699d13( )
                            • Null: 0x000...002.00405973( )
                            • Null: 0x000...002.85bc1b7b( )
                            • ETH 32 DepositContract.deposit( pubkey=0x971FB132B8681F389546681974292D935BDDBA92CEF3EB45C27067605E11991C28C491783F187C0637BAA5B9448D7179, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, signature=0x82903C917E88DEC0B25C8449AA94E26627643448D9051E96A71ED2C983A0C781A6D6DB9D5EE17F04C41C0253D1AF454E00CECCAD6736BF863CB06131126B8BD4D7142646B96ECE2AE9682F84897EA399A1D224DB7360560BFB2DECB1912875B8, deposit_data_root=0A570044335C52450C96E0C7896E84E0CBC114B43A49AA1424BFEC85D2924DA3 )
                              • Null: 0x000...002.971fb132( )
                              • Null: 0x000...002.82903c91( )
                              • Null: 0x000...002.d7142646( )
                              • Null: 0x000...002.d22c61d7( )
                              • Null: 0x000...002.25699d13( )
                              • Null: 0x000...002.00405973( )
                              • Null: 0x000...002.85bc1b7b( )
                              • Null: 0x000...002.0a02e212( )
                              • Null: 0x000...002.8bc4380d( )
                              • Null: 0x000...002.9060cff3( )
                              • Null: 0x000...002.24f33661( )
                              • Null: 0x000...002.e3a275fc( )
                              • Null: 0x000...002.ec9d2a70( )
                              • Null: 0x000...002.00405973( )
                              • Null: 0x000...002.ff98aec4( )
                              • ETH 32 DepositContract.deposit( pubkey=0x8BC4380D41C7C47A25801A2402AD575FD5941CABA37E316C654067F56D28DD0AA3ED9EFDC3B36DEC81037D5EAB27EC62, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, signature=0x9060CFF3685FFC1E5DB0BDC53B690FD5FF1E271AEA8E4C5294622B38D3A901FAC40FA0758A7A62C78C1F30227761E81F04D8548983733BAEA598CA33131AE4D224F336615CA28C255B7187D94483426F1DA3B673EC214D9A710F9B8B4F0CEFA5, deposit_data_root=E636F6F8A875EB2F5937BC3352B5EC12C75BF22AAF18D7F8C5BD307A1841DEB9 )
                                • Null: 0x000...002.8bc4380d( )
                                • Null: 0x000...002.9060cff3( )
                                • Null: 0x000...002.24f33661( )
                                • Null: 0x000...002.e3a275fc( )
                                • Null: 0x000...002.ec9d2a70( )
                                • Null: 0x000...002.00405973( )
                                • Null: 0x000...002.ff98aec4( )
                                • Null: 0x000...002.8755b300( )
                                • Null: 0x000...002.a7a48ae8( )
                                • Null: 0x000...002.860ccedb( )
                                • Null: 0x000...002.1bf19930( )
                                • Null: 0x000...002.572d8fc2( )
                                • Null: 0x000...002.00405973( )
                                • Null: 0x000...002.418a7dcb( )
                                • ETH 32 DepositContract.deposit( pubkey=0x8755B300E2C27A6B82FE7BC4AF3B29C66CE83D10B1273A7DA48802FA3E81D045C9EE0282C6A72DF86BBDE20531E675C0, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, signature=0xA7A48AE8858C5D18A1DDCFDE768B282B8F6B059F7C98132EC069F775BDCEA41FEA54C91491701E2E928B457AF5863489170460529CC03CDFD1FAE0CFF22CD7F0860CCEDB48F0A1437BCDEE28300F556D9A282D6EF78302DB11DF86F6A2E15DB1, deposit_data_root=7FD341684F0DE1038616A3978B5A53083658D7AF6A0802E703770781854912A7 )
                                  • Null: 0x000...002.8755b300( )
                                  • Null: 0x000...002.a7a48ae8( )
                                  • Null: 0x000...002.860ccedb( )
                                  • Null: 0x000...002.1bf19930( )
                                  • Null: 0x000...002.572d8fc2( )
                                  • Null: 0x000...002.00405973( )
                                  • Null: 0x000...002.418a7dcb( )
                                  • Null: 0x000...002.e636f6f8( )
                                  • Null: 0x000...002.d8abb131( )
                                  • Null: 0x000...002.9547cfe1( )
                                  • Null: 0x000...002.a0ac9d14( )
                                  • Null: 0x000...002.3950a347( )
                                  • Null: 0x000...002.d7124642( )
                                  • Null: 0x000...002.8b6230f9( )
                                  • Null: 0x000...002.00405973( )
                                  • Null: 0x000...002.6e813871( )
                                  • ETH 32 DepositContract.deposit( pubkey=0x9547CFE126F6C14C14183992055E7374FE6B995F21FF55B0C1AF9219D0C1CA6F37452B4B2C260F0D775D19AF0DECA6C3, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, signature=0xA0AC9D146079E34F9783AA816CE44401ED8B5387B7A1E2A3865D27EF8FA648916A55C726051A5DB0D148C58A8AF72E7E048D33895B28D456ECEBD290E0E7B8033950A347B6C4B3576819EACE75B620BC754E397DD2FE7F2DB886A456C1A80706, deposit_data_root=C4372713009D78A4639C1509BDECA680102658600AD44235BE63688EAC9FCA53 )
                                    • Null: 0x000...002.9547cfe1( )
                                    • Null: 0x000...002.a0ac9d14( )
                                    • Null: 0x000...002.3950a347( )
                                    • Null: 0x000...002.d7124642( )
                                    • Null: 0x000...002.8b6230f9( )
                                    • Null: 0x000...002.00405973( )
                                    • Null: 0x000...002.6e813871( )
                                    • Null: 0x000...002.82ce7138( )
                                    • Null: 0x000...002.8835bc98( )
                                    • Null: 0x000...002.f454368e( )
                                    • Null: 0x000...002.44e74382( )
                                    • Null: 0x000...002.ba6286dd( )
                                    • Null: 0x000...002.00405973( )
                                    • Null: 0x000...002.ccc60fb8( )
                                    • ETH 32 DepositContract.deposit( pubkey=0x82CE713881473857C2E6F42DE9D211D8CEFD08D9B4D1A1DAC534CB6A52986BDEE017B62853548232D55E4153BF1D9FF7, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, signature=0x8835BC988A802516A5255CBF68D8D9E3FC9316223FBA55C346A97CC5319C457A1D9EA6A4623785834303F68019EA8FBF10FC222BC1CE2258402CD9430BB478E2F454368E263EE653FCCA4DBABCE5E45903B0CA512E4BFCF682E578DDF2B6B2A6, deposit_data_root=B81A1078AB6C1B0AD2E3ED8D844E6CED7EB1FBA889DB98868847947C3CD4CB34 )
                                      • Null: 0x000...002.82ce7138( )
                                      • Null: 0x000...002.8835bc98( )
                                      • Null: 0x000...002.f454368e( )
                                      • Null: 0x000...002.44e74382( )
                                      • Null: 0x000...002.ba6286dd( )
                                      • Null: 0x000...002.00405973( )
                                      • Null: 0x000...002.ccc60fb8( )
                                      • Null: 0x000...002.c4372713( )
                                      • Null: 0x000...002.a18ddb47( )
                                      • Null: 0x000...002.84c4feab( )
                                      • Null: 0x000...002.f2bab8dd( )
                                      • Null: 0x000...002.fea9a76e( )
                                      • Null: 0x000...002.6f27b6dc( )
                                      • Null: 0x000...002.00405973( )
                                      • Null: 0x000...002.89490f84( )
                                      • ETH 32 DepositContract.deposit( pubkey=0xA18DDB4746340181D78A91094BF9030F12F8B0E634D21FC12DCD171C64580FBB153B46CD7CA9206F6A6F65CDFCF9C5EC, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, signature=0x84C4FEAB39F3DB0E9FF93CEA72D7642647FC8F23EBC4C3238DA15BBF85D4DBA4BB7F8B05C7212DFBD011B2013953932C149885ABBC230735B01F18139AC1A7C2F2BAB8DD4BCFB1962DDE0DCE0AF4ECAE51F019A5F0098059976840162FD7AA61, deposit_data_root=8FEEDCD78AA91DBD4661608D2CC5B6A61BA0EA38EC8305D97093402625E64044 )
                                        • Null: 0x000...002.a18ddb47( )
                                        • Null: 0x000...002.84c4feab( )
                                        • Null: 0x000...002.f2bab8dd( )
                                        • Null: 0x000...002.fea9a76e( )
                                        • Null: 0x000...002.6f27b6dc( )
                                        • Null: 0x000...002.00405973( )
                                        • Null: 0x000...002.89490f84( )
                                        • Null: 0x000...002.9794738a( )
                                        • Null: 0x000...002.8d7bc56f( )
                                        • Null: 0x000...002.71fccccd( )
                                        • Null: 0x000...002.12a0744b( )
                                        • Null: 0x000...002.53393fdf( )
                                        • Null: 0x000...002.00405973( )
                                        • Null: 0x000...002.9bdd2ba6( )
                                        • ETH 32 DepositContract.deposit( pubkey=0x9794738A1074AE051F121D0EBAAA6420E53E93D5D11B6CE671D1A2A4A7F4A002EB87A60F041F3148D588D2B0C743BA96, withdrawal_credentials=0x009690E5D4472C7C0DBDF490425D89862535D2A52FB686333F3A0A9FF5D2125E, signature=0x8D7BC56FE7F3DEFE9972319C4F7B805D4F7F1E0A1EB5CC9DF3E8E64380215ECC95EC18F92CA3043BC8E9553E9D23A4C303D28453C0D4EBF7BE42CA0D1BA2B6F071FCCCCD57B1FAA095624F5BAF3D15E2E7617C2266BFA6A05B46567CD7C44F72, deposit_data_root=90E2F1B20E999DE988FE3E7B1D8A37FECBF660ADC97C8B798020F9B94A7B97C8 )
                                          • Null: 0x000...002.9794738a( )
                                          • Null: 0x000...002.8d7bc56f( )
                                          • Null: 0x000...002.71fccccd( )
                                          • Null: 0x000...002.12a0744b( )
                                          • Null: 0x000...002.53393fdf( )
                                          • Null: 0x000...002.00405973( )
                                          • Null: 0x000...002.9bdd2ba6( )
                                          • Null: 0x000...002.8feedcd7( )
                                          • Null: 0x000...002.82459a49( )
                                          • Null: 0x000...002.d4b4224d( )
                                          • AppProxyUpgradeable.STATICCALL( )
                                            • KernelProxy.be00bbd8( )
                                              • Kernel.getApp( _namespace=F1F3EB40F5BC1AD1344716CED8B8A0431D840B5783AEA1FD01786BC26F35AC0F, _appId=3CA7C3E38968823CCB4C78EA688DF41356F182AE1D159E4EE608D30D68CEF320 ) => ( 0x20dC62D5904633cC6a5E34bEc87A048E80C92e97 )
                                              • Lido.DELEGATECALL( )
                                              • Keep3rV1.worked( keeper=0x6352f8C749954c9Df198cf72976E48994A77cCE2 )
                                                • Keep3rV2Helper.getQuoteLimit( gasUsed=665206 ) => ( 780219353335772372 )
                                                  • EACAggregatorProxy.STATICCALL( )
                                                    • AccessControlledOffchainAggregator.STATICCALL( )
                                                    • Keep3rV2Oracle.quote( tokenIn=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, amountIn=54051536000000000, tokenOut=0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44, points=1 ) => ( amountOut=650182794446476977, lastUpdatedAgo=882 )
                                                      • UniswapV2Pair.STATICCALL( )
                                                      • Keep3rV1.votes( 0x6352f8C749954c9Df198cf72976E48994A77cCE2 ) => ( 0 )
                                                      • Keep3rV1.bonds( 0x6352f8C749954c9Df198cf72976E48994A77cCE2, 0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44 ) => ( 204925877612047696349 )
                                                      • Keep3rV2Helper.getQuoteLimit( gasUsed=715248 ) => ( 820670549121572212 )
                                                        • EACAggregatorProxy.STATICCALL( )
                                                          • AccessControlledOffchainAggregator.STATICCALL( )
                                                          • Keep3rV2Oracle.quote( tokenIn=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, amountIn=56853888000000000, tokenOut=0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44, points=1 ) => ( amountOut=683892124267976844, lastUpdatedAgo=882 )
                                                            • UniswapV2Pair.STATICCALL( )
                                                            • Keep3rV1.votes( 0x6352f8C749954c9Df198cf72976E48994A77cCE2 ) => ( 0 )
                                                            • Keep3rV1.bonds( 0x6352f8C749954c9Df198cf72976E48994A77cCE2, 0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44 ) => ( 204925877612047696349 )
                                                              File 1 of 14: Vyper_contract
                                                              # @version 0.2.8
                                                              # @title Deposit buffered ether to Lido
                                                              # @license MIT
                                                              # @author banteg
                                                              
                                                              interface Keep3r:
                                                                  def isKeeper(keeper: address) -> bool: nonpayable
                                                                  def worked(keeper: address): nonpayable
                                                              
                                                              
                                                              interface Lido:
                                                                  def isStopped() -> bool: view
                                                                  def getBufferedEther() -> uint256: view
                                                                  def depositBufferedEther(max_deposits: uint256): nonpayable
                                                              
                                                              
                                                              keeper: public(Keep3r)
                                                              lido: public(Lido)
                                                              paused_until: public(uint256)
                                                              DEPOSIT_SIZE: constant(uint256) = 32 * 10 ** 18
                                                              MIN_DEPOSITS: constant(uint256) = 8
                                                              MAX_DEPOSITS: constant(uint256) = 32
                                                              
                                                              
                                                              @external
                                                              def __init__():
                                                                  self.keeper = Keep3r(0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44)
                                                                  self.lido = Lido(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84)
                                                              
                                                              
                                                              @view
                                                              @internal
                                                              def available_deposits() -> uint256:
                                                                  if self.lido.isStopped():
                                                                      return 0
                                                                  if self.paused_until > block.timestamp:
                                                                      return 0
                                                                  return min(self.lido.getBufferedEther() / DEPOSIT_SIZE, MAX_DEPOSITS)
                                                              
                                                              
                                                              @view
                                                              @external
                                                              def workable() -> bool:
                                                                  return self.available_deposits() >= MIN_DEPOSITS
                                                              
                                                              
                                                              @external
                                                              def work():
                                                                  assert self.keeper.isKeeper(msg.sender)  # dev: not keeper
                                                                  deposits: uint256 = self.available_deposits()
                                                                  assert deposits >= MIN_DEPOSITS  # dev: not workable
                                                                  buffered: uint256 = self.lido.getBufferedEther()
                                                                  self.lido.depositBufferedEther(deposits)
                                                                  # pause for a day if there is a key shortage
                                                                  deposited: uint256 = buffered - self.lido.getBufferedEther()
                                                                  if deposited < deposits * DEPOSIT_SIZE:
                                                                      self.paused_until = block.timestamp + 86400
                                                                  self.keeper.worked(msg.sender)

                                                              File 2 of 14: DepositContract
                                                              // ┏━━━┓━┏┓━┏┓━━┏━━━┓━━┏━━━┓━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━┏┓━━━━━┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━━┏┓━
                                                              // ┃┏━━┛┏┛┗┓┃┃━━┃┏━┓┃━━┃┏━┓┃━━━━┗┓┏┓┃━━━━━━━━━━━━━━━━━━┏┛┗┓━━━━┃┏━┓┃━━━━━━━━┏┛┗┓━━━━━━━━━━━━┏┛┗┓
                                                              // ┃┗━━┓┗┓┏┛┃┗━┓┗┛┏┛┃━━┃┃━┃┃━━━━━┃┃┃┃┏━━┓┏━━┓┏━━┓┏━━┓┏┓┗┓┏┛━━━━┃┃━┗┛┏━━┓┏━┓━┗┓┏┛┏━┓┏━━┓━┏━━┓┗┓┏┛
                                                              // ┃┏━━┛━┃┃━┃┏┓┃┏━┛┏┛━━┃┃━┃┃━━━━━┃┃┃┃┃┏┓┃┃┏┓┃┃┏┓┃┃━━┫┣┫━┃┃━━━━━┃┃━┏┓┃┏┓┃┃┏┓┓━┃┃━┃┏┛┗━┓┃━┃┏━┛━┃┃━
                                                              // ┃┗━━┓━┃┗┓┃┃┃┃┃┃┗━┓┏┓┃┗━┛┃━━━━┏┛┗┛┃┃┃━┫┃┗┛┃┃┗┛┃┣━━┃┃┃━┃┗┓━━━━┃┗━┛┃┃┗┛┃┃┃┃┃━┃┗┓┃┃━┃┗┛┗┓┃┗━┓━┃┗┓
                                                              // ┗━━━┛━┗━┛┗┛┗┛┗━━━┛┗┛┗━━━┛━━━━┗━━━┛┗━━┛┃┏━┛┗━━┛┗━━┛┗┛━┗━┛━━━━┗━━━┛┗━━┛┗┛┗┛━┗━┛┗┛━┗━━━┛┗━━┛━┗━┛
                                                              // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                                                              // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┗┛━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                                                              
                                                              // SPDX-License-Identifier: CC0-1.0
                                                              
                                                              pragma solidity 0.6.11;
                                                              
                                                              // This interface is designed to be compatible with the Vyper version.
                                                              /// @notice This is the Ethereum 2.0 deposit contract interface.
                                                              /// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
                                                              interface IDepositContract {
                                                                  /// @notice A processed deposit event.
                                                                  event DepositEvent(
                                                                      bytes pubkey,
                                                                      bytes withdrawal_credentials,
                                                                      bytes amount,
                                                                      bytes signature,
                                                                      bytes index
                                                                  );
                                                              
                                                                  /// @notice Submit a Phase 0 DepositData object.
                                                                  /// @param pubkey A BLS12-381 public key.
                                                                  /// @param withdrawal_credentials Commitment to a public key for withdrawals.
                                                                  /// @param signature A BLS12-381 signature.
                                                                  /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
                                                                  /// Used as a protection against malformed input.
                                                                  function deposit(
                                                                      bytes calldata pubkey,
                                                                      bytes calldata withdrawal_credentials,
                                                                      bytes calldata signature,
                                                                      bytes32 deposit_data_root
                                                                  ) external payable;
                                                              
                                                                  /// @notice Query the current deposit root hash.
                                                                  /// @return The deposit root hash.
                                                                  function get_deposit_root() external view returns (bytes32);
                                                              
                                                                  /// @notice Query the current deposit count.
                                                                  /// @return The deposit count encoded as a little endian 64-bit number.
                                                                  function get_deposit_count() external view returns (bytes memory);
                                                              }
                                                              
                                                              // Based on official specification in https://eips.ethereum.org/EIPS/eip-165
                                                              interface ERC165 {
                                                                  /// @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 pure returns (bool);
                                                              }
                                                              
                                                              // This is a rewrite of the Vyper Eth2.0 deposit contract in Solidity.
                                                              // It tries to stay as close as possible to the original source code.
                                                              /// @notice This is the Ethereum 2.0 deposit contract interface.
                                                              /// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
                                                              contract DepositContract is IDepositContract, ERC165 {
                                                                  uint constant DEPOSIT_CONTRACT_TREE_DEPTH = 32;
                                                                  // NOTE: this also ensures `deposit_count` will fit into 64-bits
                                                                  uint constant MAX_DEPOSIT_COUNT = 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1;
                                                              
                                                                  bytes32[DEPOSIT_CONTRACT_TREE_DEPTH] branch;
                                                                  uint256 deposit_count;
                                                              
                                                                  bytes32[DEPOSIT_CONTRACT_TREE_DEPTH] zero_hashes;
                                                              
                                                                  constructor() public {
                                                                      // Compute hashes in empty sparse Merkle tree
                                                                      for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH - 1; height++)
                                                                          zero_hashes[height + 1] = sha256(abi.encodePacked(zero_hashes[height], zero_hashes[height]));
                                                                  }
                                                              
                                                                  function get_deposit_root() override external view returns (bytes32) {
                                                                      bytes32 node;
                                                                      uint size = deposit_count;
                                                                      for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH; height++) {
                                                                          if ((size & 1) == 1)
                                                                              node = sha256(abi.encodePacked(branch[height], node));
                                                                          else
                                                                              node = sha256(abi.encodePacked(node, zero_hashes[height]));
                                                                          size /= 2;
                                                                      }
                                                                      return sha256(abi.encodePacked(
                                                                          node,
                                                                          to_little_endian_64(uint64(deposit_count)),
                                                                          bytes24(0)
                                                                      ));
                                                                  }
                                                              
                                                                  function get_deposit_count() override external view returns (bytes memory) {
                                                                      return to_little_endian_64(uint64(deposit_count));
                                                                  }
                                                              
                                                                  function deposit(
                                                                      bytes calldata pubkey,
                                                                      bytes calldata withdrawal_credentials,
                                                                      bytes calldata signature,
                                                                      bytes32 deposit_data_root
                                                                  ) override external payable {
                                                                      // Extended ABI length checks since dynamic types are used.
                                                                      require(pubkey.length == 48, "DepositContract: invalid pubkey length");
                                                                      require(withdrawal_credentials.length == 32, "DepositContract: invalid withdrawal_credentials length");
                                                                      require(signature.length == 96, "DepositContract: invalid signature length");
                                                              
                                                                      // Check deposit amount
                                                                      require(msg.value >= 1 ether, "DepositContract: deposit value too low");
                                                                      require(msg.value % 1 gwei == 0, "DepositContract: deposit value not multiple of gwei");
                                                                      uint deposit_amount = msg.value / 1 gwei;
                                                                      require(deposit_amount <= type(uint64).max, "DepositContract: deposit value too high");
                                                              
                                                                      // Emit `DepositEvent` log
                                                                      bytes memory amount = to_little_endian_64(uint64(deposit_amount));
                                                                      emit DepositEvent(
                                                                          pubkey,
                                                                          withdrawal_credentials,
                                                                          amount,
                                                                          signature,
                                                                          to_little_endian_64(uint64(deposit_count))
                                                                      );
                                                              
                                                                      // Compute deposit data root (`DepositData` hash tree root)
                                                                      bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, bytes16(0)));
                                                                      bytes32 signature_root = sha256(abi.encodePacked(
                                                                          sha256(abi.encodePacked(signature[:64])),
                                                                          sha256(abi.encodePacked(signature[64:], bytes32(0)))
                                                                      ));
                                                                      bytes32 node = sha256(abi.encodePacked(
                                                                          sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)),
                                                                          sha256(abi.encodePacked(amount, bytes24(0), signature_root))
                                                                      ));
                                                              
                                                                      // Verify computed and expected deposit data roots match
                                                                      require(node == deposit_data_root, "DepositContract: reconstructed DepositData does not match supplied deposit_data_root");
                                                              
                                                                      // Avoid overflowing the Merkle tree (and prevent edge case in computing `branch`)
                                                                      require(deposit_count < MAX_DEPOSIT_COUNT, "DepositContract: merkle tree full");
                                                              
                                                                      // Add deposit data root to Merkle tree (update a single `branch` node)
                                                                      deposit_count += 1;
                                                                      uint size = deposit_count;
                                                                      for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH; height++) {
                                                                          if ((size & 1) == 1) {
                                                                              branch[height] = node;
                                                                              return;
                                                                          }
                                                                          node = sha256(abi.encodePacked(branch[height], node));
                                                                          size /= 2;
                                                                      }
                                                                      // As the loop should always end prematurely with the `return` statement,
                                                                      // this code should be unreachable. We assert `false` just to be safe.
                                                                      assert(false);
                                                                  }
                                                              
                                                                  function supportsInterface(bytes4 interfaceId) override external pure returns (bool) {
                                                                      return interfaceId == type(ERC165).interfaceId || interfaceId == type(IDepositContract).interfaceId;
                                                                  }
                                                              
                                                                  function to_little_endian_64(uint64 value) internal pure returns (bytes memory ret) {
                                                                      ret = new bytes(8);
                                                                      bytes8 bytesValue = bytes8(value);
                                                                      // Byteswapping during copying to bytes.
                                                                      ret[0] = bytesValue[7];
                                                                      ret[1] = bytesValue[6];
                                                                      ret[2] = bytesValue[5];
                                                                      ret[3] = bytesValue[4];
                                                                      ret[4] = bytesValue[3];
                                                                      ret[5] = bytesValue[2];
                                                                      ret[6] = bytesValue[1];
                                                                      ret[7] = bytesValue[0];
                                                                  }
                                                              }

                                                              File 3 of 14: AppProxyUpgradeable
                                                              // File: contracts/common/UnstructuredStorage.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              library UnstructuredStorage {
                                                                  function getStorageBool(bytes32 position) internal view returns (bool data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageAddress(bytes32 position) internal view returns (address data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function setStorageBool(bytes32 position, bool data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageAddress(bytes32 position, address data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageBytes32(bytes32 position, bytes32 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageUint256(bytes32 position, uint256 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/acl/IACL.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IACL {
                                                                  function initialize(address permissionsCreator) external;
                                                              
                                                                  // TODO: this should be external
                                                                  // See https://github.com/ethereum/solidity/issues/4832
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              }
                                                              
                                                              // File: contracts/common/IVaultRecoverable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IVaultRecoverable {
                                                                  event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                                                              
                                                                  function transferToVault(address token) external;
                                                              
                                                                  function allowRecoverability(address token) external view returns (bool);
                                                                  function getRecoveryVault() external view returns (address);
                                                              }
                                                              
                                                              // File: contracts/kernel/IKernel.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              interface IKernelEvents {
                                                                  event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                                                              }
                                                              
                                                              
                                                              // This should be an interface, but interfaces can't inherit yet :(
                                                              contract IKernel is IKernelEvents, IVaultRecoverable {
                                                                  function acl() public view returns (IACL);
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              
                                                                  function setApp(bytes32 namespace, bytes32 appId, address app) public;
                                                                  function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                                                              }
                                                              
                                                              // File: contracts/apps/AppStorage.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract AppStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
                                                                  bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
                                                                  */
                                                                  bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
                                                                  bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
                                                              
                                                                  function kernel() public view returns (IKernel) {
                                                                      return IKernel(KERNEL_POSITION.getStorageAddress());
                                                                  }
                                                              
                                                                  function appId() public view returns (bytes32) {
                                                                      return APP_ID_POSITION.getStorageBytes32();
                                                                  }
                                                              
                                                                  function setKernel(IKernel _kernel) internal {
                                                                      KERNEL_POSITION.setStorageAddress(address(_kernel));
                                                                  }
                                                              
                                                                  function setAppId(bytes32 _appId) internal {
                                                                      APP_ID_POSITION.setStorageBytes32(_appId);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/IsContract.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract IsContract {
                                                                  /*
                                                                  * NOTE: this should NEVER be used for authentication
                                                                  * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                                                                  *
                                                                  * This is only intended to be used as a sanity check that an address is actually a contract,
                                                                  * RATHER THAN an address not being a contract.
                                                                  */
                                                                  function isContract(address _target) internal view returns (bool) {
                                                                      if (_target == address(0)) {
                                                                          return false;
                                                                      }
                                                              
                                                                      uint256 size;
                                                                      assembly { size := extcodesize(_target) }
                                                                      return size > 0;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/lib/misc/ERCProxy.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract ERCProxy {
                                                                  uint256 internal constant FORWARDING = 1;
                                                                  uint256 internal constant UPGRADEABLE = 2;
                                                              
                                                                  function proxyType() public pure returns (uint256 proxyTypeId);
                                                                  function implementation() public view returns (address codeAddr);
                                                              }
                                                              
                                                              // File: contracts/common/DelegateProxy.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract DelegateProxy is ERCProxy, IsContract {
                                                                  uint256 internal constant FWD_GAS_LIMIT = 10000;
                                                              
                                                                  /**
                                                                  * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
                                                                  * @param _dst Destination address to perform the delegatecall
                                                                  * @param _calldata Calldata for the delegatecall
                                                                  */
                                                                  function delegatedFwd(address _dst, bytes _calldata) internal {
                                                                      require(isContract(_dst));
                                                                      uint256 fwdGasLimit = FWD_GAS_LIMIT;
                                                              
                                                                      assembly {
                                                                          let result := delegatecall(sub(gas, fwdGasLimit), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
                                                                          let size := returndatasize
                                                                          let ptr := mload(0x40)
                                                                          returndatacopy(ptr, 0, size)
                                                              
                                                                          // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
                                                                          // if the call returned error data, forward it
                                                                          switch result case 0 { revert(ptr, size) }
                                                                          default { return(ptr, size) }
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/DepositableStorage.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              contract DepositableStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  // keccak256("aragonOS.depositableStorage.depositable")
                                                                  bytes32 internal constant DEPOSITABLE_POSITION = 0x665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea;
                                                              
                                                                  function isDepositable() public view returns (bool) {
                                                                      return DEPOSITABLE_POSITION.getStorageBool();
                                                                  }
                                                              
                                                                  function setDepositable(bool _depositable) internal {
                                                                      DEPOSITABLE_POSITION.setStorageBool(_depositable);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/DepositableDelegateProxy.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract DepositableDelegateProxy is DepositableStorage, DelegateProxy {
                                                                  event ProxyDeposit(address sender, uint256 value);
                                                              
                                                                  function () external payable {
                                                                      uint256 forwardGasThreshold = FWD_GAS_LIMIT;
                                                                      bytes32 isDepositablePosition = DEPOSITABLE_POSITION;
                                                              
                                                                      // Optimized assembly implementation to prevent EIP-1884 from breaking deposits, reference code in Solidity:
                                                                      // https://github.com/aragon/aragonOS/blob/v4.2.1/contracts/common/DepositableDelegateProxy.sol#L10-L20
                                                                      assembly {
                                                                          // Continue only if the gas left is lower than the threshold for forwarding to the implementation code,
                                                                          // otherwise continue outside of the assembly block.
                                                                          if lt(gas, forwardGasThreshold) {
                                                                              // Only accept the deposit and emit an event if all of the following are true:
                                                                              // the proxy accepts deposits (isDepositable), msg.data.length == 0, and msg.value > 0
                                                                              if and(and(sload(isDepositablePosition), iszero(calldatasize)), gt(callvalue, 0)) {
                                                                                  // Equivalent Solidity code for emitting the event:
                                                                                  // emit ProxyDeposit(msg.sender, msg.value);
                                                              
                                                                                  let logData := mload(0x40) // free memory pointer
                                                                                  mstore(logData, caller) // add 'msg.sender' to the log data (first event param)
                                                                                  mstore(add(logData, 0x20), callvalue) // add 'msg.value' to the log data (second event param)
                                                              
                                                                                  // Emit an event with one topic to identify the event: keccak256('ProxyDeposit(address,uint256)') = 0x15ee...dee1
                                                                                  log1(logData, 0x40, 0x15eeaa57c7bd188c1388020bcadc2c436ec60d647d36ef5b9eb3c742217ddee1)
                                                              
                                                                                  stop() // Stop. Exits execution context
                                                                              }
                                                              
                                                                              // If any of above checks failed, revert the execution (if ETH was sent, it is returned to the sender)
                                                                              revert(0, 0)
                                                                          }
                                                                      }
                                                              
                                                                      address target = implementation();
                                                                      delegatedFwd(target, msg.data);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/kernel/KernelConstants.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract KernelAppIds {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                                                              }
                                                              
                                                              
                                                              contract KernelNamespaceConstants {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyBase.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract AppProxyBase is AppStorage, DepositableDelegateProxy, KernelNamespaceConstants {
                                                                  /**
                                                                  * @dev Initialize AppProxy
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public {
                                                                      setKernel(_kernel);
                                                                      setAppId(_appId);
                                                              
                                                                      // Implicit check that kernel is actually a Kernel
                                                                      // The EVM doesn't actually provide a way for us to make sure, but we can force a revert to
                                                                      // occur if the kernel is set to 0x0 or a non-code address when we try to call a method on
                                                                      // it.
                                                                      address appCode = getAppBase(_appId);
                                                              
                                                                      // If initialize payload is provided, it will be executed
                                                                      if (_initializePayload.length > 0) {
                                                                          require(isContract(appCode));
                                                                          // Cannot make delegatecall as a delegateproxy.delegatedFwd as it
                                                                          // returns ending execution context and halts contract deployment
                                                                          require(appCode.delegatecall(_initializePayload));
                                                                      }
                                                                  }
                                                              
                                                                  function getAppBase(bytes32 _appId) internal view returns (address) {
                                                                      return kernel().getApp(KERNEL_APP_BASES_NAMESPACE, _appId);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyUpgradeable.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              contract AppProxyUpgradeable is AppProxyBase {
                                                                  /**
                                                                  * @dev Initialize AppProxyUpgradeable (makes it an upgradeable Aragon app)
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload)
                                                                      AppProxyBase(_kernel, _appId, _initializePayload)
                                                                      public // solium-disable-line visibility-first
                                                                  {
                                                                      // solium-disable-previous-line no-empty-blocks
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, the address the proxy would delegate calls to
                                                                   */
                                                                  function implementation() public view returns (address) {
                                                                      return getAppBase(appId());
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                                                                   */
                                                                  function proxyType() public pure returns (uint256 proxyTypeId) {
                                                                      return UPGRADEABLE;
                                                                  }
                                                              }

                                                              File 4 of 14: Keep3rV1
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.6.12;
                                                              
                                                              // From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol
                                                              // Subject to the MIT license.
                                                              
                                                              /**
                                                               * @dev Wrappers over Solidity's arithmetic operations with added overflow
                                                               * checks.
                                                               *
                                                               * Arithmetic operations in Solidity wrap on overflow. This can easily result
                                                               * in bugs, because programmers usually assume that an overflow raises an
                                                               * error, which is the standard behavior in high level programming languages.
                                                               * `SafeMath` restores this intuition by reverting the transaction when an
                                                               * operation overflows.
                                                               *
                                                               * Using this library instead of the unchecked operations eliminates an entire
                                                               * class of bugs, so it's recommended to use it always.
                                                               */
                                                              library SafeMath {
                                                                  /**
                                                                   * @dev Returns the addition of two unsigned integers, reverting on overflow.
                                                                   *
                                                                   * Counterpart to Solidity's `+` operator.
                                                                   *
                                                                   * Requirements:
                                                                   * - Addition cannot overflow.
                                                                   */
                                                                  function add(uint a, uint b) internal pure returns (uint) {
                                                                      uint c = a + b;
                                                                      require(c >= a, "add: +");
                                                              
                                                                      return c;
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.
                                                                   *
                                                                   * Counterpart to Solidity's `+` operator.
                                                                   *
                                                                   * Requirements:
                                                                   * - Addition cannot overflow.
                                                                   */
                                                                  function add(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
                                                                      uint c = a + b;
                                                                      require(c >= a, errorMessage);
                                                              
                                                                      return c;
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).
                                                                   *
                                                                   * Counterpart to Solidity's `-` operator.
                                                                   *
                                                                   * Requirements:
                                                                   * - Subtraction cannot underflow.
                                                                   */
                                                                  function sub(uint a, uint b) internal pure returns (uint) {
                                                                      return sub(a, b, "sub: -");
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).
                                                                   *
                                                                   * Counterpart to Solidity's `-` operator.
                                                                   *
                                                                   * Requirements:
                                                                   * - Subtraction cannot underflow.
                                                                   */
                                                                  function sub(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
                                                                      require(b <= a, errorMessage);
                                                                      uint c = a - b;
                                                              
                                                                      return c;
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Returns the multiplication of two unsigned integers, reverting on overflow.
                                                                   *
                                                                   * Counterpart to Solidity's `*` operator.
                                                                   *
                                                                   * Requirements:
                                                                   * - Multiplication cannot overflow.
                                                                   */
                                                                  function mul(uint a, uint b) internal pure returns (uint) {
                                                                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                                                                      // benefit is lost if 'b' is also tested.
                                                                      // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                                                                      if (a == 0) {
                                                                          return 0;
                                                                      }
                                                              
                                                                      uint c = a * b;
                                                                      require(c / a == b, "mul: *");
                                                              
                                                                      return c;
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Returns the multiplication of two unsigned integers, reverting on overflow.
                                                                   *
                                                                   * Counterpart to Solidity's `*` operator.
                                                                   *
                                                                   * Requirements:
                                                                   * - Multiplication cannot overflow.
                                                                   */
                                                                  function mul(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
                                                                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                                                                      // benefit is lost if 'b' is also tested.
                                                                      // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                                                                      if (a == 0) {
                                                                          return 0;
                                                                      }
                                                              
                                                                      uint c = a * b;
                                                                      require(c / a == b, errorMessage);
                                                              
                                                                      return c;
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Returns the integer division of two unsigned integers.
                                                                   * Reverts on division by zero. The result is rounded towards zero.
                                                                   *
                                                                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                                                                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                                                                   * uses an invalid opcode to revert (consuming all remaining gas).
                                                                   *
                                                                   * Requirements:
                                                                   * - The divisor cannot be zero.
                                                                   */
                                                                  function div(uint a, uint b) internal pure returns (uint) {
                                                                      return div(a, b, "div: /");
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Returns the integer division of two unsigned integers.
                                                                   * Reverts with custom message on division by zero. The result is rounded towards zero.
                                                                   *
                                                                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                                                                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                                                                   * uses an invalid opcode to revert (consuming all remaining gas).
                                                                   *
                                                                   * Requirements:
                                                                   * - The divisor cannot be zero.
                                                                   */
                                                                  function div(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
                                                                      // Solidity only automatically asserts when dividing by 0
                                                                      require(b > 0, errorMessage);
                                                                      uint c = a / b;
                                                                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                                                              
                                                                      return c;
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                                                                   * Reverts when dividing by zero.
                                                                   *
                                                                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                                                                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                                                                   * invalid opcode to revert (consuming all remaining gas).
                                                                   *
                                                                   * Requirements:
                                                                   * - The divisor cannot be zero.
                                                                   */
                                                                  function mod(uint a, uint b) internal pure returns (uint) {
                                                                      return mod(a, b, "mod: %");
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                                                                   * Reverts with custom message when dividing by zero.
                                                                   *
                                                                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                                                                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                                                                   * invalid opcode to revert (consuming all remaining gas).
                                                                   *
                                                                   * Requirements:
                                                                   * - The divisor cannot be zero.
                                                                   */
                                                                  function mod(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
                                                                      require(b != 0, errorMessage);
                                                                      return a % b;
                                                                  }
                                                              }
                                                              
                                                              /**
                                                               * @dev Contract module that helps prevent reentrant calls to a function.
                                                               *
                                                               * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
                                                               * available, which can be applied to functions to make sure there are no nested
                                                               * (reentrant) calls to them.
                                                               *
                                                               * Note that because there is a single `nonReentrant` guard, functions marked as
                                                               * `nonReentrant` may not call one another. This can be worked around by making
                                                               * those functions `private`, and then adding `external` `nonReentrant` entry
                                                               * points to them.
                                                               *
                                                               * TIP: If you would like to learn more about reentrancy and alternative ways
                                                               * to protect against it, check out our blog post
                                                               * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
                                                               */
                                                              contract ReentrancyGuard {
                                                                  // Booleans are more expensive than uint256 or any type that takes up a full
                                                                  // word because each write operation emits an extra SLOAD to first read the
                                                                  // slot's contents, replace the bits taken up by the boolean, and then write
                                                                  // back. This is the compiler's defense against contract upgrades and
                                                                  // pointer aliasing, and it cannot be disabled.
                                                              
                                                                  // The values being non-zero value makes deployment a bit more expensive,
                                                                  // but in exchange the refund on every call to nonReentrant will be lower in
                                                                  // amount. Since refunds are capped to a percentage of the total
                                                                  // transaction's gas, it is best to keep them low in cases like this one, to
                                                                  // increase the likelihood of the full refund coming into effect.
                                                                  uint256 private constant _NOT_ENTERED = 1;
                                                                  uint256 private constant _ENTERED = 2;
                                                              
                                                                  uint256 private _status;
                                                              
                                                                  constructor () internal {
                                                                      _status = _NOT_ENTERED;
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Prevents a contract from calling itself, directly or indirectly.
                                                                   * Calling a `nonReentrant` function from another `nonReentrant`
                                                                   * function is not supported. It is possible to prevent this from happening
                                                                   * by making the `nonReentrant` function external, and make it call a
                                                                   * `private` function that does the actual work.
                                                                   */
                                                                  modifier nonReentrant() {
                                                                      // On the first call to nonReentrant, _notEntered will be true
                                                                      require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                                                              
                                                                      // Any calls to nonReentrant after this point will fail
                                                                      _status = _ENTERED;
                                                              
                                                                      _;
                                                              
                                                                      // By storing the original value once again, a refund is triggered (see
                                                                      // https://eips.ethereum.org/EIPS/eip-2200)
                                                                      _status = _NOT_ENTERED;
                                                                  }
                                                              }
                                                              
                                                              /**
                                                               * @dev Interface of the ERC20 standard as defined in the EIP.
                                                               */
                                                              interface IERC20 {
                                                                  /**
                                                                   * @dev Returns the amount of tokens in existence.
                                                                   */
                                                                  function totalSupply() external view returns (uint256);
                                                              
                                                                  /**
                                                                   * @dev Returns the amount of tokens owned by `account`.
                                                                   */
                                                                  function balanceOf(address account) external view returns (uint256);
                                                              
                                                                  /**
                                                                   * @dev Moves `amount` tokens from the caller's account to `recipient`.
                                                                   *
                                                                   * Returns a boolean value indicating whether the operation succeeded.
                                                                   *
                                                                   * Emits a {Transfer} event.
                                                                   */
                                                                  function transfer(address recipient, uint256 amount) external returns (bool);
                                                              
                                                                  /**
                                                                   * @dev Returns the remaining number of tokens that `spender` will be
                                                                   * allowed to spend on behalf of `owner` through {transferFrom}. This is
                                                                   * zero by default.
                                                                   *
                                                                   * This value changes when {approve} or {transferFrom} are called.
                                                                   */
                                                                  function allowance(address owner, address spender) external view returns (uint256);
                                                              
                                                                  /**
                                                                   * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                                                                   *
                                                                   * Returns a boolean value indicating whether the operation succeeded.
                                                                   *
                                                                   * IMPORTANT: Beware that changing an allowance with this method brings the risk
                                                                   * that someone may use both the old and the new allowance by unfortunate
                                                                   * transaction ordering. One possible solution to mitigate this race
                                                                   * condition is to first reduce the spender's allowance to 0 and set the
                                                                   * desired value afterwards:
                                                                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                                                                   *
                                                                   * Emits an {Approval} event.
                                                                   */
                                                                  function approve(address spender, uint256 amount) external returns (bool);
                                                              
                                                                  /**
                                                                   * @dev Moves `amount` tokens from `sender` to `recipient` using the
                                                                   * allowance mechanism. `amount` is then deducted from the caller's
                                                                   * allowance.
                                                                   *
                                                                   * Returns a boolean value indicating whether the operation succeeded.
                                                                   *
                                                                   * Emits a {Transfer} event.
                                                                   */
                                                                  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
                                                              
                                                                  /**
                                                                   * @dev Emitted when `value` tokens are moved from one account (`from`) to
                                                                   * another (`to`).
                                                                   *
                                                                   * Note that `value` may be zero.
                                                                   */
                                                                  event Transfer(address indexed from, address indexed to, uint256 value);
                                                              
                                                                  /**
                                                                   * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                                                                   * a call to {approve}. `value` is the new allowance.
                                                                   */
                                                                  event Approval(address indexed owner, address indexed spender, uint256 value);
                                                              }
                                                              
                                                              /**
                                                               * @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) {
                                                                      // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
                                                                      // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
                                                                      // for accounts without code, i.e. `keccak256('')`
                                                                      bytes32 codehash;
                                                                      bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                                                                      // solhint-disable-next-line no-inline-assembly
                                                                      assembly { codehash := extcodehash(account) }
                                                                      return (codehash != accountHash && codehash != 0x0);
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev Converts an `address` into `address payable`. Note that this is
                                                                   * simply a type cast: the actual underlying value is not changed.
                                                                   *
                                                                   * _Available since v2.4.0._
                                                                   */
                                                                  function toPayable(address account) internal pure returns (address payable) {
                                                                      return address(uint160(account));
                                                                  }
                                                              
                                                                  /**
                                                                   * @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].
                                                                   *
                                                                   * _Available since v2.4.0._
                                                                   */
                                                                  function sendValue(address payable recipient, uint256 amount) internal {
                                                                      require(address(this).balance >= amount, "Address: insufficient");
                                                              
                                                                      // solhint-disable-next-line avoid-call-value
                                                                      (bool success, ) = recipient.call{value:amount}("");
                                                                      require(success, "Address: reverted");
                                                                  }
                                                              }
                                                              
                                                              /**
                                                               * @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 ERC20;` statement to your contract,
                                                               * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
                                                               */
                                                              library SafeERC20 {
                                                                  using SafeMath for uint256;
                                                                  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));
                                                                  }
                                                              
                                                                  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'
                                                                      // solhint-disable-next-line max-line-length
                                                                      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).add(value);
                                                                      callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                                                                  }
                                                              
                                                                  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                                                                      uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: < 0");
                                                                      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.
                                                              
                                                                      // A Solidity high level call has three parts:
                                                                      //  1. The target address is checked to verify it contains contract code
                                                                      //  2. The call itself is made, and success asserted
                                                                      //  3. The return value is decoded, which in turn checks the size of the returned data.
                                                                      // solhint-disable-next-line max-line-length
                                                                      require(address(token).isContract(), "SafeERC20: !contract");
                                                              
                                                                      // solhint-disable-next-line avoid-low-level-calls
                                                                      (bool success, bytes memory returndata) = address(token).call(data);
                                                                      require(success, "SafeERC20: low-level call failed");
                                                              
                                                                      if (returndata.length > 0) { // Return data is optional
                                                                          // solhint-disable-next-line max-line-length
                                                                          require(abi.decode(returndata, (bool)), "SafeERC20: !succeed");
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              library Keep3rV1Library {
                                                                  function getReserve(address pair, address reserve) external view returns (uint) {
                                                                      (uint _r0, uint _r1,) = IUniswapV2Pair(pair).getReserves();
                                                                      if (IUniswapV2Pair(pair).token0() == reserve) {
                                                                          return _r0;
                                                                      } else if (IUniswapV2Pair(pair).token1() == reserve) {
                                                                          return _r1;
                                                                      } else {
                                                                          return 0;
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              interface IUniswapV2Pair {
                                                                  event Approval(address indexed owner, address indexed spender, uint value);
                                                                  event Transfer(address indexed from, address indexed to, uint value);
                                                              
                                                                  function name() external pure returns (string memory);
                                                                  function symbol() external pure returns (string memory);
                                                                  function decimals() external pure returns (uint8);
                                                                  function totalSupply() external view returns (uint);
                                                                  function balanceOf(address owner) external view returns (uint);
                                                                  function allowance(address owner, address spender) external view returns (uint);
                                                              
                                                                  function approve(address spender, uint value) external returns (bool);
                                                                  function transfer(address to, uint value) external returns (bool);
                                                                  function transferFrom(address from, address to, uint value) external returns (bool);
                                                              
                                                                  function DOMAIN_SEPARATOR() external view returns (bytes32);
                                                                  function PERMIT_TYPEHASH() external pure returns (bytes32);
                                                                  function nonces(address owner) external view returns (uint);
                                                              
                                                                  function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
                                                              
                                                                  event Mint(address indexed sender, uint amount0, uint amount1);
                                                                  event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
                                                                  event Swap(
                                                                      address indexed sender,
                                                                      uint amount0In,
                                                                      uint amount1In,
                                                                      uint amount0Out,
                                                                      uint amount1Out,
                                                                      address indexed to
                                                                  );
                                                                  event Sync(uint112 reserve0, uint112 reserve1);
                                                              
                                                                  function MINIMUM_LIQUIDITY() external pure returns (uint);
                                                                  function factory() external view returns (address);
                                                                  function token0() external view returns (address);
                                                                  function token1() external view returns (address);
                                                                  function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
                                                                  function price0CumulativeLast() external view returns (uint);
                                                                  function price1CumulativeLast() external view returns (uint);
                                                                  function kLast() external view returns (uint);
                                                              
                                                                  function mint(address to) external returns (uint liquidity);
                                                                  function burn(address to) external returns (uint amount0, uint amount1);
                                                                  function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
                                                                  function skim(address to) external;
                                                                  function sync() external;
                                                              
                                                                  function initialize(address, address) external;
                                                              }
                                                              
                                                              interface IGovernance {
                                                                  function proposeJob(address job) external;
                                                              }
                                                              
                                                              interface IKeep3rV1Helper {
                                                                  function getQuoteLimit(uint gasUsed) external view returns (uint);
                                                              }
                                                              
                                                              contract Keep3rV1 is ReentrancyGuard {
                                                                  using SafeMath for uint;
                                                                  using SafeERC20 for IERC20;
                                                              
                                                                  /// @notice Keep3r Helper to set max prices for the ecosystem
                                                                  IKeep3rV1Helper public KPRH;
                                                              
                                                                  /// @notice EIP-20 token name for this token
                                                                  string public constant name = "Keep3rV1";
                                                              
                                                                  /// @notice EIP-20 token symbol for this token
                                                                  string public constant symbol = "KP3R";
                                                              
                                                                  /// @notice EIP-20 token decimals for this token
                                                                  uint8 public constant decimals = 18;
                                                              
                                                                  /// @notice Total number of tokens in circulation
                                                                  uint public totalSupply = 0; // Initial 0
                                                              
                                                                  /// @notice A record of each accounts delegate
                                                                  mapping (address => address) public delegates;
                                                              
                                                                  /// @notice A record of votes checkpoints for each account, by index
                                                                  mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
                                                              
                                                                  /// @notice The number of checkpoints for each account
                                                                  mapping (address => uint32) public numCheckpoints;
                                                              
                                                                  mapping (address => mapping (address => uint)) internal allowances;
                                                                  mapping (address => uint) internal balances;
                                                              
                                                                  /// @notice The EIP-712 typehash for the contract's domain
                                                                  bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint chainId,address verifyingContract)");
                                                                  bytes32 public immutable DOMAINSEPARATOR;
                                                              
                                                                  /// @notice The EIP-712 typehash for the delegation struct used by the contract
                                                                  bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint nonce,uint expiry)");
                                                              
                                                                  /// @notice The EIP-712 typehash for the permit struct used by the contract
                                                                  bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint value,uint nonce,uint deadline)");
                                                              
                                                              
                                                                  /// @notice A record of states for signing / validating signatures
                                                                  mapping (address => uint) public nonces;
                                                              
                                                                  /// @notice An event thats emitted when an account changes its delegate
                                                                  event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
                                                              
                                                                  /// @notice An event thats emitted when a delegate account's vote balance changes
                                                                  event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
                                                              
                                                                  /// @notice A checkpoint for marking number of votes from a given block
                                                                  struct Checkpoint {
                                                                      uint32 fromBlock;
                                                                      uint votes;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Delegate votes from `msg.sender` to `delegatee`
                                                                   * @param delegatee The address to delegate votes to
                                                                   */
                                                                  function delegate(address delegatee) public {
                                                                      _delegate(msg.sender, delegatee);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Delegates votes from signatory to `delegatee`
                                                                   * @param delegatee The address to delegate votes to
                                                                   * @param nonce The contract state required to match the signature
                                                                   * @param expiry The time at which to expire the signature
                                                                   * @param v The recovery byte of the signature
                                                                   * @param r Half of the ECDSA signature pair
                                                                   * @param s Half of the ECDSA signature pair
                                                                   */
                                                                  function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public {
                                                                      bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
                                                                      bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAINSEPARATOR, structHash));
                                                                      address signatory = ecrecover(digest, v, r, s);
                                                                      require(signatory != address(0), "delegateBySig: sig");
                                                                      require(nonce == nonces[signatory]++, "delegateBySig: nonce");
                                                                      require(now <= expiry, "delegateBySig: expired");
                                                                      _delegate(signatory, delegatee);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Gets the current votes balance for `account`
                                                                   * @param account The address to get votes balance
                                                                   * @return The number of current votes for `account`
                                                                   */
                                                                  function getCurrentVotes(address account) external view returns (uint) {
                                                                      uint32 nCheckpoints = numCheckpoints[account];
                                                                      return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Determine the prior number of votes for an account as of a block number
                                                                   * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
                                                                   * @param account The address of the account to check
                                                                   * @param blockNumber The block number to get the vote balance at
                                                                   * @return The number of votes the account had as of the given block
                                                                   */
                                                                  function getPriorVotes(address account, uint blockNumber) public view returns (uint) {
                                                                      require(blockNumber < block.number, "getPriorVotes:");
                                                              
                                                                      uint32 nCheckpoints = numCheckpoints[account];
                                                                      if (nCheckpoints == 0) {
                                                                          return 0;
                                                                      }
                                                              
                                                                      // First check most recent balance
                                                                      if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
                                                                          return checkpoints[account][nCheckpoints - 1].votes;
                                                                      }
                                                              
                                                                      // Next check implicit zero balance
                                                                      if (checkpoints[account][0].fromBlock > blockNumber) {
                                                                          return 0;
                                                                      }
                                                              
                                                                      uint32 lower = 0;
                                                                      uint32 upper = nCheckpoints - 1;
                                                                      while (upper > lower) {
                                                                          uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
                                                                          Checkpoint memory cp = checkpoints[account][center];
                                                                          if (cp.fromBlock == blockNumber) {
                                                                              return cp.votes;
                                                                          } else if (cp.fromBlock < blockNumber) {
                                                                              lower = center;
                                                                          } else {
                                                                              upper = center - 1;
                                                                          }
                                                                      }
                                                                      return checkpoints[account][lower].votes;
                                                                  }
                                                              
                                                                  function _delegate(address delegator, address delegatee) internal {
                                                                      address currentDelegate = delegates[delegator];
                                                                      uint delegatorBalance = votes[delegator].add(bonds[delegator][address(this)]);
                                                                      delegates[delegator] = delegatee;
                                                              
                                                                      emit DelegateChanged(delegator, currentDelegate, delegatee);
                                                              
                                                                      _moveDelegates(currentDelegate, delegatee, delegatorBalance);
                                                                  }
                                                              
                                                                  function _moveDelegates(address srcRep, address dstRep, uint amount) internal {
                                                                      if (srcRep != dstRep && amount > 0) {
                                                                          if (srcRep != address(0)) {
                                                                              uint32 srcRepNum = numCheckpoints[srcRep];
                                                                              uint srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                                                                              uint srcRepNew = srcRepOld.sub(amount, "_moveVotes: underflows");
                                                                              _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
                                                                          }
                                                              
                                                                          if (dstRep != address(0)) {
                                                                              uint32 dstRepNum = numCheckpoints[dstRep];
                                                                              uint dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                                                                              uint dstRepNew = dstRepOld.add(amount);
                                                                              _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
                                                                          }
                                                                      }
                                                                  }
                                                              
                                                                  function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint oldVotes, uint newVotes) internal {
                                                                    uint32 blockNumber = safe32(block.number, "_writeCheckpoint: 32 bits");
                                                              
                                                                    if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
                                                                        checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
                                                                    } else {
                                                                        checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
                                                                        numCheckpoints[delegatee] = nCheckpoints + 1;
                                                                    }
                                                              
                                                                    emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
                                                                  }
                                                              
                                                                  function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
                                                                      require(n < 2**32, errorMessage);
                                                                      return uint32(n);
                                                                  }
                                                              
                                                                  /// @notice The standard EIP-20 transfer event
                                                                  event Transfer(address indexed from, address indexed to, uint amount);
                                                              
                                                                  /// @notice The standard EIP-20 approval event
                                                                  event Approval(address indexed owner, address indexed spender, uint amount);
                                                              
                                                                  /// @notice Submit a job
                                                                  event SubmitJob(address indexed job, address indexed liquidity, address indexed provider, uint block, uint credit);
                                                              
                                                                  /// @notice Apply credit to a job
                                                                  event ApplyCredit(address indexed job, address indexed liquidity, address indexed provider, uint block, uint credit);
                                                              
                                                                  /// @notice Remove credit for a job
                                                                  event RemoveJob(address indexed job, address indexed liquidity, address indexed provider, uint block, uint credit);
                                                              
                                                                  /// @notice Unbond credit for a job
                                                                  event UnbondJob(address indexed job, address indexed liquidity, address indexed provider, uint block, uint credit);
                                                              
                                                                  /// @notice Added a Job
                                                                  event JobAdded(address indexed job, uint block, address governance);
                                                              
                                                                  /// @notice Removed a job
                                                                  event JobRemoved(address indexed job, uint block, address governance);
                                                              
                                                                  /// @notice Worked a job
                                                                  event KeeperWorked(address indexed credit, address indexed job, address indexed keeper, uint block, uint amount);
                                                              
                                                                  /// @notice Keeper bonding
                                                                  event KeeperBonding(address indexed keeper, uint block, uint active, uint bond);
                                                              
                                                                  /// @notice Keeper bonded
                                                                  event KeeperBonded(address indexed keeper, uint block, uint activated, uint bond);
                                                              
                                                                  /// @notice Keeper unbonding
                                                                  event KeeperUnbonding(address indexed keeper, uint block, uint deactive, uint bond);
                                                              
                                                                  /// @notice Keeper unbound
                                                                  event KeeperUnbound(address indexed keeper, uint block, uint deactivated, uint bond);
                                                              
                                                                  /// @notice Keeper slashed
                                                                  event KeeperSlashed(address indexed keeper, address indexed slasher, uint block, uint slash);
                                                              
                                                                  /// @notice Keeper disputed
                                                                  event KeeperDispute(address indexed keeper, uint block);
                                                              
                                                                  /// @notice Keeper resolved
                                                                  event KeeperResolved(address indexed keeper, uint block);
                                                              
                                                                  event AddCredit(address indexed credit, address indexed job, address indexed creditor, uint block, uint amount);
                                                              
                                                                  /// @notice 1 day to bond to become a keeper
                                                                  uint constant public BOND = 3 days;
                                                                  /// @notice 14 days to unbond to remove funds from being a keeper
                                                                  uint constant public UNBOND = 14 days;
                                                                  /// @notice 3 days till liquidity can be bound
                                                                  uint constant public LIQUIDITYBOND = 3 days;
                                                              
                                                                  /// @notice direct liquidity fee 0.3%
                                                                  uint constant public FEE = 30;
                                                                  uint constant public BASE = 10000;
                                                              
                                                                  /// @notice address used for ETH transfers
                                                                  address constant public ETH = address(0xE);
                                                              
                                                                  /// @notice tracks all current bondings (time)
                                                                  mapping(address => mapping(address => uint)) public bondings;
                                                                  /// @notice tracks all current unbondings (time)
                                                                  mapping(address => mapping(address => uint)) public unbondings;
                                                                  /// @notice allows for partial unbonding
                                                                  mapping(address => mapping(address => uint)) public partialUnbonding;
                                                                  /// @notice tracks all current pending bonds (amount)
                                                                  mapping(address => mapping(address => uint)) public pendingbonds;
                                                                  /// @notice tracks how much a keeper has bonded
                                                                  mapping(address => mapping(address => uint)) public bonds;
                                                                  /// @notice tracks underlying votes (that don't have bond)
                                                                  mapping(address => uint) public votes;
                                                              
                                                                  /// @notice total bonded (totalSupply for bonds)
                                                                  uint public totalBonded = 0;
                                                                  /// @notice tracks when a keeper was first registered
                                                                  mapping(address => uint) public firstSeen;
                                                              
                                                                  /// @notice tracks if a keeper has a pending dispute
                                                                  mapping(address => bool) public disputes;
                                                              
                                                                  /// @notice tracks last job performed for a keeper
                                                                  mapping(address => uint) public lastJob;
                                                                  /// @notice tracks the total job executions for a keeper
                                                                  mapping(address => uint) public workCompleted;
                                                                  /// @notice list of all jobs registered for the keeper system
                                                                  mapping(address => bool) public jobs;
                                                                  /// @notice the current credit available for a job
                                                                  mapping(address => mapping(address => uint)) public credits;
                                                                  /// @notice the balances for the liquidity providers
                                                                  mapping(address => mapping(address => mapping(address => uint))) public liquidityProvided;
                                                                  /// @notice liquidity unbonding days
                                                                  mapping(address => mapping(address => mapping(address => uint))) public liquidityUnbonding;
                                                                  /// @notice liquidity unbonding amounts
                                                                  mapping(address => mapping(address => mapping(address => uint))) public liquidityAmountsUnbonding;
                                                                  /// @notice job proposal delay
                                                                  mapping(address => uint) public jobProposalDelay;
                                                                  /// @notice liquidity apply date
                                                                  mapping(address => mapping(address => mapping(address => uint))) public liquidityApplied;
                                                                  /// @notice liquidity amount to apply
                                                                  mapping(address => mapping(address => mapping(address => uint))) public liquidityAmount;
                                                              
                                                                  /// @notice list of all current keepers
                                                                  mapping(address => bool) public keepers;
                                                                  /// @notice blacklist of keepers not allowed to participate
                                                                  mapping(address => bool) public blacklist;
                                                              
                                                                  /// @notice traversable array of keepers to make external management easier
                                                                  address[] public keeperList;
                                                                  /// @notice traversable array of jobs to make external management easier
                                                                  address[] public jobList;
                                                              
                                                                  /// @notice governance address for the governance contract
                                                                  address public governance;
                                                                  address public pendingGovernance;
                                                              
                                                                  /// @notice the liquidity token supplied by users paying for jobs
                                                                  mapping(address => bool) public liquidityAccepted;
                                                              
                                                                  address[] public liquidityPairs;
                                                              
                                                                  uint internal _gasUsed;
                                                              
                                                                  constructor(address _kph) public {
                                                                      // Set governance for this token
                                                                      governance = msg.sender;
                                                                      DOMAINSEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), _getChainId(), address(this)));
                                                                      KPRH = IKeep3rV1Helper(_kph);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Add ETH credit to a job to be paid out for work
                                                                   * @param job the job being credited
                                                                   */
                                                                  function addCreditETH(address job) external payable {
                                                                      require(jobs[job], "addCreditETH: !job");
                                                                      uint _fee = msg.value.mul(FEE).div(BASE);
                                                                      credits[job][ETH] = credits[job][ETH].add(msg.value.sub(_fee));
                                                                      payable(governance).transfer(_fee);
                                                              
                                                                      emit AddCredit(ETH, job, msg.sender, block.number, msg.value);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Add credit to a job to be paid out for work
                                                                   * @param credit the credit being assigned to the job
                                                                   * @param job the job being credited
                                                                   * @param amount the amount of credit being added to the job
                                                                   */
                                                                  function addCredit(address credit, address job, uint amount) external nonReentrant {
                                                                      require(jobs[job], "addCreditETH: !job");
                                                                      uint _before = IERC20(credit).balanceOf(address(this));
                                                                      IERC20(credit).safeTransferFrom(msg.sender, address(this), amount);
                                                                      uint _received = IERC20(credit).balanceOf(address(this)).sub(_before);
                                                                      uint _fee = _received.mul(FEE).div(BASE);
                                                                      credits[job][credit] = credits[job][credit].add(_received.sub(_fee));
                                                                      IERC20(credit).safeTransfer(governance, _fee);
                                                              
                                                                      emit AddCredit(credit, job, msg.sender, block.number, _received);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Add non transferable votes for governance
                                                                   * @param voter to add the votes to
                                                                   * @param amount of votes to add
                                                                   */
                                                                  function addVotes(address voter, uint amount) external {
                                                                      require(msg.sender == governance, "addVotes: !gov");
                                                                      _activate(voter, address(this));
                                                                      votes[voter] = votes[voter].add(amount);
                                                                      totalBonded = totalBonded.add(amount);
                                                                      _moveDelegates(address(0), delegates[voter], amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Remove non transferable votes for governance
                                                                   * @param voter to subtract the votes
                                                                   * @param amount of votes to remove
                                                                   */
                                                                  function removeVotes(address voter, uint amount) external {
                                                                      require(msg.sender == governance, "addVotes: !gov");
                                                                      votes[voter] = votes[voter].sub(amount);
                                                                      totalBonded = totalBonded.sub(amount);
                                                                      _moveDelegates(delegates[voter], address(0), amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Add credit to a job to be paid out for work
                                                                   * @param job the job being credited
                                                                   * @param amount the amount of credit being added to the job
                                                                   */
                                                                  function addKPRCredit(address job, uint amount) external {
                                                                      require(msg.sender == governance, "addKPRCredit: !gov");
                                                                      require(jobs[job], "addKPRCredit: !job");
                                                                      credits[job][address(this)] = credits[job][address(this)].add(amount);
                                                                      _mint(address(this), amount);
                                                                      emit AddCredit(address(this), job, msg.sender, block.number, amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Approve a liquidity pair for being accepted in future
                                                                   * @param liquidity the liquidity no longer accepted
                                                                   */
                                                                  function approveLiquidity(address liquidity) external {
                                                                      require(msg.sender == governance, "approveLiquidity: !gov");
                                                                      require(!liquidityAccepted[liquidity], "approveLiquidity: !pair");
                                                                      liquidityAccepted[liquidity] = true;
                                                                      liquidityPairs.push(liquidity);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Revoke a liquidity pair from being accepted in future
                                                                   * @param liquidity the liquidity no longer accepted
                                                                   */
                                                                  function revokeLiquidity(address liquidity) external {
                                                                      require(msg.sender == governance, "revokeLiquidity: !gov");
                                                                      liquidityAccepted[liquidity] = false;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Displays all accepted liquidity pairs
                                                                   */
                                                                  function pairs() external view returns (address[] memory) {
                                                                      return liquidityPairs;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Allows liquidity providers to submit jobs
                                                                   * @param liquidity the liquidity being added
                                                                   * @param job the job to assign credit to
                                                                   * @param amount the amount of liquidity tokens to use
                                                                   */
                                                                  function addLiquidityToJob(address liquidity, address job, uint amount) external nonReentrant {
                                                                      require(liquidityAccepted[liquidity], "addLiquidityToJob: !pair");
                                                                      IERC20(liquidity).safeTransferFrom(msg.sender, address(this), amount);
                                                                      liquidityProvided[msg.sender][liquidity][job] = liquidityProvided[msg.sender][liquidity][job].add(amount);
                                                              
                                                                      liquidityApplied[msg.sender][liquidity][job] = now.add(LIQUIDITYBOND);
                                                                      liquidityAmount[msg.sender][liquidity][job] = liquidityAmount[msg.sender][liquidity][job].add(amount);
                                                              
                                                                      if (!jobs[job] && jobProposalDelay[job] < now) {
                                                                          IGovernance(governance).proposeJob(job);
                                                                          jobProposalDelay[job] = now.add(UNBOND);
                                                                      }
                                                                      emit SubmitJob(job, liquidity, msg.sender, block.number, amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Applies the credit provided in addLiquidityToJob to the job
                                                                   * @param provider the liquidity provider
                                                                   * @param liquidity the pair being added as liquidity
                                                                   * @param job the job that is receiving the credit
                                                                   */
                                                                  function applyCreditToJob(address provider, address liquidity, address job) external {
                                                                      require(liquidityAccepted[liquidity], "addLiquidityToJob: !pair");
                                                                      require(liquidityApplied[provider][liquidity][job] != 0, "credit: no bond");
                                                                      require(liquidityApplied[provider][liquidity][job] < now, "credit: bonding");
                                                                      uint _liquidity = Keep3rV1Library.getReserve(liquidity, address(this));
                                                                      uint _credit = _liquidity.mul(liquidityAmount[provider][liquidity][job]).div(IERC20(liquidity).totalSupply());
                                                                      _mint(address(this), _credit);
                                                                      credits[job][address(this)] = credits[job][address(this)].add(_credit);
                                                                      liquidityAmount[provider][liquidity][job] = 0;
                                                              
                                                                      emit ApplyCredit(job, liquidity, provider, block.number, _credit);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Unbond liquidity for a job
                                                                   * @param liquidity the pair being unbound
                                                                   * @param job the job being unbound from
                                                                   * @param amount the amount of liquidity being removed
                                                                   */
                                                                  function unbondLiquidityFromJob(address liquidity, address job, uint amount) external {
                                                                      require(liquidityAmount[msg.sender][liquidity][job] == 0, "credit: pending credit");
                                                                      liquidityUnbonding[msg.sender][liquidity][job] = now.add(UNBOND);
                                                                      liquidityAmountsUnbonding[msg.sender][liquidity][job] = liquidityAmountsUnbonding[msg.sender][liquidity][job].add(amount);
                                                                      require(liquidityAmountsUnbonding[msg.sender][liquidity][job] <= liquidityProvided[msg.sender][liquidity][job], "unbondLiquidityFromJob: insufficient funds");
                                                              
                                                                      uint _liquidity = Keep3rV1Library.getReserve(liquidity, address(this));
                                                                      uint _credit = _liquidity.mul(amount).div(IERC20(liquidity).totalSupply());
                                                                      if (_credit > credits[job][address(this)]) {
                                                                          _burn(address(this), credits[job][address(this)]);
                                                                          credits[job][address(this)] = 0;
                                                                      } else {
                                                                          _burn(address(this), _credit);
                                                                          credits[job][address(this)] = credits[job][address(this)].sub(_credit);
                                                                      }
                                                              
                                                                      emit UnbondJob(job, liquidity, msg.sender, block.number, amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Allows liquidity providers to remove liquidity
                                                                   * @param liquidity the pair being unbound
                                                                   * @param job the job being unbound from
                                                                   */
                                                                  function removeLiquidityFromJob(address liquidity, address job) external {
                                                                      require(liquidityUnbonding[msg.sender][liquidity][job] != 0, "removeJob: unbond");
                                                                      require(liquidityUnbonding[msg.sender][liquidity][job] < now, "removeJob: unbonding");
                                                                      uint _amount = liquidityAmountsUnbonding[msg.sender][liquidity][job];
                                                                      liquidityProvided[msg.sender][liquidity][job] = liquidityProvided[msg.sender][liquidity][job].sub(_amount);
                                                                      liquidityAmountsUnbonding[msg.sender][liquidity][job] = 0;
                                                                      IERC20(liquidity).safeTransfer(msg.sender, _amount);
                                                              
                                                                      emit RemoveJob(job, liquidity, msg.sender, block.number, _amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Allows governance to mint new tokens to treasury
                                                                   * @param amount the amount of tokens to mint to treasury
                                                                   */
                                                                  function mint(uint amount) external {
                                                                      require(msg.sender == governance, "mint: !gov");
                                                                      _mint(governance, amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice burn owned tokens
                                                                   * @param amount the amount of tokens to burn
                                                                   */
                                                                  function burn(uint amount) external {
                                                                      _burn(msg.sender, amount);
                                                                  }
                                                              
                                                                  function _mint(address dst, uint amount) internal {
                                                                      // mint the amount
                                                                      totalSupply = totalSupply.add(amount);
                                                                      // transfer the amount to the recipient
                                                                      balances[dst] = balances[dst].add(amount);
                                                                      emit Transfer(address(0), dst, amount);
                                                                  }
                                                              
                                                                  function _burn(address dst, uint amount) internal {
                                                                      require(dst != address(0), "_burn: zero address");
                                                                      balances[dst] = balances[dst].sub(amount, "_burn: exceeds balance");
                                                                      totalSupply = totalSupply.sub(amount);
                                                                      emit Transfer(dst, address(0), amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Implemented by jobs to show that a keeper performed work
                                                                   * @param keeper address of the keeper that performed the work
                                                                   */
                                                                  function worked(address keeper) external {
                                                                      workReceipt(keeper, KPRH.getQuoteLimit(_gasUsed.sub(gasleft())));
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Implemented by jobs to show that a keeper performed work
                                                                   * @param keeper address of the keeper that performed the work
                                                                   * @param amount the reward that should be allocated
                                                                   */
                                                                  function workReceipt(address keeper, uint amount) public {
                                                                      require(jobs[msg.sender], "workReceipt: !job");
                                                                      require(amount <= KPRH.getQuoteLimit(_gasUsed.sub(gasleft())), "workReceipt: max limit");
                                                                      credits[msg.sender][address(this)] = credits[msg.sender][address(this)].sub(amount, "workReceipt: insuffient funds");
                                                                      lastJob[keeper] = now;
                                                                      _reward(keeper, amount);
                                                                      workCompleted[keeper] = workCompleted[keeper].add(amount);
                                                                      emit KeeperWorked(address(this), msg.sender, keeper, block.number, amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Implemented by jobs to show that a keeper performed work
                                                                   * @param credit the asset being awarded to the keeper
                                                                   * @param keeper address of the keeper that performed the work
                                                                   * @param amount the reward that should be allocated
                                                                   */
                                                                  function receipt(address credit, address keeper, uint amount) external {
                                                                      require(jobs[msg.sender], "receipt: !job");
                                                                      credits[msg.sender][credit] = credits[msg.sender][credit].sub(amount, "workReceipt: insuffient funds");
                                                                      lastJob[keeper] = now;
                                                                      IERC20(credit).safeTransfer(keeper, amount);
                                                                      emit KeeperWorked(credit, msg.sender, keeper, block.number, amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Implemented by jobs to show that a keeper performed work
                                                                   * @param keeper address of the keeper that performed the work
                                                                   * @param amount the amount of ETH sent to the keeper
                                                                   */
                                                                  function receiptETH(address keeper, uint amount) external {
                                                                      require(jobs[msg.sender], "receipt: !job");
                                                                      credits[msg.sender][ETH] = credits[msg.sender][ETH].sub(amount, "workReceipt: insuffient funds");
                                                                      lastJob[keeper] = now;
                                                                      payable(keeper).transfer(amount);
                                                                      emit KeeperWorked(ETH, msg.sender, keeper, block.number, amount);
                                                                  }
                                                              
                                                                  function _reward(address _from, uint _amount) internal {
                                                                      bonds[_from][address(this)] = bonds[_from][address(this)].add(_amount);
                                                                      totalBonded = totalBonded.add(_amount);
                                                                      _moveDelegates(address(0), delegates[_from], _amount);
                                                                      emit Transfer(msg.sender, _from, _amount);
                                                                  }
                                                              
                                                                  function _bond(address bonding, address _from, uint _amount) internal {
                                                                      bonds[_from][bonding] = bonds[_from][bonding].add(_amount);
                                                                      if (bonding == address(this)) {
                                                                          totalBonded = totalBonded.add(_amount);
                                                                          _moveDelegates(address(0), delegates[_from], _amount);
                                                                      }
                                                                  }
                                                              
                                                                  function _unbond(address bonding, address _from, uint _amount) internal {
                                                                      bonds[_from][bonding] = bonds[_from][bonding].sub(_amount);
                                                                      if (bonding == address(this)) {
                                                                          totalBonded = totalBonded.sub(_amount);
                                                                          _moveDelegates(delegates[_from], address(0), _amount);
                                                                      }
                                                              
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Allows governance to add new job systems
                                                                   * @param job address of the contract for which work should be performed
                                                                   */
                                                                  function addJob(address job) external {
                                                                      require(msg.sender == governance, "addJob: !gov");
                                                                      require(!jobs[job], "addJob: job known");
                                                                      jobs[job] = true;
                                                                      jobList.push(job);
                                                                      emit JobAdded(job, block.number, msg.sender);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Full listing of all jobs ever added
                                                                   * @return array blob
                                                                   */
                                                                  function getJobs() external view returns (address[] memory) {
                                                                      return jobList;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Allows governance to remove a job from the systems
                                                                   * @param job address of the contract for which work should be performed
                                                                   */
                                                                  function removeJob(address job) external {
                                                                      require(msg.sender == governance, "removeJob: !gov");
                                                                      jobs[job] = false;
                                                                      emit JobRemoved(job, block.number, msg.sender);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Allows governance to change the Keep3rHelper for max spend
                                                                   * @param _kprh new helper address to set
                                                                   */
                                                                  function setKeep3rHelper(IKeep3rV1Helper _kprh) external {
                                                                      require(msg.sender == governance, "setKeep3rHelper: !gov");
                                                                      KPRH = _kprh;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Allows governance to change governance (for future upgradability)
                                                                   * @param _governance new governance address to set
                                                                   */
                                                                  function setGovernance(address _governance) external {
                                                                      require(msg.sender == governance, "setGovernance: !gov");
                                                                      pendingGovernance = _governance;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Allows pendingGovernance to accept their role as governance (protection pattern)
                                                                   */
                                                                  function acceptGovernance() external {
                                                                      require(msg.sender == pendingGovernance, "acceptGovernance: !pendingGov");
                                                                      governance = pendingGovernance;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice confirms if the current keeper is registered, can be used for general (non critical) functions
                                                                   * @param keeper the keeper being investigated
                                                                   * @return true/false if the address is a keeper
                                                                   */
                                                                  function isKeeper(address keeper) external returns (bool) {
                                                                      _gasUsed = gasleft();
                                                                      return keepers[keeper];
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice confirms if the current keeper is registered and has a minimum bond, should be used for protected functions
                                                                   * @param keeper the keeper being investigated
                                                                   * @param minBond the minimum requirement for the asset provided in bond
                                                                   * @param earned the total funds earned in the keepers lifetime
                                                                   * @param age the age of the keeper in the system
                                                                   * @return true/false if the address is a keeper and has more than the bond
                                                                   */
                                                                  function isMinKeeper(address keeper, uint minBond, uint earned, uint age) external returns (bool) {
                                                                      _gasUsed = gasleft();
                                                                      return keepers[keeper]
                                                                              && bonds[keeper][address(this)].add(votes[keeper]) >= minBond
                                                                              && workCompleted[keeper] >= earned
                                                                              && now.sub(firstSeen[keeper]) >= age;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice confirms if the current keeper is registered and has a minimum bond, should be used for protected functions
                                                                   * @param keeper the keeper being investigated
                                                                   * @param bond the bound asset being evaluated
                                                                   * @param minBond the minimum requirement for the asset provided in bond
                                                                   * @param earned the total funds earned in the keepers lifetime
                                                                   * @param age the age of the keeper in the system
                                                                   * @return true/false if the address is a keeper and has more than the bond
                                                                   */
                                                                  function isBondedKeeper(address keeper, address bond, uint minBond, uint earned, uint age) external returns (bool) {
                                                                      _gasUsed = gasleft();
                                                                      return keepers[keeper]
                                                                              && bonds[keeper][bond] >= minBond
                                                                              && workCompleted[keeper] >= earned
                                                                              && now.sub(firstSeen[keeper]) >= age;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice begin the bonding process for a new keeper
                                                                   * @param bonding the asset being bound
                                                                   * @param amount the amount of bonding asset being bound
                                                                   */
                                                                  function bond(address bonding, uint amount) external nonReentrant {
                                                                      require(!blacklist[msg.sender], "bond: blacklisted");
                                                                      bondings[msg.sender][bonding] = now.add(BOND);
                                                                      if (bonding == address(this)) {
                                                                          _transferTokens(msg.sender, address(this), amount);
                                                                      } else {
                                                                          uint _before = IERC20(bonding).balanceOf(address(this));
                                                                          IERC20(bonding).safeTransferFrom(msg.sender, address(this), amount);
                                                                          amount = IERC20(bonding).balanceOf(address(this)).sub(_before);
                                                                      }
                                                                      pendingbonds[msg.sender][bonding] = pendingbonds[msg.sender][bonding].add(amount);
                                                                      emit KeeperBonding(msg.sender, block.number, bondings[msg.sender][bonding], amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice get full list of keepers in the system
                                                                   */
                                                                  function getKeepers() external view returns (address[] memory) {
                                                                      return keeperList;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice allows a keeper to activate/register themselves after bonding
                                                                   * @param bonding the asset being activated as bond collateral
                                                                   */
                                                                  function activate(address bonding) external {
                                                                      require(!blacklist[msg.sender], "activate: blacklisted");
                                                                      require(bondings[msg.sender][bonding] != 0 && bondings[msg.sender][bonding] < now, "activate: bonding");
                                                                      _activate(msg.sender, bonding);
                                                                  }
                                                                  
                                                                  function _activate(address keeper, address bonding) internal {
                                                                      if (firstSeen[keeper] == 0) {
                                                                        firstSeen[keeper] = now;
                                                                        keeperList.push(keeper);
                                                                        lastJob[keeper] = now;
                                                                      }
                                                                      keepers[keeper] = true;
                                                                      _bond(bonding, keeper, pendingbonds[keeper][bonding]);
                                                                      pendingbonds[keeper][bonding] = 0;
                                                                      emit KeeperBonded(keeper, block.number, block.timestamp, bonds[keeper][bonding]);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice begin the unbonding process to stop being a keeper
                                                                   * @param bonding the asset being unbound
                                                                   * @param amount allows for partial unbonding
                                                                   */
                                                                  function unbond(address bonding, uint amount) external {
                                                                      unbondings[msg.sender][bonding] = now.add(UNBOND);
                                                                      _unbond(bonding, msg.sender, amount);
                                                                      partialUnbonding[msg.sender][bonding] = partialUnbonding[msg.sender][bonding].add(amount);
                                                                      emit KeeperUnbonding(msg.sender, block.number, unbondings[msg.sender][bonding], amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice withdraw funds after unbonding has finished
                                                                   * @param bonding the asset to withdraw from the bonding pool
                                                                   */
                                                                  function withdraw(address bonding) external nonReentrant {
                                                                      require(unbondings[msg.sender][bonding] != 0 && unbondings[msg.sender][bonding] < now, "withdraw: unbonding");
                                                                      require(!disputes[msg.sender], "withdraw: disputes");
                                                              
                                                                      if (bonding == address(this)) {
                                                                          _transferTokens(address(this), msg.sender, partialUnbonding[msg.sender][bonding]);
                                                                      } else {
                                                                          IERC20(bonding).safeTransfer(msg.sender, partialUnbonding[msg.sender][bonding]);
                                                                      }
                                                                      emit KeeperUnbound(msg.sender, block.number, block.timestamp, partialUnbonding[msg.sender][bonding]);
                                                                      partialUnbonding[msg.sender][bonding] = 0;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice allows governance to create a dispute for a given keeper
                                                                   * @param keeper the address in dispute
                                                                   */
                                                                  function dispute(address keeper) external {
                                                                      require(msg.sender == governance, "dispute: !gov");
                                                                      disputes[keeper] = true;
                                                                      emit KeeperDispute(keeper, block.number);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice allows governance to slash a keeper based on a dispute
                                                                   * @param bonded the asset being slashed
                                                                   * @param keeper the address being slashed
                                                                   * @param amount the amount being slashed
                                                                   */
                                                                  function slash(address bonded, address keeper, uint amount) public nonReentrant {
                                                                      require(msg.sender == governance, "slash: !gov");
                                                                      if (bonded == address(this)) {
                                                                          _transferTokens(address(this), governance, amount);
                                                                      } else {
                                                                          IERC20(bonded).safeTransfer(governance, amount);
                                                                      }
                                                                      _unbond(bonded, keeper, amount);
                                                                      disputes[keeper] = false;
                                                                      emit KeeperSlashed(keeper, msg.sender, block.number, amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice blacklists a keeper from participating in the network
                                                                   * @param keeper the address being slashed
                                                                   */
                                                                  function revoke(address keeper) external {
                                                                      require(msg.sender == governance, "slash: !gov");
                                                                      keepers[keeper] = false;
                                                                      blacklist[keeper] = true;
                                                                      slash(address(this), keeper, bonds[keeper][address(this)]);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice allows governance to resolve a dispute on a keeper
                                                                   * @param keeper the address cleared
                                                                   */
                                                                  function resolve(address keeper) external {
                                                                      require(msg.sender == governance, "resolve: !gov");
                                                                      disputes[keeper] = false;
                                                                      emit KeeperResolved(keeper, block.number);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
                                                                   * @param account The address of the account holding the funds
                                                                   * @param spender The address of the account spending the funds
                                                                   * @return The number of tokens approved
                                                                   */
                                                                  function allowance(address account, address spender) external view returns (uint) {
                                                                      return allowances[account][spender];
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Approve `spender` to transfer up to `amount` from `src`
                                                                   * @dev This will overwrite the approval amount for `spender`
                                                                   *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
                                                                   * @param spender The address of the account which may transfer tokens
                                                                   * @param amount The number of tokens that are approved (2^256-1 means infinite)
                                                                   * @return Whether or not the approval succeeded
                                                                   */
                                                                  function approve(address spender, uint amount) public returns (bool) {
                                                                      allowances[msg.sender][spender] = amount;
                                                              
                                                                      emit Approval(msg.sender, spender, amount);
                                                                      return true;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Triggers an approval from owner to spends
                                                                   * @param owner The address to approve from
                                                                   * @param spender The address to be approved
                                                                   * @param amount The number of tokens that are approved (2^256-1 means infinite)
                                                                   * @param deadline The time at which to expire the signature
                                                                   * @param v The recovery byte of the signature
                                                                   * @param r Half of the ECDSA signature pair
                                                                   * @param s Half of the ECDSA signature pair
                                                                   */
                                                                  function permit(address owner, address spender, uint amount, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
                                                                      bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, amount, nonces[owner]++, deadline));
                                                                      bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAINSEPARATOR, structHash));
                                                                      address signatory = ecrecover(digest, v, r, s);
                                                                      require(signatory != address(0), "permit: signature");
                                                                      require(signatory == owner, "permit: unauthorized");
                                                                      require(now <= deadline, "permit: expired");
                                                              
                                                                      allowances[owner][spender] = amount;
                                                              
                                                                      emit Approval(owner, spender, amount);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Get the number of tokens held by the `account`
                                                                   * @param account The address of the account to get the balance of
                                                                   * @return The number of tokens held
                                                                   */
                                                                  function balanceOf(address account) external view returns (uint) {
                                                                      return balances[account];
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Transfer `amount` tokens from `msg.sender` to `dst`
                                                                   * @param dst The address of the destination account
                                                                   * @param amount The number of tokens to transfer
                                                                   * @return Whether or not the transfer succeeded
                                                                   */
                                                                  function transfer(address dst, uint amount) public returns (bool) {
                                                                      _transferTokens(msg.sender, dst, amount);
                                                                      return true;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Transfer `amount` tokens from `src` to `dst`
                                                                   * @param src The address of the source account
                                                                   * @param dst The address of the destination account
                                                                   * @param amount The number of tokens to transfer
                                                                   * @return Whether or not the transfer succeeded
                                                                   */
                                                                  function transferFrom(address src, address dst, uint amount) external returns (bool) {
                                                                      address spender = msg.sender;
                                                                      uint spenderAllowance = allowances[src][spender];
                                                              
                                                                      if (spender != src && spenderAllowance != uint(-1)) {
                                                                          uint newAllowance = spenderAllowance.sub(amount, "transferFrom: exceeds spender allowance");
                                                                          allowances[src][spender] = newAllowance;
                                                              
                                                                          emit Approval(src, spender, newAllowance);
                                                                      }
                                                              
                                                                      _transferTokens(src, dst, amount);
                                                                      return true;
                                                                  }
                                                              
                                                                  function _transferTokens(address src, address dst, uint amount) internal {
                                                                      require(src != address(0), "_transferTokens: zero address");
                                                                      require(dst != address(0), "_transferTokens: zero address");
                                                              
                                                                      balances[src] = balances[src].sub(amount, "_transferTokens: exceeds balance");
                                                                      balances[dst] = balances[dst].add(amount, "_transferTokens: overflows");
                                                                      emit Transfer(src, dst, amount);
                                                                  }
                                                              
                                                                  function _getChainId() internal pure returns (uint) {
                                                                      uint chainId;
                                                                      assembly { chainId := chainid() }
                                                                      return chainId;
                                                                  }
                                                              }

                                                              File 5 of 14: KernelProxy
                                                              /**
                                                               *Submitted for verification at Etherscan.io on 2020-02-06
                                                              */
                                                              
                                                              // File: contracts/acl/IACL.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IACL {
                                                                  function initialize(address permissionsCreator) external;
                                                              
                                                                  // TODO: this should be external
                                                                  // See https://github.com/ethereum/solidity/issues/4832
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              }
                                                              
                                                              // File: contracts/common/IVaultRecoverable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IVaultRecoverable {
                                                                  event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                                                              
                                                                  function transferToVault(address token) external;
                                                              
                                                                  function allowRecoverability(address token) external view returns (bool);
                                                                  function getRecoveryVault() external view returns (address);
                                                              }
                                                              
                                                              // File: contracts/kernel/IKernel.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              interface IKernelEvents {
                                                                  event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                                                              }
                                                              
                                                              
                                                              // This should be an interface, but interfaces can't inherit yet :(
                                                              contract IKernel is IKernelEvents, IVaultRecoverable {
                                                                  function acl() public view returns (IACL);
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              
                                                                  function setApp(bytes32 namespace, bytes32 appId, address app) public;
                                                                  function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                                                              }
                                                              
                                                              // File: contracts/kernel/KernelConstants.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract KernelAppIds {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                                                              }
                                                              
                                                              
                                                              contract KernelNamespaceConstants {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                                                              }
                                                              
                                                              // File: contracts/kernel/KernelStorage.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              contract KernelStorage {
                                                                  // namespace => app id => address
                                                                  mapping (bytes32 => mapping (bytes32 => address)) public apps;
                                                                  bytes32 public recoveryVaultAppId;
                                                              }
                                                              
                                                              // File: contracts/acl/ACLSyntaxSugar.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract ACLSyntaxSugar {
                                                                  function arr() internal pure returns (uint256[]) {
                                                                      return new uint256[](0);
                                                                  }
                                                              
                                                                  function arr(bytes32 _a) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a));
                                                                  }
                                                              
                                                                  function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                              
                                                                  function arr(address _a) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a));
                                                                  }
                                                              
                                                                  function arr(address _a, address _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                              
                                                                  function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), _b, _c);
                                                                  }
                                                              
                                                                  function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), _b, _c, _d);
                                                                  }
                                                              
                                                                  function arr(address _a, uint256 _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                              
                                                                  function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), _c, _d, _e);
                                                                  }
                                                              
                                                                  function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), uint256(_c));
                                                                  }
                                                              
                                                                  function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), uint256(_c));
                                                                  }
                                                              
                                                                  function arr(uint256 _a) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](1);
                                                                      r[0] = _a;
                                                                  }
                                                              
                                                                  function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](2);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                  }
                                                              
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](3);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                  }
                                                              
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](4);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                      r[3] = _d;
                                                                  }
                                                              
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](5);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                      r[3] = _d;
                                                                      r[4] = _e;
                                                                  }
                                                              }
                                                              
                                                              
                                                              contract ACLHelpers {
                                                                  function decodeParamOp(uint256 _x) internal pure returns (uint8 b) {
                                                                      return uint8(_x >> (8 * 30));
                                                                  }
                                                              
                                                                  function decodeParamId(uint256 _x) internal pure returns (uint8 b) {
                                                                      return uint8(_x >> (8 * 31));
                                                                  }
                                                              
                                                                  function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) {
                                                                      a = uint32(_x);
                                                                      b = uint32(_x >> (8 * 4));
                                                                      c = uint32(_x >> (8 * 8));
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/ConversionHelpers.sol
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              library ConversionHelpers {
                                                                  string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH";
                                                              
                                                                  function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) {
                                                                      // Force cast the uint256[] into a bytes array, by overwriting its length
                                                                      // Note that the bytes array doesn't need to be initialized as we immediately overwrite it
                                                                      // with the input and a new length. The input becomes invalid from this point forward.
                                                                      uint256 byteLength = _input.length * 32;
                                                                      assembly {
                                                                          output := _input
                                                                          mstore(output, byteLength)
                                                                      }
                                                                  }
                                                              
                                                                  function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) {
                                                                      // Force cast the bytes array into a uint256[], by overwriting its length
                                                                      // Note that the uint256[] doesn't need to be initialized as we immediately overwrite it
                                                                      // with the input and a new length. The input becomes invalid from this point forward.
                                                                      uint256 intsLength = _input.length / 32;
                                                                      require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH);
                                                              
                                                                      assembly {
                                                                          output := _input
                                                                          mstore(output, intsLength)
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/IsContract.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract IsContract {
                                                                  /*
                                                                  * NOTE: this should NEVER be used for authentication
                                                                  * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                                                                  *
                                                                  * This is only intended to be used as a sanity check that an address is actually a contract,
                                                                  * RATHER THAN an address not being a contract.
                                                                  */
                                                                  function isContract(address _target) internal view returns (bool) {
                                                                      if (_target == address(0)) {
                                                                          return false;
                                                                      }
                                                              
                                                                      uint256 size;
                                                                      assembly { size := extcodesize(_target) }
                                                                      return size > 0;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/Uint256Helpers.sol
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              library Uint256Helpers {
                                                                  uint256 private constant MAX_UINT64 = uint64(-1);
                                                              
                                                                  string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG";
                                                              
                                                                  function toUint64(uint256 a) internal pure returns (uint64) {
                                                                      require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG);
                                                                      return uint64(a);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/TimeHelpers.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              contract TimeHelpers {
                                                                  using Uint256Helpers for uint256;
                                                              
                                                                  /**
                                                                  * @dev Returns the current block number.
                                                                  *      Using a function rather than `block.number` allows us to easily mock the block number in
                                                                  *      tests.
                                                                  */
                                                                  function getBlockNumber() internal view returns (uint256) {
                                                                      return block.number;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Returns the current block number, converted to uint64.
                                                                  *      Using a function rather than `block.number` allows us to easily mock the block number in
                                                                  *      tests.
                                                                  */
                                                                  function getBlockNumber64() internal view returns (uint64) {
                                                                      return getBlockNumber().toUint64();
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Returns the current timestamp.
                                                                  *      Using a function rather than `block.timestamp` allows us to easily mock it in
                                                                  *      tests.
                                                                  */
                                                                  function getTimestamp() internal view returns (uint256) {
                                                                      return block.timestamp; // solium-disable-line security/no-block-members
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Returns the current timestamp, converted to uint64.
                                                                  *      Using a function rather than `block.timestamp` allows us to easily mock it in
                                                                  *      tests.
                                                                  */
                                                                  function getTimestamp64() internal view returns (uint64) {
                                                                      return getTimestamp().toUint64();
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/UnstructuredStorage.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              library UnstructuredStorage {
                                                                  function getStorageBool(bytes32 position) internal view returns (bool data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageAddress(bytes32 position) internal view returns (address data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function setStorageBool(bytes32 position, bool data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageAddress(bytes32 position, address data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageBytes32(bytes32 position, bytes32 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageUint256(bytes32 position, uint256 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/Initializable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract Initializable is TimeHelpers {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  // keccak256("aragonOS.initializable.initializationBlock")
                                                                  bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e;
                                                              
                                                                  string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED";
                                                                  string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED";
                                                              
                                                                  modifier onlyInit {
                                                                      require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED);
                                                                      _;
                                                                  }
                                                              
                                                                  modifier isInitialized {
                                                                      require(hasInitialized(), ERROR_NOT_INITIALIZED);
                                                                      _;
                                                                  }
                                                              
                                                                  /**
                                                                  * @return Block number in which the contract was initialized
                                                                  */
                                                                  function getInitializationBlock() public view returns (uint256) {
                                                                      return INITIALIZATION_BLOCK_POSITION.getStorageUint256();
                                                                  }
                                                              
                                                                  /**
                                                                  * @return Whether the contract has been initialized by the time of the current block
                                                                  */
                                                                  function hasInitialized() public view returns (bool) {
                                                                      uint256 initializationBlock = getInitializationBlock();
                                                                      return initializationBlock != 0 && getBlockNumber() >= initializationBlock;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Function to be called by top level contract after initialization has finished.
                                                                  */
                                                                  function initialized() internal onlyInit {
                                                                      INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber());
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Function to be called by top level contract after initialization to enable the contract
                                                                  *      at a future block number rather than immediately.
                                                                  */
                                                                  function initializedAt(uint256 _blockNumber) internal onlyInit {
                                                                      INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/Petrifiable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              contract Petrifiable is Initializable {
                                                                  // Use block UINT256_MAX (which should be never) as the initializable date
                                                                  uint256 internal constant PETRIFIED_BLOCK = uint256(-1);
                                                              
                                                                  function isPetrified() public view returns (bool) {
                                                                      return getInitializationBlock() == PETRIFIED_BLOCK;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Function to be called by top level contract to prevent being initialized.
                                                                  *      Useful for freezing base contracts when they're used behind proxies.
                                                                  */
                                                                  function petrify() internal onlyInit {
                                                                      initializedAt(PETRIFIED_BLOCK);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/lib/token/ERC20.sol
                                                              
                                                              // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              /**
                                                               * @title ERC20 interface
                                                               * @dev see https://github.com/ethereum/EIPs/issues/20
                                                               */
                                                              contract ERC20 {
                                                                  function totalSupply() public view returns (uint256);
                                                              
                                                                  function balanceOf(address _who) public view returns (uint256);
                                                              
                                                                  function allowance(address _owner, address _spender)
                                                                      public view returns (uint256);
                                                              
                                                                  function transfer(address _to, uint256 _value) public returns (bool);
                                                              
                                                                  function approve(address _spender, uint256 _value)
                                                                      public returns (bool);
                                                              
                                                                  function transferFrom(address _from, address _to, uint256 _value)
                                                                      public returns (bool);
                                                              
                                                                  event Transfer(
                                                                      address indexed from,
                                                                      address indexed to,
                                                                      uint256 value
                                                                  );
                                                              
                                                                  event Approval(
                                                                      address indexed owner,
                                                                      address indexed spender,
                                                                      uint256 value
                                                                  );
                                                              }
                                                              
                                                              // File: contracts/common/EtherTokenConstant.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              // aragonOS and aragon-apps rely on address(0) to denote native ETH, in
                                                              // contracts where both tokens and ETH are accepted
                                                              contract EtherTokenConstant {
                                                                  address internal constant ETH = address(0);
                                                              }
                                                              
                                                              // File: contracts/common/SafeERC20.sol
                                                              
                                                              // Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol)
                                                              // and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143)
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              library SafeERC20 {
                                                                  // Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`:
                                                                  // https://github.com/ethereum/solidity/issues/3544
                                                                  bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb;
                                                              
                                                                  string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED";
                                                                  string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED";
                                                              
                                                                  function invokeAndCheckSuccess(address _addr, bytes memory _calldata)
                                                                      private
                                                                      returns (bool)
                                                                  {
                                                                      bool ret;
                                                                      assembly {
                                                                          let ptr := mload(0x40)    // free memory pointer
                                                              
                                                                          let success := call(
                                                                              gas,                  // forward all gas
                                                                              _addr,                // address
                                                                              0,                    // no value
                                                                              add(_calldata, 0x20), // calldata start
                                                                              mload(_calldata),     // calldata length
                                                                              ptr,                  // write output over free memory
                                                                              0x20                  // uint256 return
                                                                          )
                                                              
                                                                          if gt(success, 0) {
                                                                              // Check number of bytes returned from last function call
                                                                              switch returndatasize
                                                              
                                                                              // No bytes returned: assume success
                                                                              case 0 {
                                                                                  ret := 1
                                                                              }
                                                              
                                                                              // 32 bytes returned: check if non-zero
                                                                              case 0x20 {
                                                                                  // Only return success if returned data was true
                                                                                  // Already have output in ptr
                                                                                  ret := eq(mload(ptr), 1)
                                                                              }
                                                              
                                                                              // Not sure what was returned: don't mark as success
                                                                              default { }
                                                                          }
                                                                      }
                                                                      return ret;
                                                                  }
                                                              
                                                                  function staticInvoke(address _addr, bytes memory _calldata)
                                                                      private
                                                                      view
                                                                      returns (bool, uint256)
                                                                  {
                                                                      bool success;
                                                                      uint256 ret;
                                                                      assembly {
                                                                          let ptr := mload(0x40)    // free memory pointer
                                                              
                                                                          success := staticcall(
                                                                              gas,                  // forward all gas
                                                                              _addr,                // address
                                                                              add(_calldata, 0x20), // calldata start
                                                                              mload(_calldata),     // calldata length
                                                                              ptr,                  // write output over free memory
                                                                              0x20                  // uint256 return
                                                                          )
                                                              
                                                                          if gt(success, 0) {
                                                                              ret := mload(ptr)
                                                                          }
                                                                      }
                                                                      return (success, ret);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) {
                                                                      bytes memory transferCallData = abi.encodeWithSelector(
                                                                          TRANSFER_SELECTOR,
                                                                          _to,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, transferCallData);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
                                                                      bytes memory transferFromCallData = abi.encodeWithSelector(
                                                                          _token.transferFrom.selector,
                                                                          _from,
                                                                          _to,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, transferFromCallData);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) {
                                                                      bytes memory approveCallData = abi.encodeWithSelector(
                                                                          _token.approve.selector,
                                                                          _spender,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, approveCallData);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Static call into ERC20.balanceOf().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) {
                                                                      bytes memory balanceOfCallData = abi.encodeWithSelector(
                                                                          _token.balanceOf.selector,
                                                                          _owner
                                                                      );
                                                              
                                                                      (bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData);
                                                                      require(success, ERROR_TOKEN_BALANCE_REVERTED);
                                                              
                                                                      return tokenBalance;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Static call into ERC20.allowance().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) {
                                                                      bytes memory allowanceCallData = abi.encodeWithSelector(
                                                                          _token.allowance.selector,
                                                                          _owner,
                                                                          _spender
                                                                      );
                                                              
                                                                      (bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData);
                                                                      require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                                                              
                                                                      return allowance;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Static call into ERC20.totalSupply().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticTotalSupply(ERC20 _token) internal view returns (uint256) {
                                                                      bytes memory totalSupplyCallData = abi.encodeWithSelector(_token.totalSupply.selector);
                                                              
                                                                      (bool success, uint256 totalSupply) = staticInvoke(_token, totalSupplyCallData);
                                                                      require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                                                              
                                                                      return totalSupply;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/VaultRecoverable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract {
                                                                  using SafeERC20 for ERC20;
                                                              
                                                                  string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED";
                                                                  string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT";
                                                                  string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED";
                                                              
                                                                  /**
                                                                   * @notice Send funds to recovery Vault. This contract should never receive funds,
                                                                   *         but in case it does, this function allows one to recover them.
                                                                   * @param _token Token balance to be sent to recovery vault.
                                                                   */
                                                                  function transferToVault(address _token) external {
                                                                      require(allowRecoverability(_token), ERROR_DISALLOWED);
                                                                      address vault = getRecoveryVault();
                                                                      require(isContract(vault), ERROR_VAULT_NOT_CONTRACT);
                                                              
                                                                      uint256 balance;
                                                                      if (_token == ETH) {
                                                                          balance = address(this).balance;
                                                                          vault.transfer(balance);
                                                                      } else {
                                                                          ERC20 token = ERC20(_token);
                                                                          balance = token.staticBalanceOf(this);
                                                                          require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED);
                                                                      }
                                                              
                                                                      emit RecoverToVault(vault, _token, balance);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev By default deriving from AragonApp makes it recoverable
                                                                  * @param token Token address that would be recovered
                                                                  * @return bool whether the app allows the recovery
                                                                  */
                                                                  function allowRecoverability(address token) public view returns (bool) {
                                                                      return true;
                                                                  }
                                                              
                                                                  // Cast non-implemented interface to be public so we can use it internally
                                                                  function getRecoveryVault() public view returns (address);
                                                              }
                                                              
                                                              // File: contracts/apps/AppStorage.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract AppStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
                                                                  bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
                                                                  */
                                                                  bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
                                                                  bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
                                                              
                                                                  function kernel() public view returns (IKernel) {
                                                                      return IKernel(KERNEL_POSITION.getStorageAddress());
                                                                  }
                                                              
                                                                  function appId() public view returns (bytes32) {
                                                                      return APP_ID_POSITION.getStorageBytes32();
                                                                  }
                                                              
                                                                  function setKernel(IKernel _kernel) internal {
                                                                      KERNEL_POSITION.setStorageAddress(address(_kernel));
                                                                  }
                                                              
                                                                  function setAppId(bytes32 _appId) internal {
                                                                      APP_ID_POSITION.setStorageBytes32(_appId);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/lib/misc/ERCProxy.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract ERCProxy {
                                                                  uint256 internal constant FORWARDING = 1;
                                                                  uint256 internal constant UPGRADEABLE = 2;
                                                              
                                                                  function proxyType() public pure returns (uint256 proxyTypeId);
                                                                  function implementation() public view returns (address codeAddr);
                                                              }
                                                              
                                                              // File: contracts/common/DelegateProxy.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract DelegateProxy is ERCProxy, IsContract {
                                                                  uint256 internal constant FWD_GAS_LIMIT = 10000;
                                                              
                                                                  /**
                                                                  * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
                                                                  * @param _dst Destination address to perform the delegatecall
                                                                  * @param _calldata Calldata for the delegatecall
                                                                  */
                                                                  function delegatedFwd(address _dst, bytes _calldata) internal {
                                                                      require(isContract(_dst));
                                                                      uint256 fwdGasLimit = FWD_GAS_LIMIT;
                                                              
                                                                      assembly {
                                                                          let result := delegatecall(sub(gas, fwdGasLimit), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
                                                                          let size := returndatasize
                                                                          let ptr := mload(0x40)
                                                                          returndatacopy(ptr, 0, size)
                                                              
                                                                          // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
                                                                          // if the call returned error data, forward it
                                                                          switch result case 0 { revert(ptr, size) }
                                                                          default { return(ptr, size) }
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/DepositableStorage.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              contract DepositableStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  // keccak256("aragonOS.depositableStorage.depositable")
                                                                  bytes32 internal constant DEPOSITABLE_POSITION = 0x665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea;
                                                              
                                                                  function isDepositable() public view returns (bool) {
                                                                      return DEPOSITABLE_POSITION.getStorageBool();
                                                                  }
                                                              
                                                                  function setDepositable(bool _depositable) internal {
                                                                      DEPOSITABLE_POSITION.setStorageBool(_depositable);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/DepositableDelegateProxy.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract DepositableDelegateProxy is DepositableStorage, DelegateProxy {
                                                                  event ProxyDeposit(address sender, uint256 value);
                                                              
                                                                  function () external payable {
                                                                      uint256 forwardGasThreshold = FWD_GAS_LIMIT;
                                                                      bytes32 isDepositablePosition = DEPOSITABLE_POSITION;
                                                              
                                                                      // Optimized assembly implementation to prevent EIP-1884 from breaking deposits, reference code in Solidity:
                                                                      // https://github.com/aragon/aragonOS/blob/v4.2.1/contracts/common/DepositableDelegateProxy.sol#L10-L20
                                                                      assembly {
                                                                          // Continue only if the gas left is lower than the threshold for forwarding to the implementation code,
                                                                          // otherwise continue outside of the assembly block.
                                                                          if lt(gas, forwardGasThreshold) {
                                                                              // Only accept the deposit and emit an event if all of the following are true:
                                                                              // the proxy accepts deposits (isDepositable), msg.data.length == 0, and msg.value > 0
                                                                              if and(and(sload(isDepositablePosition), iszero(calldatasize)), gt(callvalue, 0)) {
                                                                                  // Equivalent Solidity code for emitting the event:
                                                                                  // emit ProxyDeposit(msg.sender, msg.value);
                                                              
                                                                                  let logData := mload(0x40) // free memory pointer
                                                                                  mstore(logData, caller) // add 'msg.sender' to the log data (first event param)
                                                                                  mstore(add(logData, 0x20), callvalue) // add 'msg.value' to the log data (second event param)
                                                              
                                                                                  // Emit an event with one topic to identify the event: keccak256('ProxyDeposit(address,uint256)') = 0x15ee...dee1
                                                                                  log1(logData, 0x40, 0x15eeaa57c7bd188c1388020bcadc2c436ec60d647d36ef5b9eb3c742217ddee1)
                                                              
                                                                                  stop() // Stop. Exits execution context
                                                                              }
                                                              
                                                                              // If any of above checks failed, revert the execution (if ETH was sent, it is returned to the sender)
                                                                              revert(0, 0)
                                                                          }
                                                                      }
                                                              
                                                                      address target = implementation();
                                                                      delegatedFwd(target, msg.data);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyBase.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract AppProxyBase is AppStorage, DepositableDelegateProxy, KernelNamespaceConstants {
                                                                  /**
                                                                  * @dev Initialize AppProxy
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public {
                                                                      setKernel(_kernel);
                                                                      setAppId(_appId);
                                                              
                                                                      // Implicit check that kernel is actually a Kernel
                                                                      // The EVM doesn't actually provide a way for us to make sure, but we can force a revert to
                                                                      // occur if the kernel is set to 0x0 or a non-code address when we try to call a method on
                                                                      // it.
                                                                      address appCode = getAppBase(_appId);
                                                              
                                                                      // If initialize payload is provided, it will be executed
                                                                      if (_initializePayload.length > 0) {
                                                                          require(isContract(appCode));
                                                                          // Cannot make delegatecall as a delegateproxy.delegatedFwd as it
                                                                          // returns ending execution context and halts contract deployment
                                                                          require(appCode.delegatecall(_initializePayload));
                                                                      }
                                                                  }
                                                              
                                                                  function getAppBase(bytes32 _appId) internal view returns (address) {
                                                                      return kernel().getApp(KERNEL_APP_BASES_NAMESPACE, _appId);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyUpgradeable.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              contract AppProxyUpgradeable is AppProxyBase {
                                                                  /**
                                                                  * @dev Initialize AppProxyUpgradeable (makes it an upgradeable Aragon app)
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload)
                                                                      AppProxyBase(_kernel, _appId, _initializePayload)
                                                                      public // solium-disable-line visibility-first
                                                                  {
                                                                      // solium-disable-previous-line no-empty-blocks
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, the address the proxy would delegate calls to
                                                                   */
                                                                  function implementation() public view returns (address) {
                                                                      return getAppBase(appId());
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                                                                   */
                                                                  function proxyType() public pure returns (uint256 proxyTypeId) {
                                                                      return UPGRADEABLE;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyPinned.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract AppProxyPinned is IsContract, AppProxyBase {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  // keccak256("aragonOS.appStorage.pinnedCode")
                                                                  bytes32 internal constant PINNED_CODE_POSITION = 0xdee64df20d65e53d7f51cb6ab6d921a0a6a638a91e942e1d8d02df28e31c038e;
                                                              
                                                                  /**
                                                                  * @dev Initialize AppProxyPinned (makes it an un-upgradeable Aragon app)
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload)
                                                                      AppProxyBase(_kernel, _appId, _initializePayload)
                                                                      public // solium-disable-line visibility-first
                                                                  {
                                                                      setPinnedCode(getAppBase(_appId));
                                                                      require(isContract(pinnedCode()));
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, the address the proxy would delegate calls to
                                                                   */
                                                                  function implementation() public view returns (address) {
                                                                      return pinnedCode();
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                                                                   */
                                                                  function proxyType() public pure returns (uint256 proxyTypeId) {
                                                                      return FORWARDING;
                                                                  }
                                                              
                                                                  function setPinnedCode(address _pinnedCode) internal {
                                                                      PINNED_CODE_POSITION.setStorageAddress(_pinnedCode);
                                                                  }
                                                              
                                                                  function pinnedCode() internal view returns (address) {
                                                                      return PINNED_CODE_POSITION.getStorageAddress();
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/factory/AppProxyFactory.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract AppProxyFactory {
                                                                  event NewAppProxy(address proxy, bool isUpgradeable, bytes32 appId);
                                                              
                                                                  /**
                                                                  * @notice Create a new upgradeable app instance on `_kernel` with identifier `_appId`
                                                                  * @param _kernel App's Kernel reference
                                                                  * @param _appId Identifier for app
                                                                  * @return AppProxyUpgradeable
                                                                  */
                                                                  function newAppProxy(IKernel _kernel, bytes32 _appId) public returns (AppProxyUpgradeable) {
                                                                      return newAppProxy(_kernel, _appId, new bytes(0));
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Create a new upgradeable app instance on `_kernel` with identifier `_appId` and initialization payload `_initializePayload`
                                                                  * @param _kernel App's Kernel reference
                                                                  * @param _appId Identifier for app
                                                                  * @return AppProxyUpgradeable
                                                                  */
                                                                  function newAppProxy(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public returns (AppProxyUpgradeable) {
                                                                      AppProxyUpgradeable proxy = new AppProxyUpgradeable(_kernel, _appId, _initializePayload);
                                                                      emit NewAppProxy(address(proxy), true, _appId);
                                                                      return proxy;
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Create a new pinned app instance on `_kernel` with identifier `_appId`
                                                                  * @param _kernel App's Kernel reference
                                                                  * @param _appId Identifier for app
                                                                  * @return AppProxyPinned
                                                                  */
                                                                  function newAppProxyPinned(IKernel _kernel, bytes32 _appId) public returns (AppProxyPinned) {
                                                                      return newAppProxyPinned(_kernel, _appId, new bytes(0));
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Create a new pinned app instance on `_kernel` with identifier `_appId` and initialization payload `_initializePayload`
                                                                  * @param _kernel App's Kernel reference
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Proxy initialization payload
                                                                  * @return AppProxyPinned
                                                                  */
                                                                  function newAppProxyPinned(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public returns (AppProxyPinned) {
                                                                      AppProxyPinned proxy = new AppProxyPinned(_kernel, _appId, _initializePayload);
                                                                      emit NewAppProxy(address(proxy), false, _appId);
                                                                      return proxy;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/kernel/Kernel.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              // solium-disable-next-line max-len
                                                              contract Kernel is IKernel, KernelStorage, KernelAppIds, KernelNamespaceConstants, Petrifiable, IsContract, VaultRecoverable, AppProxyFactory, ACLSyntaxSugar {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 public constant APP_MANAGER_ROLE = keccak256("APP_MANAGER_ROLE");
                                                                  */
                                                                  bytes32 public constant APP_MANAGER_ROLE = 0xb6d92708f3d4817afc106147d969e229ced5c46e65e0a5002a0d391287762bd0;
                                                              
                                                                  string private constant ERROR_APP_NOT_CONTRACT = "KERNEL_APP_NOT_CONTRACT";
                                                                  string private constant ERROR_INVALID_APP_CHANGE = "KERNEL_INVALID_APP_CHANGE";
                                                                  string private constant ERROR_AUTH_FAILED = "KERNEL_AUTH_FAILED";
                                                              
                                                                  /**
                                                                  * @dev Constructor that allows the deployer to choose if the base instance should be petrified immediately.
                                                                  * @param _shouldPetrify Immediately petrify this instance so that it can never be initialized
                                                                  */
                                                                  constructor(bool _shouldPetrify) public {
                                                                      if (_shouldPetrify) {
                                                                          petrify();
                                                                      }
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Initialize can only be called once. It saves the block number in which it was initialized.
                                                                  * @notice Initialize this kernel instance along with its ACL and set `_permissionsCreator` as the entity that can create other permissions
                                                                  * @param _baseAcl Address of base ACL app
                                                                  * @param _permissionsCreator Entity that will be given permission over createPermission
                                                                  */
                                                                  function initialize(IACL _baseAcl, address _permissionsCreator) public onlyInit {
                                                                      initialized();
                                                              
                                                                      // Set ACL base
                                                                      _setApp(KERNEL_APP_BASES_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID, _baseAcl);
                                                              
                                                                      // Create ACL instance and attach it as the default ACL app
                                                                      IACL acl = IACL(newAppProxy(this, KERNEL_DEFAULT_ACL_APP_ID));
                                                                      acl.initialize(_permissionsCreator);
                                                                      _setApp(KERNEL_APP_ADDR_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID, acl);
                                                              
                                                                      recoveryVaultAppId = KERNEL_DEFAULT_VAULT_APP_ID;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Create a new instance of an app linked to this kernel
                                                                  * @notice Create a new upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`
                                                                  * @param _appId Identifier for app
                                                                  * @param _appBase Address of the app's base implementation
                                                                  * @return AppProxy instance
                                                                  */
                                                                  function newAppInstance(bytes32 _appId, address _appBase)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                                                                      returns (ERCProxy appProxy)
                                                                  {
                                                                      return newAppInstance(_appId, _appBase, new bytes(0), false);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Create a new instance of an app linked to this kernel and set its base
                                                                  *      implementation if it was not already set
                                                                  * @notice Create a new upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`. `_setDefault ? 'Also sets it as the default app instance.':''`
                                                                  * @param _appId Identifier for app
                                                                  * @param _appBase Address of the app's base implementation
                                                                  * @param _initializePayload Payload for call made by the proxy during its construction to initialize
                                                                  * @param _setDefault Whether the app proxy app is the default one.
                                                                  *        Useful when the Kernel needs to know of an instance of a particular app,
                                                                  *        like Vault for escape hatch mechanism.
                                                                  * @return AppProxy instance
                                                                  */
                                                                  function newAppInstance(bytes32 _appId, address _appBase, bytes _initializePayload, bool _setDefault)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                                                                      returns (ERCProxy appProxy)
                                                                  {
                                                                      _setAppIfNew(KERNEL_APP_BASES_NAMESPACE, _appId, _appBase);
                                                                      appProxy = newAppProxy(this, _appId, _initializePayload);
                                                                      // By calling setApp directly and not the internal functions, we make sure the params are checked
                                                                      // and it will only succeed if sender has permissions to set something to the namespace.
                                                                      if (_setDefault) {
                                                                          setApp(KERNEL_APP_ADDR_NAMESPACE, _appId, appProxy);
                                                                      }
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Create a new pinned instance of an app linked to this kernel
                                                                  * @notice Create a new non-upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`.
                                                                  * @param _appId Identifier for app
                                                                  * @param _appBase Address of the app's base implementation
                                                                  * @return AppProxy instance
                                                                  */
                                                                  function newPinnedAppInstance(bytes32 _appId, address _appBase)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                                                                      returns (ERCProxy appProxy)
                                                                  {
                                                                      return newPinnedAppInstance(_appId, _appBase, new bytes(0), false);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Create a new pinned instance of an app linked to this kernel and set
                                                                  *      its base implementation if it was not already set
                                                                  * @notice Create a new non-upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`. `_setDefault ? 'Also sets it as the default app instance.':''`
                                                                  * @param _appId Identifier for app
                                                                  * @param _appBase Address of the app's base implementation
                                                                  * @param _initializePayload Payload for call made by the proxy during its construction to initialize
                                                                  * @param _setDefault Whether the app proxy app is the default one.
                                                                  *        Useful when the Kernel needs to know of an instance of a particular app,
                                                                  *        like Vault for escape hatch mechanism.
                                                                  * @return AppProxy instance
                                                                  */
                                                                  function newPinnedAppInstance(bytes32 _appId, address _appBase, bytes _initializePayload, bool _setDefault)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                                                                      returns (ERCProxy appProxy)
                                                                  {
                                                                      _setAppIfNew(KERNEL_APP_BASES_NAMESPACE, _appId, _appBase);
                                                                      appProxy = newAppProxyPinned(this, _appId, _initializePayload);
                                                                      // By calling setApp directly and not the internal functions, we make sure the params are checked
                                                                      // and it will only succeed if sender has permissions to set something to the namespace.
                                                                      if (_setDefault) {
                                                                          setApp(KERNEL_APP_ADDR_NAMESPACE, _appId, appProxy);
                                                                      }
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Set the resolving address of an app instance or base implementation
                                                                  * @notice Set the resolving address of `_appId` in namespace `_namespace` to `_app`
                                                                  * @param _namespace App namespace to use
                                                                  * @param _appId Identifier for app
                                                                  * @param _app Address of the app instance or base implementation
                                                                  * @return ID of app
                                                                  */
                                                                  function setApp(bytes32 _namespace, bytes32 _appId, address _app)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(_namespace, _appId))
                                                                  {
                                                                      _setApp(_namespace, _appId, _app);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Set the default vault id for the escape hatch mechanism
                                                                  * @param _recoveryVaultAppId Identifier of the recovery vault app
                                                                  */
                                                                  function setRecoveryVaultAppId(bytes32 _recoveryVaultAppId)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_ADDR_NAMESPACE, _recoveryVaultAppId))
                                                                  {
                                                                      recoveryVaultAppId = _recoveryVaultAppId;
                                                                  }
                                                              
                                                                  // External access to default app id and namespace constants to mimic default getters for constants
                                                                  /* solium-disable function-order, mixedcase */
                                                                  function CORE_NAMESPACE() external pure returns (bytes32) { return KERNEL_CORE_NAMESPACE; }
                                                                  function APP_BASES_NAMESPACE() external pure returns (bytes32) { return KERNEL_APP_BASES_NAMESPACE; }
                                                                  function APP_ADDR_NAMESPACE() external pure returns (bytes32) { return KERNEL_APP_ADDR_NAMESPACE; }
                                                                  function KERNEL_APP_ID() external pure returns (bytes32) { return KERNEL_CORE_APP_ID; }
                                                                  function DEFAULT_ACL_APP_ID() external pure returns (bytes32) { return KERNEL_DEFAULT_ACL_APP_ID; }
                                                                  /* solium-enable function-order, mixedcase */
                                                              
                                                                  /**
                                                                  * @dev Get the address of an app instance or base implementation
                                                                  * @param _namespace App namespace to use
                                                                  * @param _appId Identifier for app
                                                                  * @return Address of the app
                                                                  */
                                                                  function getApp(bytes32 _namespace, bytes32 _appId) public view returns (address) {
                                                                      return apps[_namespace][_appId];
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Get the address of the recovery Vault instance (to recover funds)
                                                                  * @return Address of the Vault
                                                                  */
                                                                  function getRecoveryVault() public view returns (address) {
                                                                      return apps[KERNEL_APP_ADDR_NAMESPACE][recoveryVaultAppId];
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Get the installed ACL app
                                                                  * @return ACL app
                                                                  */
                                                                  function acl() public view returns (IACL) {
                                                                      return IACL(getApp(KERNEL_APP_ADDR_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID));
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Function called by apps to check ACL on kernel or to check permission status
                                                                  * @param _who Sender of the original call
                                                                  * @param _where Address of the app
                                                                  * @param _what Identifier for a group of actions in app
                                                                  * @param _how Extra data for ACL auth
                                                                  * @return Boolean indicating whether the ACL allows the role or not.
                                                                  *         Always returns false if the kernel hasn't been initialized yet.
                                                                  */
                                                                  function hasPermission(address _who, address _where, bytes32 _what, bytes _how) public view returns (bool) {
                                                                      IACL defaultAcl = acl();
                                                                      return address(defaultAcl) != address(0) && // Poor man's initialization check (saves gas)
                                                                          defaultAcl.hasPermission(_who, _where, _what, _how);
                                                                  }
                                                              
                                                                  function _setApp(bytes32 _namespace, bytes32 _appId, address _app) internal {
                                                                      require(isContract(_app), ERROR_APP_NOT_CONTRACT);
                                                                      apps[_namespace][_appId] = _app;
                                                                      emit SetApp(_namespace, _appId, _app);
                                                                  }
                                                              
                                                                  function _setAppIfNew(bytes32 _namespace, bytes32 _appId, address _app) internal {
                                                                      address app = getApp(_namespace, _appId);
                                                                      if (app != address(0)) {
                                                                          // The only way to set an app is if it passes the isContract check, so no need to check it again
                                                                          require(app == _app, ERROR_INVALID_APP_CHANGE);
                                                                      } else {
                                                                          _setApp(_namespace, _appId, _app);
                                                                      }
                                                                  }
                                                              
                                                                  modifier auth(bytes32 _role, uint256[] memory _params) {
                                                                      require(
                                                                          hasPermission(msg.sender, address(this), _role, ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)),
                                                                          ERROR_AUTH_FAILED
                                                                      );
                                                                      _;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/kernel/KernelProxy.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract KernelProxy is IKernelEvents, KernelStorage, KernelAppIds, KernelNamespaceConstants, IsContract, DepositableDelegateProxy {
                                                                  /**
                                                                  * @dev KernelProxy is a proxy contract to a kernel implementation. The implementation
                                                                  *      can update the reference, which effectively upgrades the contract
                                                                  * @param _kernelImpl Address of the contract used as implementation for kernel
                                                                  */
                                                                  constructor(IKernel _kernelImpl) public {
                                                                      require(isContract(address(_kernelImpl)));
                                                                      apps[KERNEL_CORE_NAMESPACE][KERNEL_CORE_APP_ID] = _kernelImpl;
                                                              
                                                                      // Note that emitting this event is important for verifying that a KernelProxy instance
                                                                      // was never upgraded to a malicious Kernel logic contract over its lifespan.
                                                                      // This starts the "chain of trust", that can be followed through later SetApp() events
                                                                      // emitted during kernel upgrades.
                                                                      emit SetApp(KERNEL_CORE_NAMESPACE, KERNEL_CORE_APP_ID, _kernelImpl);
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                                                                   */
                                                                  function proxyType() public pure returns (uint256 proxyTypeId) {
                                                                      return UPGRADEABLE;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev ERC897, the address the proxy would delegate calls to
                                                                  */
                                                                  function implementation() public view returns (address) {
                                                                      return apps[KERNEL_CORE_NAMESPACE][KERNEL_CORE_APP_ID];
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/Autopetrified.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              contract Autopetrified is Petrifiable {
                                                                  constructor() public {
                                                                      // Immediately petrify base (non-proxy) instances of inherited contracts on deploy.
                                                                      // This renders them uninitializable (and unusable without a proxy).
                                                                      petrify();
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/ReentrancyGuard.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              contract ReentrancyGuard {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant REENTRANCY_MUTEX_POSITION = keccak256("aragonOS.reentrancyGuard.mutex");
                                                                  */
                                                                  bytes32 private constant REENTRANCY_MUTEX_POSITION = 0xe855346402235fdd185c890e68d2c4ecad599b88587635ee285bce2fda58dacb;
                                                              
                                                                  string private constant ERROR_REENTRANT = "REENTRANCY_REENTRANT_CALL";
                                                              
                                                                  modifier nonReentrant() {
                                                                      // Ensure mutex is unlocked
                                                                      require(!REENTRANCY_MUTEX_POSITION.getStorageBool(), ERROR_REENTRANT);
                                                              
                                                                      // Lock mutex before function call
                                                                      REENTRANCY_MUTEX_POSITION.setStorageBool(true);
                                                              
                                                                      // Perform function call
                                                                      _;
                                                              
                                                                      // Unlock mutex after function call
                                                                      REENTRANCY_MUTEX_POSITION.setStorageBool(false);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/evmscript/IEVMScriptExecutor.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IEVMScriptExecutor {
                                                                  function execScript(bytes script, bytes input, address[] blacklist) external returns (bytes);
                                                                  function executorType() external pure returns (bytes32);
                                                              }
                                                              
                                                              // File: contracts/evmscript/IEVMScriptRegistry.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              contract EVMScriptRegistryConstants {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = apmNamehash("evmreg");
                                                                  */
                                                                  bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = 0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61;
                                                              }
                                                              
                                                              
                                                              interface IEVMScriptRegistry {
                                                                  function addScriptExecutor(IEVMScriptExecutor executor) external returns (uint id);
                                                                  function disableScriptExecutor(uint256 executorId) external;
                                                              
                                                                  // TODO: this should be external
                                                                  // See https://github.com/ethereum/solidity/issues/4832
                                                                  function getScriptExecutor(bytes script) public view returns (IEVMScriptExecutor);
                                                              }
                                                              
                                                              // File: contracts/evmscript/EVMScriptRunner.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract EVMScriptRunner is AppStorage, Initializable, EVMScriptRegistryConstants, KernelNamespaceConstants {
                                                                  string private constant ERROR_EXECUTOR_UNAVAILABLE = "EVMRUN_EXECUTOR_UNAVAILABLE";
                                                                  string private constant ERROR_PROTECTED_STATE_MODIFIED = "EVMRUN_PROTECTED_STATE_MODIFIED";
                                                              
                                                                  /* This is manually crafted in assembly
                                                                  string private constant ERROR_EXECUTOR_INVALID_RETURN = "EVMRUN_EXECUTOR_INVALID_RETURN";
                                                                  */
                                                              
                                                                  event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData);
                                                              
                                                                  function getEVMScriptExecutor(bytes _script) public view returns (IEVMScriptExecutor) {
                                                                      return IEVMScriptExecutor(getEVMScriptRegistry().getScriptExecutor(_script));
                                                                  }
                                                              
                                                                  function getEVMScriptRegistry() public view returns (IEVMScriptRegistry) {
                                                                      address registryAddr = kernel().getApp(KERNEL_APP_ADDR_NAMESPACE, EVMSCRIPT_REGISTRY_APP_ID);
                                                                      return IEVMScriptRegistry(registryAddr);
                                                                  }
                                                              
                                                                  function runScript(bytes _script, bytes _input, address[] _blacklist)
                                                                      internal
                                                                      isInitialized
                                                                      protectState
                                                                      returns (bytes)
                                                                  {
                                                                      IEVMScriptExecutor executor = getEVMScriptExecutor(_script);
                                                                      require(address(executor) != address(0), ERROR_EXECUTOR_UNAVAILABLE);
                                                              
                                                                      bytes4 sig = executor.execScript.selector;
                                                                      bytes memory data = abi.encodeWithSelector(sig, _script, _input, _blacklist);
                                                              
                                                                      bytes memory output;
                                                                      assembly {
                                                                          let success := delegatecall(
                                                                              gas,                // forward all gas
                                                                              executor,           // address
                                                                              add(data, 0x20),    // calldata start
                                                                              mload(data),        // calldata length
                                                                              0,                  // don't write output (we'll handle this ourselves)
                                                                              0                   // don't write output
                                                                          )
                                                              
                                                                          output := mload(0x40) // free mem ptr get
                                                              
                                                                          switch success
                                                                          case 0 {
                                                                              // If the call errored, forward its full error data
                                                                              returndatacopy(output, 0, returndatasize)
                                                                              revert(output, returndatasize)
                                                                          }
                                                                          default {
                                                                              switch gt(returndatasize, 0x3f)
                                                                              case 0 {
                                                                                  // Need at least 0x40 bytes returned for properly ABI-encoded bytes values,
                                                                                  // revert with "EVMRUN_EXECUTOR_INVALID_RETURN"
                                                                                  // See remix: doing a `revert("EVMRUN_EXECUTOR_INVALID_RETURN")` always results in
                                                                                  // this memory layout
                                                                                  mstore(output, 0x08c379a000000000000000000000000000000000000000000000000000000000)         // error identifier
                                                                                  mstore(add(output, 0x04), 0x0000000000000000000000000000000000000000000000000000000000000020) // starting offset
                                                                                  mstore(add(output, 0x24), 0x000000000000000000000000000000000000000000000000000000000000001e) // reason length
                                                                                  mstore(add(output, 0x44), 0x45564d52554e5f4558454355544f525f494e56414c49445f52455455524e0000) // reason
                                                              
                                                                                  revert(output, 100) // 100 = 4 + 3 * 32 (error identifier + 3 words for the ABI encoded error)
                                                                              }
                                                                              default {
                                                                                  // Copy result
                                                                                  //
                                                                                  // Needs to perform an ABI decode for the expected `bytes` return type of
                                                                                  // `executor.execScript()` as solidity will automatically ABI encode the returned bytes as:
                                                                                  //    [ position of the first dynamic length return value = 0x20 (32 bytes) ]
                                                                                  //    [ output length (32 bytes) ]
                                                                                  //    [ output content (N bytes) ]
                                                                                  //
                                                                                  // Perform the ABI decode by ignoring the first 32 bytes of the return data
                                                                                  let copysize := sub(returndatasize, 0x20)
                                                                                  returndatacopy(output, 0x20, copysize)
                                                              
                                                                                  mstore(0x40, add(output, copysize)) // free mem ptr set
                                                                              }
                                                                          }
                                                                      }
                                                              
                                                                      emit ScriptResult(address(executor), _script, _input, output);
                                                              
                                                                      return output;
                                                                  }
                                                              
                                                                  modifier protectState {
                                                                      address preKernel = address(kernel());
                                                                      bytes32 preAppId = appId();
                                                                      _; // exec
                                                                      require(address(kernel()) == preKernel, ERROR_PROTECTED_STATE_MODIFIED);
                                                                      require(appId() == preAppId, ERROR_PROTECTED_STATE_MODIFIED);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/apps/AragonApp.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              // Contracts inheriting from AragonApp are, by default, immediately petrified upon deployment so
                                                              // that they can never be initialized.
                                                              // Unless overriden, this behaviour enforces those contracts to be usable only behind an AppProxy.
                                                              // ReentrancyGuard, EVMScriptRunner, and ACLSyntaxSugar are not directly used by this contract, but
                                                              // are included so that they are automatically usable by subclassing contracts
                                                              contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGuard, EVMScriptRunner, ACLSyntaxSugar {
                                                                  string private constant ERROR_AUTH_FAILED = "APP_AUTH_FAILED";
                                                              
                                                                  modifier auth(bytes32 _role) {
                                                                      require(canPerform(msg.sender, _role, new uint256[](0)), ERROR_AUTH_FAILED);
                                                                      _;
                                                                  }
                                                              
                                                                  modifier authP(bytes32 _role, uint256[] _params) {
                                                                      require(canPerform(msg.sender, _role, _params), ERROR_AUTH_FAILED);
                                                                      _;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Check whether an action can be performed by a sender for a particular role on this app
                                                                  * @param _sender Sender of the call
                                                                  * @param _role Role on this app
                                                                  * @param _params Permission params for the role
                                                                  * @return Boolean indicating whether the sender has the permissions to perform the action.
                                                                  *         Always returns false if the app hasn't been initialized yet.
                                                                  */
                                                                  function canPerform(address _sender, bytes32 _role, uint256[] _params) public view returns (bool) {
                                                                      if (!hasInitialized()) {
                                                                          return false;
                                                                      }
                                                              
                                                                      IKernel linkedKernel = kernel();
                                                                      if (address(linkedKernel) == address(0)) {
                                                                          return false;
                                                                      }
                                                              
                                                                      return linkedKernel.hasPermission(
                                                                          _sender,
                                                                          address(this),
                                                                          _role,
                                                                          ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)
                                                                      );
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Get the recovery vault for the app
                                                                  * @return Recovery vault address for the app
                                                                  */
                                                                  function getRecoveryVault() public view returns (address) {
                                                                      // Funds recovery via a vault is only available when used with a kernel
                                                                      return kernel().getRecoveryVault(); // if kernel is not set, it will revert
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/acl/IACLOracle.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IACLOracle {
                                                                  function canPerform(address who, address where, bytes32 what, uint256[] how) external view returns (bool);
                                                              }
                                                              
                                                              // File: contracts/acl/ACL.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              /* solium-disable function-order */
                                                              // Allow public initialize() to be first
                                                              contract ACL is IACL, TimeHelpers, AragonApp, ACLHelpers {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 public constant CREATE_PERMISSIONS_ROLE = keccak256("CREATE_PERMISSIONS_ROLE");
                                                                  */
                                                                  bytes32 public constant CREATE_PERMISSIONS_ROLE = 0x0b719b33c83b8e5d300c521cb8b54ae9bd933996a14bef8c2f4e0285d2d2400a;
                                                              
                                                                  enum Op { NONE, EQ, NEQ, GT, LT, GTE, LTE, RET, NOT, AND, OR, XOR, IF_ELSE } // op types
                                                              
                                                                  struct Param {
                                                                      uint8 id;
                                                                      uint8 op;
                                                                      uint240 value; // even though value is an uint240 it can store addresses
                                                                      // in the case of 32 byte hashes losing 2 bytes precision isn't a huge deal
                                                                      // op and id take less than 1 byte each so it can be kept in 1 sstore
                                                                  }
                                                              
                                                                  uint8 internal constant BLOCK_NUMBER_PARAM_ID = 200;
                                                                  uint8 internal constant TIMESTAMP_PARAM_ID    = 201;
                                                                  // 202 is unused
                                                                  uint8 internal constant ORACLE_PARAM_ID       = 203;
                                                                  uint8 internal constant LOGIC_OP_PARAM_ID     = 204;
                                                                  uint8 internal constant PARAM_VALUE_PARAM_ID  = 205;
                                                                  // TODO: Add execution times param type?
                                                              
                                                                  /* Hardcoded constant to save gas
                                                                  bytes32 public constant EMPTY_PARAM_HASH = keccak256(uint256(0));
                                                                  */
                                                                  bytes32 public constant EMPTY_PARAM_HASH = 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563;
                                                                  bytes32 public constant NO_PERMISSION = bytes32(0);
                                                                  address public constant ANY_ENTITY = address(-1);
                                                                  address public constant BURN_ENTITY = address(1); // address(0) is already used as "no permission manager"
                                                              
                                                                  string private constant ERROR_AUTH_INIT_KERNEL = "ACL_AUTH_INIT_KERNEL";
                                                                  string private constant ERROR_AUTH_NO_MANAGER = "ACL_AUTH_NO_MANAGER";
                                                                  string private constant ERROR_EXISTENT_MANAGER = "ACL_EXISTENT_MANAGER";
                                                              
                                                                  // Whether someone has a permission
                                                                  mapping (bytes32 => bytes32) internal permissions; // permissions hash => params hash
                                                                  mapping (bytes32 => Param[]) internal permissionParams; // params hash => params
                                                              
                                                                  // Who is the manager of a permission
                                                                  mapping (bytes32 => address) internal permissionManager;
                                                              
                                                                  event SetPermission(address indexed entity, address indexed app, bytes32 indexed role, bool allowed);
                                                                  event SetPermissionParams(address indexed entity, address indexed app, bytes32 indexed role, bytes32 paramsHash);
                                                                  event ChangePermissionManager(address indexed app, bytes32 indexed role, address indexed manager);
                                                              
                                                                  modifier onlyPermissionManager(address _app, bytes32 _role) {
                                                                      require(msg.sender == getPermissionManager(_app, _role), ERROR_AUTH_NO_MANAGER);
                                                                      _;
                                                                  }
                                                              
                                                                  modifier noPermissionManager(address _app, bytes32 _role) {
                                                                      // only allow permission creation (or re-creation) when there is no manager
                                                                      require(getPermissionManager(_app, _role) == address(0), ERROR_EXISTENT_MANAGER);
                                                                      _;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Initialize can only be called once. It saves the block number in which it was initialized.
                                                                  * @notice Initialize an ACL instance and set `_permissionsCreator` as the entity that can create other permissions
                                                                  * @param _permissionsCreator Entity that will be given permission over createPermission
                                                                  */
                                                                  function initialize(address _permissionsCreator) public onlyInit {
                                                                      initialized();
                                                                      require(msg.sender == address(kernel()), ERROR_AUTH_INIT_KERNEL);
                                                              
                                                                      _createPermission(_permissionsCreator, this, CREATE_PERMISSIONS_ROLE, _permissionsCreator);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Creates a permission that wasn't previously set and managed.
                                                                  *      If a created permission is removed it is possible to reset it with createPermission.
                                                                  *      This is the **ONLY** way to create permissions and set managers to permissions that don't
                                                                  *      have a manager.
                                                                  *      In terms of the ACL being initialized, this function implicitly protects all the other
                                                                  *      state-changing external functions, as they all require the sender to be a manager.
                                                                  * @notice Create a new permission granting `_entity` the ability to perform actions requiring `_role` on `_app`, setting `_manager` as the permission's manager
                                                                  * @param _entity Address of the whitelisted entity that will be able to perform the role
                                                                  * @param _app Address of the app in which the role will be allowed (requires app to depend on kernel for ACL)
                                                                  * @param _role Identifier for the group of actions in app given access to perform
                                                                  * @param _manager Address of the entity that will be able to grant and revoke the permission further.
                                                                  */
                                                                  function createPermission(address _entity, address _app, bytes32 _role, address _manager)
                                                                      external
                                                                      auth(CREATE_PERMISSIONS_ROLE)
                                                                      noPermissionManager(_app, _role)
                                                                  {
                                                                      _createPermission(_entity, _app, _role, _manager);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Grants permission if allowed. This requires `msg.sender` to be the permission manager
                                                                  * @notice Grant `_entity` the ability to perform actions requiring `_role` on `_app`
                                                                  * @param _entity Address of the whitelisted entity that will be able to perform the role
                                                                  * @param _app Address of the app in which the role will be allowed (requires app to depend on kernel for ACL)
                                                                  * @param _role Identifier for the group of actions in app given access to perform
                                                                  */
                                                                  function grantPermission(address _entity, address _app, bytes32 _role)
                                                                      external
                                                                  {
                                                                      grantPermissionP(_entity, _app, _role, new uint256[](0));
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Grants a permission with parameters if allowed. This requires `msg.sender` to be the permission manager
                                                                  * @notice Grant `_entity` the ability to perform actions requiring `_role` on `_app`
                                                                  * @param _entity Address of the whitelisted entity that will be able to perform the role
                                                                  * @param _app Address of the app in which the role will be allowed (requires app to depend on kernel for ACL)
                                                                  * @param _role Identifier for the group of actions in app given access to perform
                                                                  * @param _params Permission parameters
                                                                  */
                                                                  function grantPermissionP(address _entity, address _app, bytes32 _role, uint256[] _params)
                                                                      public
                                                                      onlyPermissionManager(_app, _role)
                                                                  {
                                                                      bytes32 paramsHash = _params.length > 0 ? _saveParams(_params) : EMPTY_PARAM_HASH;
                                                                      _setPermission(_entity, _app, _role, paramsHash);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Revokes permission if allowed. This requires `msg.sender` to be the the permission manager
                                                                  * @notice Revoke from `_entity` the ability to perform actions requiring `_role` on `_app`
                                                                  * @param _entity Address of the whitelisted entity to revoke access from
                                                                  * @param _app Address of the app in which the role will be revoked
                                                                  * @param _role Identifier for the group of actions in app being revoked
                                                                  */
                                                                  function revokePermission(address _entity, address _app, bytes32 _role)
                                                                      external
                                                                      onlyPermissionManager(_app, _role)
                                                                  {
                                                                      _setPermission(_entity, _app, _role, NO_PERMISSION);
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Set `_newManager` as the manager of `_role` in `_app`
                                                                  * @param _newManager Address for the new manager
                                                                  * @param _app Address of the app in which the permission management is being transferred
                                                                  * @param _role Identifier for the group of actions being transferred
                                                                  */
                                                                  function setPermissionManager(address _newManager, address _app, bytes32 _role)
                                                                      external
                                                                      onlyPermissionManager(_app, _role)
                                                                  {
                                                                      _setPermissionManager(_newManager, _app, _role);
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Remove the manager of `_role` in `_app`
                                                                  * @param _app Address of the app in which the permission is being unmanaged
                                                                  * @param _role Identifier for the group of actions being unmanaged
                                                                  */
                                                                  function removePermissionManager(address _app, bytes32 _role)
                                                                      external
                                                                      onlyPermissionManager(_app, _role)
                                                                  {
                                                                      _setPermissionManager(address(0), _app, _role);
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Burn non-existent `_role` in `_app`, so no modification can be made to it (grant, revoke, permission manager)
                                                                  * @param _app Address of the app in which the permission is being burned
                                                                  * @param _role Identifier for the group of actions being burned
                                                                  */
                                                                  function createBurnedPermission(address _app, bytes32 _role)
                                                                      external
                                                                      auth(CREATE_PERMISSIONS_ROLE)
                                                                      noPermissionManager(_app, _role)
                                                                  {
                                                                      _setPermissionManager(BURN_ENTITY, _app, _role);
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Burn `_role` in `_app`, so no modification can be made to it (grant, revoke, permission manager)
                                                                  * @param _app Address of the app in which the permission is being burned
                                                                  * @param _role Identifier for the group of actions being burned
                                                                  */
                                                                  function burnPermissionManager(address _app, bytes32 _role)
                                                                      external
                                                                      onlyPermissionManager(_app, _role)
                                                                  {
                                                                      _setPermissionManager(BURN_ENTITY, _app, _role);
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Get parameters for permission array length
                                                                   * @param _entity Address of the whitelisted entity that will be able to perform the role
                                                                   * @param _app Address of the app
                                                                   * @param _role Identifier for a group of actions in app
                                                                   * @return Length of the array
                                                                   */
                                                                  function getPermissionParamsLength(address _entity, address _app, bytes32 _role) external view returns (uint) {
                                                                      return permissionParams[permissions[permissionHash(_entity, _app, _role)]].length;
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Get parameter for permission
                                                                  * @param _entity Address of the whitelisted entity that will be able to perform the role
                                                                  * @param _app Address of the app
                                                                  * @param _role Identifier for a group of actions in app
                                                                  * @param _index Index of parameter in the array
                                                                  * @return Parameter (id, op, value)
                                                                  */
                                                                  function getPermissionParam(address _entity, address _app, bytes32 _role, uint _index)
                                                                      external
                                                                      view
                                                                      returns (uint8, uint8, uint240)
                                                                  {
                                                                      Param storage param = permissionParams[permissions[permissionHash(_entity, _app, _role)]][_index];
                                                                      return (param.id, param.op, param.value);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Get manager for permission
                                                                  * @param _app Address of the app
                                                                  * @param _role Identifier for a group of actions in app
                                                                  * @return address of the manager for the permission
                                                                  */
                                                                  function getPermissionManager(address _app, bytes32 _role) public view returns (address) {
                                                                      return permissionManager[roleHash(_app, _role)];
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Function called by apps to check ACL on kernel or to check permission statu
                                                                  * @param _who Sender of the original call
                                                                  * @param _where Address of the app
                                                                  * @param _where Identifier for a group of actions in app
                                                                  * @param _how Permission parameters
                                                                  * @return boolean indicating whether the ACL allows the role or not
                                                                  */
                                                                  function hasPermission(address _who, address _where, bytes32 _what, bytes memory _how) public view returns (bool) {
                                                                      return hasPermission(_who, _where, _what, ConversionHelpers.dangerouslyCastBytesToUintArray(_how));
                                                                  }
                                                              
                                                                  function hasPermission(address _who, address _where, bytes32 _what, uint256[] memory _how) public view returns (bool) {
                                                                      bytes32 whoParams = permissions[permissionHash(_who, _where, _what)];
                                                                      if (whoParams != NO_PERMISSION && evalParams(whoParams, _who, _where, _what, _how)) {
                                                                          return true;
                                                                      }
                                                              
                                                                      bytes32 anyParams = permissions[permissionHash(ANY_ENTITY, _where, _what)];
                                                                      if (anyParams != NO_PERMISSION && evalParams(anyParams, ANY_ENTITY, _where, _what, _how)) {
                                                                          return true;
                                                                      }
                                                              
                                                                      return false;
                                                                  }
                                                              
                                                                  function hasPermission(address _who, address _where, bytes32 _what) public view returns (bool) {
                                                                      uint256[] memory empty = new uint256[](0);
                                                                      return hasPermission(_who, _where, _what, empty);
                                                                  }
                                                              
                                                                  function evalParams(
                                                                      bytes32 _paramsHash,
                                                                      address _who,
                                                                      address _where,
                                                                      bytes32 _what,
                                                                      uint256[] _how
                                                                  ) public view returns (bool)
                                                                  {
                                                                      if (_paramsHash == EMPTY_PARAM_HASH) {
                                                                          return true;
                                                                      }
                                                              
                                                                      return _evalParam(_paramsHash, 0, _who, _where, _what, _how);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Internal createPermission for access inside the kernel (on instantiation)
                                                                  */
                                                                  function _createPermission(address _entity, address _app, bytes32 _role, address _manager) internal {
                                                                      _setPermission(_entity, _app, _role, EMPTY_PARAM_HASH);
                                                                      _setPermissionManager(_manager, _app, _role);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Internal function called to actually save the permission
                                                                  */
                                                                  function _setPermission(address _entity, address _app, bytes32 _role, bytes32 _paramsHash) internal {
                                                                      permissions[permissionHash(_entity, _app, _role)] = _paramsHash;
                                                                      bool entityHasPermission = _paramsHash != NO_PERMISSION;
                                                                      bool permissionHasParams = entityHasPermission && _paramsHash != EMPTY_PARAM_HASH;
                                                              
                                                                      emit SetPermission(_entity, _app, _role, entityHasPermission);
                                                                      if (permissionHasParams) {
                                                                          emit SetPermissionParams(_entity, _app, _role, _paramsHash);
                                                                      }
                                                                  }
                                                              
                                                                  function _saveParams(uint256[] _encodedParams) internal returns (bytes32) {
                                                                      bytes32 paramHash = keccak256(abi.encodePacked(_encodedParams));
                                                                      Param[] storage params = permissionParams[paramHash];
                                                              
                                                                      if (params.length == 0) { // params not saved before
                                                                          for (uint256 i = 0; i < _encodedParams.length; i++) {
                                                                              uint256 encodedParam = _encodedParams[i];
                                                                              Param memory param = Param(decodeParamId(encodedParam), decodeParamOp(encodedParam), uint240(encodedParam));
                                                                              params.push(param);
                                                                          }
                                                                      }
                                                              
                                                                      return paramHash;
                                                                  }
                                                              
                                                                  function _evalParam(
                                                                      bytes32 _paramsHash,
                                                                      uint32 _paramId,
                                                                      address _who,
                                                                      address _where,
                                                                      bytes32 _what,
                                                                      uint256[] _how
                                                                  ) internal view returns (bool)
                                                                  {
                                                                      if (_paramId >= permissionParams[_paramsHash].length) {
                                                                          return false; // out of bounds
                                                                      }
                                                              
                                                                      Param memory param = permissionParams[_paramsHash][_paramId];
                                                              
                                                                      if (param.id == LOGIC_OP_PARAM_ID) {
                                                                          return _evalLogic(param, _paramsHash, _who, _where, _what, _how);
                                                                      }
                                                              
                                                                      uint256 value;
                                                                      uint256 comparedTo = uint256(param.value);
                                                              
                                                                      // get value
                                                                      if (param.id == ORACLE_PARAM_ID) {
                                                                          value = checkOracle(IACLOracle(param.value), _who, _where, _what, _how) ? 1 : 0;
                                                                          comparedTo = 1;
                                                                      } else if (param.id == BLOCK_NUMBER_PARAM_ID) {
                                                                          value = getBlockNumber();
                                                                      } else if (param.id == TIMESTAMP_PARAM_ID) {
                                                                          value = getTimestamp();
                                                                      } else if (param.id == PARAM_VALUE_PARAM_ID) {
                                                                          value = uint256(param.value);
                                                                      } else {
                                                                          if (param.id >= _how.length) {
                                                                              return false;
                                                                          }
                                                                          value = uint256(uint240(_how[param.id])); // force lost precision
                                                                      }
                                                              
                                                                      if (Op(param.op) == Op.RET) {
                                                                          return uint256(value) > 0;
                                                                      }
                                                              
                                                                      return compare(value, Op(param.op), comparedTo);
                                                                  }
                                                              
                                                                  function _evalLogic(Param _param, bytes32 _paramsHash, address _who, address _where, bytes32 _what, uint256[] _how)
                                                                      internal
                                                                      view
                                                                      returns (bool)
                                                                  {
                                                                      if (Op(_param.op) == Op.IF_ELSE) {
                                                                          uint32 conditionParam;
                                                                          uint32 successParam;
                                                                          uint32 failureParam;
                                                              
                                                                          (conditionParam, successParam, failureParam) = decodeParamsList(uint256(_param.value));
                                                                          bool result = _evalParam(_paramsHash, conditionParam, _who, _where, _what, _how);
                                                              
                                                                          return _evalParam(_paramsHash, result ? successParam : failureParam, _who, _where, _what, _how);
                                                                      }
                                                              
                                                                      uint32 param1;
                                                                      uint32 param2;
                                                              
                                                                      (param1, param2,) = decodeParamsList(uint256(_param.value));
                                                                      bool r1 = _evalParam(_paramsHash, param1, _who, _where, _what, _how);
                                                              
                                                                      if (Op(_param.op) == Op.NOT) {
                                                                          return !r1;
                                                                      }
                                                              
                                                                      if (r1 && Op(_param.op) == Op.OR) {
                                                                          return true;
                                                                      }
                                                              
                                                                      if (!r1 && Op(_param.op) == Op.AND) {
                                                                          return false;
                                                                      }
                                                              
                                                                      bool r2 = _evalParam(_paramsHash, param2, _who, _where, _what, _how);
                                                              
                                                                      if (Op(_param.op) == Op.XOR) {
                                                                          return r1 != r2;
                                                                      }
                                                              
                                                                      return r2; // both or and and depend on result of r2 after checks
                                                                  }
                                                              
                                                                  function compare(uint256 _a, Op _op, uint256 _b) internal pure returns (bool) {
                                                                      if (_op == Op.EQ)  return _a == _b;                              // solium-disable-line lbrace
                                                                      if (_op == Op.NEQ) return _a != _b;                              // solium-disable-line lbrace
                                                                      if (_op == Op.GT)  return _a > _b;                               // solium-disable-line lbrace
                                                                      if (_op == Op.LT)  return _a < _b;                               // solium-disable-line lbrace
                                                                      if (_op == Op.GTE) return _a >= _b;                              // solium-disable-line lbrace
                                                                      if (_op == Op.LTE) return _a <= _b;                              // solium-disable-line lbrace
                                                                      return false;
                                                                  }
                                                              
                                                                  function checkOracle(IACLOracle _oracleAddr, address _who, address _where, bytes32 _what, uint256[] _how) internal view returns (bool) {
                                                                      bytes4 sig = _oracleAddr.canPerform.selector;
                                                              
                                                                      // a raw call is required so we can return false if the call reverts, rather than reverting
                                                                      bytes memory checkCalldata = abi.encodeWithSelector(sig, _who, _where, _what, _how);
                                                              
                                                                      bool ok;
                                                                      assembly {
                                                                          // send all available gas; if the oracle eats up all the gas, we will eventually revert
                                                                          // note that we are currently guaranteed to still have some gas after the call from
                                                                          // EIP-150's 63/64 gas forward rule
                                                                          ok := staticcall(gas, _oracleAddr, add(checkCalldata, 0x20), mload(checkCalldata), 0, 0)
                                                                      }
                                                              
                                                                      if (!ok) {
                                                                          return false;
                                                                      }
                                                              
                                                                      uint256 size;
                                                                      assembly { size := returndatasize }
                                                                      if (size != 32) {
                                                                          return false;
                                                                      }
                                                              
                                                                      bool result;
                                                                      assembly {
                                                                          let ptr := mload(0x40)       // get next free memory ptr
                                                                          returndatacopy(ptr, 0, size) // copy return from above `staticcall`
                                                                          result := mload(ptr)         // read data at ptr and set it to result
                                                                          mstore(ptr, 0)               // set pointer memory to 0 so it still is the next free ptr
                                                                      }
                                                              
                                                                      return result;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Internal function that sets management
                                                                  */
                                                                  function _setPermissionManager(address _newManager, address _app, bytes32 _role) internal {
                                                                      permissionManager[roleHash(_app, _role)] = _newManager;
                                                                      emit ChangePermissionManager(_app, _role, _newManager);
                                                                  }
                                                              
                                                                  function roleHash(address _where, bytes32 _what) internal pure returns (bytes32) {
                                                                      return keccak256(abi.encodePacked("ROLE", _where, _what));
                                                                  }
                                                              
                                                                  function permissionHash(address _who, address _where, bytes32 _what) internal pure returns (bytes32) {
                                                                      return keccak256(abi.encodePacked("PERMISSION", _who, _where, _what));
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/evmscript/ScriptHelpers.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              library ScriptHelpers {
                                                                  function getSpecId(bytes _script) internal pure returns (uint32) {
                                                                      return uint32At(_script, 0);
                                                                  }
                                                              
                                                                  function uint256At(bytes _data, uint256 _location) internal pure returns (uint256 result) {
                                                                      assembly {
                                                                          result := mload(add(_data, add(0x20, _location)))
                                                                      }
                                                                  }
                                                              
                                                                  function addressAt(bytes _data, uint256 _location) internal pure returns (address result) {
                                                                      uint256 word = uint256At(_data, _location);
                                                              
                                                                      assembly {
                                                                          result := div(and(word, 0xffffffffffffffffffffffffffffffffffffffff000000000000000000000000),
                                                                          0x1000000000000000000000000)
                                                                      }
                                                                  }
                                                              
                                                                  function uint32At(bytes _data, uint256 _location) internal pure returns (uint32 result) {
                                                                      uint256 word = uint256At(_data, _location);
                                                              
                                                                      assembly {
                                                                          result := div(and(word, 0xffffffff00000000000000000000000000000000000000000000000000000000),
                                                                          0x100000000000000000000000000000000000000000000000000000000)
                                                                      }
                                                                  }
                                                              
                                                                  function locationOf(bytes _data, uint256 _location) internal pure returns (uint256 result) {
                                                                      assembly {
                                                                          result := add(_data, add(0x20, _location))
                                                                      }
                                                                  }
                                                              
                                                                  function toBytes(bytes4 _sig) internal pure returns (bytes) {
                                                                      bytes memory payload = new bytes(4);
                                                                      assembly { mstore(add(payload, 0x20), _sig) }
                                                                      return payload;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/evmscript/EVMScriptRegistry.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              /* solium-disable function-order */
                                                              // Allow public initialize() to be first
                                                              contract EVMScriptRegistry is IEVMScriptRegistry, EVMScriptRegistryConstants, AragonApp {
                                                                  using ScriptHelpers for bytes;
                                                              
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 public constant REGISTRY_ADD_EXECUTOR_ROLE = keccak256("REGISTRY_ADD_EXECUTOR_ROLE");
                                                                  bytes32 public constant REGISTRY_MANAGER_ROLE = keccak256("REGISTRY_MANAGER_ROLE");
                                                                  */
                                                                  bytes32 public constant REGISTRY_ADD_EXECUTOR_ROLE = 0xc4e90f38eea8c4212a009ca7b8947943ba4d4a58d19b683417f65291d1cd9ed2;
                                                                  // WARN: Manager can censor all votes and the like happening in an org
                                                                  bytes32 public constant REGISTRY_MANAGER_ROLE = 0xf7a450ef335e1892cb42c8ca72e7242359d7711924b75db5717410da3f614aa3;
                                                              
                                                                  uint256 internal constant SCRIPT_START_LOCATION = 4;
                                                              
                                                                  string private constant ERROR_INEXISTENT_EXECUTOR = "EVMREG_INEXISTENT_EXECUTOR";
                                                                  string private constant ERROR_EXECUTOR_ENABLED = "EVMREG_EXECUTOR_ENABLED";
                                                                  string private constant ERROR_EXECUTOR_DISABLED = "EVMREG_EXECUTOR_DISABLED";
                                                                  string private constant ERROR_SCRIPT_LENGTH_TOO_SHORT = "EVMREG_SCRIPT_LENGTH_TOO_SHORT";
                                                              
                                                                  struct ExecutorEntry {
                                                                      IEVMScriptExecutor executor;
                                                                      bool enabled;
                                                                  }
                                                              
                                                                  uint256 private executorsNextIndex;
                                                                  mapping (uint256 => ExecutorEntry) public executors;
                                                              
                                                                  event EnableExecutor(uint256 indexed executorId, address indexed executorAddress);
                                                                  event DisableExecutor(uint256 indexed executorId, address indexed executorAddress);
                                                              
                                                                  modifier executorExists(uint256 _executorId) {
                                                                      require(_executorId > 0 && _executorId < executorsNextIndex, ERROR_INEXISTENT_EXECUTOR);
                                                                      _;
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Initialize the registry
                                                                  */
                                                                  function initialize() public onlyInit {
                                                                      initialized();
                                                                      // Create empty record to begin executor IDs at 1
                                                                      executorsNextIndex = 1;
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Add a new script executor with address `_executor` to the registry
                                                                  * @param _executor Address of the IEVMScriptExecutor that will be added to the registry
                                                                  * @return id Identifier of the executor in the registry
                                                                  */
                                                                  function addScriptExecutor(IEVMScriptExecutor _executor) external auth(REGISTRY_ADD_EXECUTOR_ROLE) returns (uint256 id) {
                                                                      uint256 executorId = executorsNextIndex++;
                                                                      executors[executorId] = ExecutorEntry(_executor, true);
                                                                      emit EnableExecutor(executorId, _executor);
                                                                      return executorId;
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Disable script executor with ID `_executorId`
                                                                  * @param _executorId Identifier of the executor in the registry
                                                                  */
                                                                  function disableScriptExecutor(uint256 _executorId)
                                                                      external
                                                                      authP(REGISTRY_MANAGER_ROLE, arr(_executorId))
                                                                  {
                                                                      // Note that we don't need to check for an executor's existence in this case, as only
                                                                      // existing executors can be enabled
                                                                      ExecutorEntry storage executorEntry = executors[_executorId];
                                                                      require(executorEntry.enabled, ERROR_EXECUTOR_DISABLED);
                                                                      executorEntry.enabled = false;
                                                                      emit DisableExecutor(_executorId, executorEntry.executor);
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Enable script executor with ID `_executorId`
                                                                  * @param _executorId Identifier of the executor in the registry
                                                                  */
                                                                  function enableScriptExecutor(uint256 _executorId)
                                                                      external
                                                                      authP(REGISTRY_MANAGER_ROLE, arr(_executorId))
                                                                      executorExists(_executorId)
                                                                  {
                                                                      ExecutorEntry storage executorEntry = executors[_executorId];
                                                                      require(!executorEntry.enabled, ERROR_EXECUTOR_ENABLED);
                                                                      executorEntry.enabled = true;
                                                                      emit EnableExecutor(_executorId, executorEntry.executor);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Get the script executor that can execute a particular script based on its first 4 bytes
                                                                  * @param _script EVMScript being inspected
                                                                  */
                                                                  function getScriptExecutor(bytes _script) public view returns (IEVMScriptExecutor) {
                                                                      require(_script.length >= SCRIPT_START_LOCATION, ERROR_SCRIPT_LENGTH_TOO_SHORT);
                                                                      uint256 id = _script.getSpecId();
                                                              
                                                                      // Note that we don't need to check for an executor's existence in this case, as only
                                                                      // existing executors can be enabled
                                                                      ExecutorEntry storage entry = executors[id];
                                                                      return entry.enabled ? entry.executor : IEVMScriptExecutor(0);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/evmscript/executors/BaseEVMScriptExecutor.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract BaseEVMScriptExecutor is IEVMScriptExecutor, Autopetrified {
                                                                  uint256 internal constant SCRIPT_START_LOCATION = 4;
                                                              }
                                                              
                                                              // File: contracts/evmscript/executors/CallsScript.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              // Inspired by https://github.com/reverendus/tx-manager
                                                              
                                                              
                                                              
                                                              
                                                              contract CallsScript is BaseEVMScriptExecutor {
                                                                  using ScriptHelpers for bytes;
                                                              
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant EXECUTOR_TYPE = keccak256("CALLS_SCRIPT");
                                                                  */
                                                                  bytes32 internal constant EXECUTOR_TYPE = 0x2dc858a00f3e417be1394b87c07158e989ec681ce8cc68a9093680ac1a870302;
                                                              
                                                                  string private constant ERROR_BLACKLISTED_CALL = "EVMCALLS_BLACKLISTED_CALL";
                                                                  string private constant ERROR_INVALID_LENGTH = "EVMCALLS_INVALID_LENGTH";
                                                              
                                                                  /* This is manually crafted in assembly
                                                                  string private constant ERROR_CALL_REVERTED = "EVMCALLS_CALL_REVERTED";
                                                                  */
                                                              
                                                                  event LogScriptCall(address indexed sender, address indexed src, address indexed dst);
                                                              
                                                                  /**
                                                                  * @notice Executes a number of call scripts
                                                                  * @param _script [ specId (uint32) ] many calls with this structure ->
                                                                  *    [ to (address: 20 bytes) ] [ calldataLength (uint32: 4 bytes) ] [ calldata (calldataLength bytes) ]
                                                                  * @param _blacklist Addresses the script cannot call to, or will revert.
                                                                  * @return Always returns empty byte array
                                                                  */
                                                                  function execScript(bytes _script, bytes, address[] _blacklist) external isInitialized returns (bytes) {
                                                                      uint256 location = SCRIPT_START_LOCATION; // first 32 bits are spec id
                                                                      while (location < _script.length) {
                                                                          // Check there's at least address + calldataLength available
                                                                          require(_script.length - location >= 0x18, ERROR_INVALID_LENGTH);
                                                              
                                                                          address contractAddress = _script.addressAt(location);
                                                                          // Check address being called is not blacklist
                                                                          for (uint256 i = 0; i < _blacklist.length; i++) {
                                                                              require(contractAddress != _blacklist[i], ERROR_BLACKLISTED_CALL);
                                                                          }
                                                              
                                                                          // logged before execution to ensure event ordering in receipt
                                                                          // if failed entire execution is reverted regardless
                                                                          emit LogScriptCall(msg.sender, address(this), contractAddress);
                                                              
                                                                          uint256 calldataLength = uint256(_script.uint32At(location + 0x14));
                                                                          uint256 startOffset = location + 0x14 + 0x04;
                                                                          uint256 calldataStart = _script.locationOf(startOffset);
                                                              
                                                                          // compute end of script / next location
                                                                          location = startOffset + calldataLength;
                                                                          require(location <= _script.length, ERROR_INVALID_LENGTH);
                                                              
                                                                          bool success;
                                                                          assembly {
                                                                              success := call(
                                                                                  sub(gas, 5000),       // forward gas left - 5000
                                                                                  contractAddress,      // address
                                                                                  0,                    // no value
                                                                                  calldataStart,        // calldata start
                                                                                  calldataLength,       // calldata length
                                                                                  0,                    // don't write output
                                                                                  0                     // don't write output
                                                                              )
                                                              
                                                                              switch success
                                                                              case 0 {
                                                                                  let ptr := mload(0x40)
                                                              
                                                                                  switch returndatasize
                                                                                  case 0 {
                                                                                      // No error data was returned, revert with "EVMCALLS_CALL_REVERTED"
                                                                                      // See remix: doing a `revert("EVMCALLS_CALL_REVERTED")` always results in
                                                                                      // this memory layout
                                                                                      mstore(ptr, 0x08c379a000000000000000000000000000000000000000000000000000000000)         // error identifier
                                                                                      mstore(add(ptr, 0x04), 0x0000000000000000000000000000000000000000000000000000000000000020) // starting offset
                                                                                      mstore(add(ptr, 0x24), 0x0000000000000000000000000000000000000000000000000000000000000016) // reason length
                                                                                      mstore(add(ptr, 0x44), 0x45564d43414c4c535f43414c4c5f524556455254454400000000000000000000) // reason
                                                              
                                                                                      revert(ptr, 100) // 100 = 4 + 3 * 32 (error identifier + 3 words for the ABI encoded error)
                                                                                  }
                                                                                  default {
                                                                                      // Forward the full error data
                                                                                      returndatacopy(ptr, 0, returndatasize)
                                                                                      revert(ptr, returndatasize)
                                                                                  }
                                                                              }
                                                                              default { }
                                                                          }
                                                                      }
                                                                      // No need to allocate empty bytes for the return as this can only be called via an delegatecall
                                                                      // (due to the isInitialized modifier)
                                                                  }
                                                              
                                                                  function executorType() external pure returns (bytes32) {
                                                                      return EXECUTOR_TYPE;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/factory/EVMScriptRegistryFactory.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract EVMScriptRegistryFactory is EVMScriptRegistryConstants {
                                                                  EVMScriptRegistry public baseReg;
                                                                  IEVMScriptExecutor public baseCallScript;
                                                              
                                                                  /**
                                                                  * @notice Create a new EVMScriptRegistryFactory.
                                                                  */
                                                                  constructor() public {
                                                                      baseReg = new EVMScriptRegistry();
                                                                      baseCallScript = IEVMScriptExecutor(new CallsScript());
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Install a new pinned instance of EVMScriptRegistry on `_dao`.
                                                                  * @param _dao Kernel
                                                                  * @return Installed EVMScriptRegistry
                                                                  */
                                                                  function newEVMScriptRegistry(Kernel _dao) public returns (EVMScriptRegistry reg) {
                                                                      bytes memory initPayload = abi.encodeWithSelector(reg.initialize.selector);
                                                                      reg = EVMScriptRegistry(_dao.newPinnedAppInstance(EVMSCRIPT_REGISTRY_APP_ID, baseReg, initPayload, true));
                                                              
                                                                      ACL acl = ACL(_dao.acl());
                                                              
                                                                      acl.createPermission(this, reg, reg.REGISTRY_ADD_EXECUTOR_ROLE(), this);
                                                              
                                                                      reg.addScriptExecutor(baseCallScript);     // spec 1 = CallsScript
                                                              
                                                                      // Clean up the permissions
                                                                      acl.revokePermission(this, reg, reg.REGISTRY_ADD_EXECUTOR_ROLE());
                                                                      acl.removePermissionManager(reg, reg.REGISTRY_ADD_EXECUTOR_ROLE());
                                                              
                                                                      return reg;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/factory/DAOFactory.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract DAOFactory {
                                                                  IKernel public baseKernel;
                                                                  IACL public baseACL;
                                                                  EVMScriptRegistryFactory public regFactory;
                                                              
                                                                  event DeployDAO(address dao);
                                                                  event DeployEVMScriptRegistry(address reg);
                                                              
                                                                  /**
                                                                  * @notice Create a new DAOFactory, creating DAOs with Kernels proxied to `_baseKernel`, ACLs proxied to `_baseACL`, and new EVMScriptRegistries created from `_regFactory`.
                                                                  * @param _baseKernel Base Kernel
                                                                  * @param _baseACL Base ACL
                                                                  * @param _regFactory EVMScriptRegistry factory
                                                                  */
                                                                  constructor(IKernel _baseKernel, IACL _baseACL, EVMScriptRegistryFactory _regFactory) public {
                                                                      // No need to init as it cannot be killed by devops199
                                                                      if (address(_regFactory) != address(0)) {
                                                                          regFactory = _regFactory;
                                                                      }
                                                              
                                                                      baseKernel = _baseKernel;
                                                                      baseACL = _baseACL;
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Create a new DAO with `_root` set as the initial admin
                                                                  * @param _root Address that will be granted control to setup DAO permissions
                                                                  * @return Newly created DAO
                                                                  */
                                                                  function newDAO(address _root) public returns (Kernel) {
                                                                      Kernel dao = Kernel(new KernelProxy(baseKernel));
                                                              
                                                                      if (address(regFactory) == address(0)) {
                                                                          dao.initialize(baseACL, _root);
                                                                      } else {
                                                                          dao.initialize(baseACL, this);
                                                              
                                                                          ACL acl = ACL(dao.acl());
                                                                          bytes32 permRole = acl.CREATE_PERMISSIONS_ROLE();
                                                                          bytes32 appManagerRole = dao.APP_MANAGER_ROLE();
                                                              
                                                                          acl.grantPermission(regFactory, acl, permRole);
                                                              
                                                                          acl.createPermission(regFactory, dao, appManagerRole, this);
                                                              
                                                                          EVMScriptRegistry reg = regFactory.newEVMScriptRegistry(dao);
                                                                          emit DeployEVMScriptRegistry(address(reg));
                                                              
                                                                          // Clean up permissions
                                                                          // First, completely reset the APP_MANAGER_ROLE
                                                                          acl.revokePermission(regFactory, dao, appManagerRole);
                                                                          acl.removePermissionManager(dao, appManagerRole);
                                                              
                                                                          // Then, make root the only holder and manager of CREATE_PERMISSIONS_ROLE
                                                                          acl.revokePermission(regFactory, acl, permRole);
                                                                          acl.revokePermission(this, acl, permRole);
                                                                          acl.grantPermission(_root, acl, permRole);
                                                                          acl.setPermissionManager(_root, acl, permRole);
                                                                      }
                                                              
                                                                      emit DeployDAO(address(dao));
                                                              
                                                                      return dao;
                                                                  }
                                                              }

                                                              File 6 of 14: Kernel
                                                              // File: contracts/acl/IACL.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IACL {
                                                                  function initialize(address permissionsCreator) external;
                                                              
                                                                  // TODO: this should be external
                                                                  // See https://github.com/ethereum/solidity/issues/4832
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              }
                                                              
                                                              // File: contracts/common/IVaultRecoverable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IVaultRecoverable {
                                                                  event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                                                              
                                                                  function transferToVault(address token) external;
                                                              
                                                                  function allowRecoverability(address token) external view returns (bool);
                                                                  function getRecoveryVault() external view returns (address);
                                                              }
                                                              
                                                              // File: contracts/kernel/IKernel.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              interface IKernelEvents {
                                                                  event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                                                              }
                                                              
                                                              
                                                              // This should be an interface, but interfaces can't inherit yet :(
                                                              contract IKernel is IKernelEvents, IVaultRecoverable {
                                                                  function acl() public view returns (IACL);
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              
                                                                  function setApp(bytes32 namespace, bytes32 appId, address app) public;
                                                                  function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                                                              }
                                                              
                                                              // File: contracts/kernel/KernelConstants.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract KernelAppIds {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                                                              }
                                                              
                                                              
                                                              contract KernelNamespaceConstants {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                                                              }
                                                              
                                                              // File: contracts/kernel/KernelStorage.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              contract KernelStorage {
                                                                  // namespace => app id => address
                                                                  mapping (bytes32 => mapping (bytes32 => address)) public apps;
                                                                  bytes32 public recoveryVaultAppId;
                                                              }
                                                              
                                                              // File: contracts/acl/ACLSyntaxSugar.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract ACLSyntaxSugar {
                                                                  function arr() internal pure returns (uint256[]) {
                                                                      return new uint256[](0);
                                                                  }
                                                              
                                                                  function arr(bytes32 _a) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a));
                                                                  }
                                                              
                                                                  function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                              
                                                                  function arr(address _a) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a));
                                                                  }
                                                              
                                                                  function arr(address _a, address _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                              
                                                                  function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), _b, _c);
                                                                  }
                                                              
                                                                  function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), _b, _c, _d);
                                                                  }
                                                              
                                                                  function arr(address _a, uint256 _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                              
                                                                  function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), _c, _d, _e);
                                                                  }
                                                              
                                                                  function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), uint256(_c));
                                                                  }
                                                              
                                                                  function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), uint256(_c));
                                                                  }
                                                              
                                                                  function arr(uint256 _a) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](1);
                                                                      r[0] = _a;
                                                                  }
                                                              
                                                                  function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](2);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                  }
                                                              
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](3);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                  }
                                                              
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](4);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                      r[3] = _d;
                                                                  }
                                                              
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](5);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                      r[3] = _d;
                                                                      r[4] = _e;
                                                                  }
                                                              }
                                                              
                                                              
                                                              contract ACLHelpers {
                                                                  function decodeParamOp(uint256 _x) internal pure returns (uint8 b) {
                                                                      return uint8(_x >> (8 * 30));
                                                                  }
                                                              
                                                                  function decodeParamId(uint256 _x) internal pure returns (uint8 b) {
                                                                      return uint8(_x >> (8 * 31));
                                                                  }
                                                              
                                                                  function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) {
                                                                      a = uint32(_x);
                                                                      b = uint32(_x >> (8 * 4));
                                                                      c = uint32(_x >> (8 * 8));
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/ConversionHelpers.sol
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              library ConversionHelpers {
                                                                  string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH";
                                                              
                                                                  function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) {
                                                                      // Force cast the uint256[] into a bytes array, by overwriting its length
                                                                      // Note that the bytes array doesn't need to be initialized as we immediately overwrite it
                                                                      // with the input and a new length. The input becomes invalid from this point forward.
                                                                      uint256 byteLength = _input.length * 32;
                                                                      assembly {
                                                                          output := _input
                                                                          mstore(output, byteLength)
                                                                      }
                                                                  }
                                                              
                                                                  function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) {
                                                                      // Force cast the bytes array into a uint256[], by overwriting its length
                                                                      // Note that the uint256[] doesn't need to be initialized as we immediately overwrite it
                                                                      // with the input and a new length. The input becomes invalid from this point forward.
                                                                      uint256 intsLength = _input.length / 32;
                                                                      require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH);
                                                              
                                                                      assembly {
                                                                          output := _input
                                                                          mstore(output, intsLength)
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/IsContract.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract IsContract {
                                                                  /*
                                                                  * NOTE: this should NEVER be used for authentication
                                                                  * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                                                                  *
                                                                  * This is only intended to be used as a sanity check that an address is actually a contract,
                                                                  * RATHER THAN an address not being a contract.
                                                                  */
                                                                  function isContract(address _target) internal view returns (bool) {
                                                                      if (_target == address(0)) {
                                                                          return false;
                                                                      }
                                                              
                                                                      uint256 size;
                                                                      assembly { size := extcodesize(_target) }
                                                                      return size > 0;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/Uint256Helpers.sol
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              library Uint256Helpers {
                                                                  uint256 private constant MAX_UINT64 = uint64(-1);
                                                              
                                                                  string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG";
                                                              
                                                                  function toUint64(uint256 a) internal pure returns (uint64) {
                                                                      require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG);
                                                                      return uint64(a);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/TimeHelpers.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              contract TimeHelpers {
                                                                  using Uint256Helpers for uint256;
                                                              
                                                                  /**
                                                                  * @dev Returns the current block number.
                                                                  *      Using a function rather than `block.number` allows us to easily mock the block number in
                                                                  *      tests.
                                                                  */
                                                                  function getBlockNumber() internal view returns (uint256) {
                                                                      return block.number;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Returns the current block number, converted to uint64.
                                                                  *      Using a function rather than `block.number` allows us to easily mock the block number in
                                                                  *      tests.
                                                                  */
                                                                  function getBlockNumber64() internal view returns (uint64) {
                                                                      return getBlockNumber().toUint64();
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Returns the current timestamp.
                                                                  *      Using a function rather than `block.timestamp` allows us to easily mock it in
                                                                  *      tests.
                                                                  */
                                                                  function getTimestamp() internal view returns (uint256) {
                                                                      return block.timestamp; // solium-disable-line security/no-block-members
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Returns the current timestamp, converted to uint64.
                                                                  *      Using a function rather than `block.timestamp` allows us to easily mock it in
                                                                  *      tests.
                                                                  */
                                                                  function getTimestamp64() internal view returns (uint64) {
                                                                      return getTimestamp().toUint64();
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/UnstructuredStorage.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              library UnstructuredStorage {
                                                                  function getStorageBool(bytes32 position) internal view returns (bool data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageAddress(bytes32 position) internal view returns (address data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function setStorageBool(bytes32 position, bool data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageAddress(bytes32 position, address data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageBytes32(bytes32 position, bytes32 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageUint256(bytes32 position, uint256 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/Initializable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract Initializable is TimeHelpers {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  // keccak256("aragonOS.initializable.initializationBlock")
                                                                  bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e;
                                                              
                                                                  string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED";
                                                                  string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED";
                                                              
                                                                  modifier onlyInit {
                                                                      require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED);
                                                                      _;
                                                                  }
                                                              
                                                                  modifier isInitialized {
                                                                      require(hasInitialized(), ERROR_NOT_INITIALIZED);
                                                                      _;
                                                                  }
                                                              
                                                                  /**
                                                                  * @return Block number in which the contract was initialized
                                                                  */
                                                                  function getInitializationBlock() public view returns (uint256) {
                                                                      return INITIALIZATION_BLOCK_POSITION.getStorageUint256();
                                                                  }
                                                              
                                                                  /**
                                                                  * @return Whether the contract has been initialized by the time of the current block
                                                                  */
                                                                  function hasInitialized() public view returns (bool) {
                                                                      uint256 initializationBlock = getInitializationBlock();
                                                                      return initializationBlock != 0 && getBlockNumber() >= initializationBlock;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Function to be called by top level contract after initialization has finished.
                                                                  */
                                                                  function initialized() internal onlyInit {
                                                                      INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber());
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Function to be called by top level contract after initialization to enable the contract
                                                                  *      at a future block number rather than immediately.
                                                                  */
                                                                  function initializedAt(uint256 _blockNumber) internal onlyInit {
                                                                      INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/Petrifiable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              contract Petrifiable is Initializable {
                                                                  // Use block UINT256_MAX (which should be never) as the initializable date
                                                                  uint256 internal constant PETRIFIED_BLOCK = uint256(-1);
                                                              
                                                                  function isPetrified() public view returns (bool) {
                                                                      return getInitializationBlock() == PETRIFIED_BLOCK;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Function to be called by top level contract to prevent being initialized.
                                                                  *      Useful for freezing base contracts when they're used behind proxies.
                                                                  */
                                                                  function petrify() internal onlyInit {
                                                                      initializedAt(PETRIFIED_BLOCK);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/lib/token/ERC20.sol
                                                              
                                                              // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              /**
                                                               * @title ERC20 interface
                                                               * @dev see https://github.com/ethereum/EIPs/issues/20
                                                               */
                                                              contract ERC20 {
                                                                  function totalSupply() public view returns (uint256);
                                                              
                                                                  function balanceOf(address _who) public view returns (uint256);
                                                              
                                                                  function allowance(address _owner, address _spender)
                                                                      public view returns (uint256);
                                                              
                                                                  function transfer(address _to, uint256 _value) public returns (bool);
                                                              
                                                                  function approve(address _spender, uint256 _value)
                                                                      public returns (bool);
                                                              
                                                                  function transferFrom(address _from, address _to, uint256 _value)
                                                                      public returns (bool);
                                                              
                                                                  event Transfer(
                                                                      address indexed from,
                                                                      address indexed to,
                                                                      uint256 value
                                                                  );
                                                              
                                                                  event Approval(
                                                                      address indexed owner,
                                                                      address indexed spender,
                                                                      uint256 value
                                                                  );
                                                              }
                                                              
                                                              // File: contracts/common/EtherTokenConstant.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              // aragonOS and aragon-apps rely on address(0) to denote native ETH, in
                                                              // contracts where both tokens and ETH are accepted
                                                              contract EtherTokenConstant {
                                                                  address internal constant ETH = address(0);
                                                              }
                                                              
                                                              // File: contracts/common/SafeERC20.sol
                                                              
                                                              // Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol)
                                                              // and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143)
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              library SafeERC20 {
                                                                  // Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`:
                                                                  // https://github.com/ethereum/solidity/issues/3544
                                                                  bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb;
                                                              
                                                                  string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED";
                                                                  string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED";
                                                              
                                                                  function invokeAndCheckSuccess(address _addr, bytes memory _calldata)
                                                                      private
                                                                      returns (bool)
                                                                  {
                                                                      bool ret;
                                                                      assembly {
                                                                          let ptr := mload(0x40)    // free memory pointer
                                                              
                                                                          let success := call(
                                                                              gas,                  // forward all gas
                                                                              _addr,                // address
                                                                              0,                    // no value
                                                                              add(_calldata, 0x20), // calldata start
                                                                              mload(_calldata),     // calldata length
                                                                              ptr,                  // write output over free memory
                                                                              0x20                  // uint256 return
                                                                          )
                                                              
                                                                          if gt(success, 0) {
                                                                              // Check number of bytes returned from last function call
                                                                              switch returndatasize
                                                              
                                                                              // No bytes returned: assume success
                                                                              case 0 {
                                                                                  ret := 1
                                                                              }
                                                              
                                                                              // 32 bytes returned: check if non-zero
                                                                              case 0x20 {
                                                                                  // Only return success if returned data was true
                                                                                  // Already have output in ptr
                                                                                  ret := eq(mload(ptr), 1)
                                                                              }
                                                              
                                                                              // Not sure what was returned: don't mark as success
                                                                              default { }
                                                                          }
                                                                      }
                                                                      return ret;
                                                                  }
                                                              
                                                                  function staticInvoke(address _addr, bytes memory _calldata)
                                                                      private
                                                                      view
                                                                      returns (bool, uint256)
                                                                  {
                                                                      bool success;
                                                                      uint256 ret;
                                                                      assembly {
                                                                          let ptr := mload(0x40)    // free memory pointer
                                                              
                                                                          success := staticcall(
                                                                              gas,                  // forward all gas
                                                                              _addr,                // address
                                                                              add(_calldata, 0x20), // calldata start
                                                                              mload(_calldata),     // calldata length
                                                                              ptr,                  // write output over free memory
                                                                              0x20                  // uint256 return
                                                                          )
                                                              
                                                                          if gt(success, 0) {
                                                                              ret := mload(ptr)
                                                                          }
                                                                      }
                                                                      return (success, ret);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) {
                                                                      bytes memory transferCallData = abi.encodeWithSelector(
                                                                          TRANSFER_SELECTOR,
                                                                          _to,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, transferCallData);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
                                                                      bytes memory transferFromCallData = abi.encodeWithSelector(
                                                                          _token.transferFrom.selector,
                                                                          _from,
                                                                          _to,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, transferFromCallData);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) {
                                                                      bytes memory approveCallData = abi.encodeWithSelector(
                                                                          _token.approve.selector,
                                                                          _spender,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, approveCallData);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Static call into ERC20.balanceOf().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) {
                                                                      bytes memory balanceOfCallData = abi.encodeWithSelector(
                                                                          _token.balanceOf.selector,
                                                                          _owner
                                                                      );
                                                              
                                                                      (bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData);
                                                                      require(success, ERROR_TOKEN_BALANCE_REVERTED);
                                                              
                                                                      return tokenBalance;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Static call into ERC20.allowance().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) {
                                                                      bytes memory allowanceCallData = abi.encodeWithSelector(
                                                                          _token.allowance.selector,
                                                                          _owner,
                                                                          _spender
                                                                      );
                                                              
                                                                      (bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData);
                                                                      require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                                                              
                                                                      return allowance;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Static call into ERC20.totalSupply().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticTotalSupply(ERC20 _token) internal view returns (uint256) {
                                                                      bytes memory totalSupplyCallData = abi.encodeWithSelector(_token.totalSupply.selector);
                                                              
                                                                      (bool success, uint256 totalSupply) = staticInvoke(_token, totalSupplyCallData);
                                                                      require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                                                              
                                                                      return totalSupply;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/VaultRecoverable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract {
                                                                  using SafeERC20 for ERC20;
                                                              
                                                                  string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED";
                                                                  string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT";
                                                                  string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED";
                                                              
                                                                  /**
                                                                   * @notice Send funds to recovery Vault. This contract should never receive funds,
                                                                   *         but in case it does, this function allows one to recover them.
                                                                   * @param _token Token balance to be sent to recovery vault.
                                                                   */
                                                                  function transferToVault(address _token) external {
                                                                      require(allowRecoverability(_token), ERROR_DISALLOWED);
                                                                      address vault = getRecoveryVault();
                                                                      require(isContract(vault), ERROR_VAULT_NOT_CONTRACT);
                                                              
                                                                      uint256 balance;
                                                                      if (_token == ETH) {
                                                                          balance = address(this).balance;
                                                                          vault.transfer(balance);
                                                                      } else {
                                                                          ERC20 token = ERC20(_token);
                                                                          balance = token.staticBalanceOf(this);
                                                                          require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED);
                                                                      }
                                                              
                                                                      emit RecoverToVault(vault, _token, balance);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev By default deriving from AragonApp makes it recoverable
                                                                  * @param token Token address that would be recovered
                                                                  * @return bool whether the app allows the recovery
                                                                  */
                                                                  function allowRecoverability(address token) public view returns (bool) {
                                                                      return true;
                                                                  }
                                                              
                                                                  // Cast non-implemented interface to be public so we can use it internally
                                                                  function getRecoveryVault() public view returns (address);
                                                              }
                                                              
                                                              // File: contracts/apps/AppStorage.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract AppStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
                                                                  bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
                                                                  */
                                                                  bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
                                                                  bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
                                                              
                                                                  function kernel() public view returns (IKernel) {
                                                                      return IKernel(KERNEL_POSITION.getStorageAddress());
                                                                  }
                                                              
                                                                  function appId() public view returns (bytes32) {
                                                                      return APP_ID_POSITION.getStorageBytes32();
                                                                  }
                                                              
                                                                  function setKernel(IKernel _kernel) internal {
                                                                      KERNEL_POSITION.setStorageAddress(address(_kernel));
                                                                  }
                                                              
                                                                  function setAppId(bytes32 _appId) internal {
                                                                      APP_ID_POSITION.setStorageBytes32(_appId);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/lib/misc/ERCProxy.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract ERCProxy {
                                                                  uint256 internal constant FORWARDING = 1;
                                                                  uint256 internal constant UPGRADEABLE = 2;
                                                              
                                                                  function proxyType() public pure returns (uint256 proxyTypeId);
                                                                  function implementation() public view returns (address codeAddr);
                                                              }
                                                              
                                                              // File: contracts/common/DelegateProxy.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract DelegateProxy is ERCProxy, IsContract {
                                                                  uint256 internal constant FWD_GAS_LIMIT = 10000;
                                                              
                                                                  /**
                                                                  * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
                                                                  * @param _dst Destination address to perform the delegatecall
                                                                  * @param _calldata Calldata for the delegatecall
                                                                  */
                                                                  function delegatedFwd(address _dst, bytes _calldata) internal {
                                                                      require(isContract(_dst));
                                                                      uint256 fwdGasLimit = FWD_GAS_LIMIT;
                                                              
                                                                      assembly {
                                                                          let result := delegatecall(sub(gas, fwdGasLimit), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
                                                                          let size := returndatasize
                                                                          let ptr := mload(0x40)
                                                                          returndatacopy(ptr, 0, size)
                                                              
                                                                          // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
                                                                          // if the call returned error data, forward it
                                                                          switch result case 0 { revert(ptr, size) }
                                                                          default { return(ptr, size) }
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/DepositableStorage.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              contract DepositableStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  // keccak256("aragonOS.depositableStorage.depositable")
                                                                  bytes32 internal constant DEPOSITABLE_POSITION = 0x665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea;
                                                              
                                                                  function isDepositable() public view returns (bool) {
                                                                      return DEPOSITABLE_POSITION.getStorageBool();
                                                                  }
                                                              
                                                                  function setDepositable(bool _depositable) internal {
                                                                      DEPOSITABLE_POSITION.setStorageBool(_depositable);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/DepositableDelegateProxy.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract DepositableDelegateProxy is DepositableStorage, DelegateProxy {
                                                                  event ProxyDeposit(address sender, uint256 value);
                                                              
                                                                  function () external payable {
                                                                      uint256 forwardGasThreshold = FWD_GAS_LIMIT;
                                                                      bytes32 isDepositablePosition = DEPOSITABLE_POSITION;
                                                              
                                                                      // Optimized assembly implementation to prevent EIP-1884 from breaking deposits, reference code in Solidity:
                                                                      // https://github.com/aragon/aragonOS/blob/v4.2.1/contracts/common/DepositableDelegateProxy.sol#L10-L20
                                                                      assembly {
                                                                          // Continue only if the gas left is lower than the threshold for forwarding to the implementation code,
                                                                          // otherwise continue outside of the assembly block.
                                                                          if lt(gas, forwardGasThreshold) {
                                                                              // Only accept the deposit and emit an event if all of the following are true:
                                                                              // the proxy accepts deposits (isDepositable), msg.data.length == 0, and msg.value > 0
                                                                              if and(and(sload(isDepositablePosition), iszero(calldatasize)), gt(callvalue, 0)) {
                                                                                  // Equivalent Solidity code for emitting the event:
                                                                                  // emit ProxyDeposit(msg.sender, msg.value);
                                                              
                                                                                  let logData := mload(0x40) // free memory pointer
                                                                                  mstore(logData, caller) // add 'msg.sender' to the log data (first event param)
                                                                                  mstore(add(logData, 0x20), callvalue) // add 'msg.value' to the log data (second event param)
                                                              
                                                                                  // Emit an event with one topic to identify the event: keccak256('ProxyDeposit(address,uint256)') = 0x15ee...dee1
                                                                                  log1(logData, 0x40, 0x15eeaa57c7bd188c1388020bcadc2c436ec60d647d36ef5b9eb3c742217ddee1)
                                                              
                                                                                  stop() // Stop. Exits execution context
                                                                              }
                                                              
                                                                              // If any of above checks failed, revert the execution (if ETH was sent, it is returned to the sender)
                                                                              revert(0, 0)
                                                                          }
                                                                      }
                                                              
                                                                      address target = implementation();
                                                                      delegatedFwd(target, msg.data);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyBase.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract AppProxyBase is AppStorage, DepositableDelegateProxy, KernelNamespaceConstants {
                                                                  /**
                                                                  * @dev Initialize AppProxy
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public {
                                                                      setKernel(_kernel);
                                                                      setAppId(_appId);
                                                              
                                                                      // Implicit check that kernel is actually a Kernel
                                                                      // The EVM doesn't actually provide a way for us to make sure, but we can force a revert to
                                                                      // occur if the kernel is set to 0x0 or a non-code address when we try to call a method on
                                                                      // it.
                                                                      address appCode = getAppBase(_appId);
                                                              
                                                                      // If initialize payload is provided, it will be executed
                                                                      if (_initializePayload.length > 0) {
                                                                          require(isContract(appCode));
                                                                          // Cannot make delegatecall as a delegateproxy.delegatedFwd as it
                                                                          // returns ending execution context and halts contract deployment
                                                                          require(appCode.delegatecall(_initializePayload));
                                                                      }
                                                                  }
                                                              
                                                                  function getAppBase(bytes32 _appId) internal view returns (address) {
                                                                      return kernel().getApp(KERNEL_APP_BASES_NAMESPACE, _appId);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyUpgradeable.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              contract AppProxyUpgradeable is AppProxyBase {
                                                                  /**
                                                                  * @dev Initialize AppProxyUpgradeable (makes it an upgradeable Aragon app)
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload)
                                                                      AppProxyBase(_kernel, _appId, _initializePayload)
                                                                      public // solium-disable-line visibility-first
                                                                  {
                                                                      // solium-disable-previous-line no-empty-blocks
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, the address the proxy would delegate calls to
                                                                   */
                                                                  function implementation() public view returns (address) {
                                                                      return getAppBase(appId());
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                                                                   */
                                                                  function proxyType() public pure returns (uint256 proxyTypeId) {
                                                                      return UPGRADEABLE;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyPinned.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract AppProxyPinned is IsContract, AppProxyBase {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  // keccak256("aragonOS.appStorage.pinnedCode")
                                                                  bytes32 internal constant PINNED_CODE_POSITION = 0xdee64df20d65e53d7f51cb6ab6d921a0a6a638a91e942e1d8d02df28e31c038e;
                                                              
                                                                  /**
                                                                  * @dev Initialize AppProxyPinned (makes it an un-upgradeable Aragon app)
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload)
                                                                      AppProxyBase(_kernel, _appId, _initializePayload)
                                                                      public // solium-disable-line visibility-first
                                                                  {
                                                                      setPinnedCode(getAppBase(_appId));
                                                                      require(isContract(pinnedCode()));
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, the address the proxy would delegate calls to
                                                                   */
                                                                  function implementation() public view returns (address) {
                                                                      return pinnedCode();
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                                                                   */
                                                                  function proxyType() public pure returns (uint256 proxyTypeId) {
                                                                      return FORWARDING;
                                                                  }
                                                              
                                                                  function setPinnedCode(address _pinnedCode) internal {
                                                                      PINNED_CODE_POSITION.setStorageAddress(_pinnedCode);
                                                                  }
                                                              
                                                                  function pinnedCode() internal view returns (address) {
                                                                      return PINNED_CODE_POSITION.getStorageAddress();
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/factory/AppProxyFactory.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract AppProxyFactory {
                                                                  event NewAppProxy(address proxy, bool isUpgradeable, bytes32 appId);
                                                              
                                                                  /**
                                                                  * @notice Create a new upgradeable app instance on `_kernel` with identifier `_appId`
                                                                  * @param _kernel App's Kernel reference
                                                                  * @param _appId Identifier for app
                                                                  * @return AppProxyUpgradeable
                                                                  */
                                                                  function newAppProxy(IKernel _kernel, bytes32 _appId) public returns (AppProxyUpgradeable) {
                                                                      return newAppProxy(_kernel, _appId, new bytes(0));
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Create a new upgradeable app instance on `_kernel` with identifier `_appId` and initialization payload `_initializePayload`
                                                                  * @param _kernel App's Kernel reference
                                                                  * @param _appId Identifier for app
                                                                  * @return AppProxyUpgradeable
                                                                  */
                                                                  function newAppProxy(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public returns (AppProxyUpgradeable) {
                                                                      AppProxyUpgradeable proxy = new AppProxyUpgradeable(_kernel, _appId, _initializePayload);
                                                                      emit NewAppProxy(address(proxy), true, _appId);
                                                                      return proxy;
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Create a new pinned app instance on `_kernel` with identifier `_appId`
                                                                  * @param _kernel App's Kernel reference
                                                                  * @param _appId Identifier for app
                                                                  * @return AppProxyPinned
                                                                  */
                                                                  function newAppProxyPinned(IKernel _kernel, bytes32 _appId) public returns (AppProxyPinned) {
                                                                      return newAppProxyPinned(_kernel, _appId, new bytes(0));
                                                                  }
                                                              
                                                                  /**
                                                                  * @notice Create a new pinned app instance on `_kernel` with identifier `_appId` and initialization payload `_initializePayload`
                                                                  * @param _kernel App's Kernel reference
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Proxy initialization payload
                                                                  * @return AppProxyPinned
                                                                  */
                                                                  function newAppProxyPinned(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public returns (AppProxyPinned) {
                                                                      AppProxyPinned proxy = new AppProxyPinned(_kernel, _appId, _initializePayload);
                                                                      emit NewAppProxy(address(proxy), false, _appId);
                                                                      return proxy;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/kernel/Kernel.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              // solium-disable-next-line max-len
                                                              contract Kernel is IKernel, KernelStorage, KernelAppIds, KernelNamespaceConstants, Petrifiable, IsContract, VaultRecoverable, AppProxyFactory, ACLSyntaxSugar {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 public constant APP_MANAGER_ROLE = keccak256("APP_MANAGER_ROLE");
                                                                  */
                                                                  bytes32 public constant APP_MANAGER_ROLE = 0xb6d92708f3d4817afc106147d969e229ced5c46e65e0a5002a0d391287762bd0;
                                                              
                                                                  string private constant ERROR_APP_NOT_CONTRACT = "KERNEL_APP_NOT_CONTRACT";
                                                                  string private constant ERROR_INVALID_APP_CHANGE = "KERNEL_INVALID_APP_CHANGE";
                                                                  string private constant ERROR_AUTH_FAILED = "KERNEL_AUTH_FAILED";
                                                              
                                                                  /**
                                                                  * @dev Constructor that allows the deployer to choose if the base instance should be petrified immediately.
                                                                  * @param _shouldPetrify Immediately petrify this instance so that it can never be initialized
                                                                  */
                                                                  constructor(bool _shouldPetrify) public {
                                                                      if (_shouldPetrify) {
                                                                          petrify();
                                                                      }
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Initialize can only be called once. It saves the block number in which it was initialized.
                                                                  * @notice Initialize this kernel instance along with its ACL and set `_permissionsCreator` as the entity that can create other permissions
                                                                  * @param _baseAcl Address of base ACL app
                                                                  * @param _permissionsCreator Entity that will be given permission over createPermission
                                                                  */
                                                                  function initialize(IACL _baseAcl, address _permissionsCreator) public onlyInit {
                                                                      initialized();
                                                              
                                                                      // Set ACL base
                                                                      _setApp(KERNEL_APP_BASES_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID, _baseAcl);
                                                              
                                                                      // Create ACL instance and attach it as the default ACL app
                                                                      IACL acl = IACL(newAppProxy(this, KERNEL_DEFAULT_ACL_APP_ID));
                                                                      acl.initialize(_permissionsCreator);
                                                                      _setApp(KERNEL_APP_ADDR_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID, acl);
                                                              
                                                                      recoveryVaultAppId = KERNEL_DEFAULT_VAULT_APP_ID;
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Create a new instance of an app linked to this kernel
                                                                  * @notice Create a new upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`
                                                                  * @param _appId Identifier for app
                                                                  * @param _appBase Address of the app's base implementation
                                                                  * @return AppProxy instance
                                                                  */
                                                                  function newAppInstance(bytes32 _appId, address _appBase)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                                                                      returns (ERCProxy appProxy)
                                                                  {
                                                                      return newAppInstance(_appId, _appBase, new bytes(0), false);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Create a new instance of an app linked to this kernel and set its base
                                                                  *      implementation if it was not already set
                                                                  * @notice Create a new upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`. `_setDefault ? 'Also sets it as the default app instance.':''`
                                                                  * @param _appId Identifier for app
                                                                  * @param _appBase Address of the app's base implementation
                                                                  * @param _initializePayload Payload for call made by the proxy during its construction to initialize
                                                                  * @param _setDefault Whether the app proxy app is the default one.
                                                                  *        Useful when the Kernel needs to know of an instance of a particular app,
                                                                  *        like Vault for escape hatch mechanism.
                                                                  * @return AppProxy instance
                                                                  */
                                                                  function newAppInstance(bytes32 _appId, address _appBase, bytes _initializePayload, bool _setDefault)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                                                                      returns (ERCProxy appProxy)
                                                                  {
                                                                      _setAppIfNew(KERNEL_APP_BASES_NAMESPACE, _appId, _appBase);
                                                                      appProxy = newAppProxy(this, _appId, _initializePayload);
                                                                      // By calling setApp directly and not the internal functions, we make sure the params are checked
                                                                      // and it will only succeed if sender has permissions to set something to the namespace.
                                                                      if (_setDefault) {
                                                                          setApp(KERNEL_APP_ADDR_NAMESPACE, _appId, appProxy);
                                                                      }
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Create a new pinned instance of an app linked to this kernel
                                                                  * @notice Create a new non-upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`.
                                                                  * @param _appId Identifier for app
                                                                  * @param _appBase Address of the app's base implementation
                                                                  * @return AppProxy instance
                                                                  */
                                                                  function newPinnedAppInstance(bytes32 _appId, address _appBase)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                                                                      returns (ERCProxy appProxy)
                                                                  {
                                                                      return newPinnedAppInstance(_appId, _appBase, new bytes(0), false);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Create a new pinned instance of an app linked to this kernel and set
                                                                  *      its base implementation if it was not already set
                                                                  * @notice Create a new non-upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`. `_setDefault ? 'Also sets it as the default app instance.':''`
                                                                  * @param _appId Identifier for app
                                                                  * @param _appBase Address of the app's base implementation
                                                                  * @param _initializePayload Payload for call made by the proxy during its construction to initialize
                                                                  * @param _setDefault Whether the app proxy app is the default one.
                                                                  *        Useful when the Kernel needs to know of an instance of a particular app,
                                                                  *        like Vault for escape hatch mechanism.
                                                                  * @return AppProxy instance
                                                                  */
                                                                  function newPinnedAppInstance(bytes32 _appId, address _appBase, bytes _initializePayload, bool _setDefault)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_BASES_NAMESPACE, _appId))
                                                                      returns (ERCProxy appProxy)
                                                                  {
                                                                      _setAppIfNew(KERNEL_APP_BASES_NAMESPACE, _appId, _appBase);
                                                                      appProxy = newAppProxyPinned(this, _appId, _initializePayload);
                                                                      // By calling setApp directly and not the internal functions, we make sure the params are checked
                                                                      // and it will only succeed if sender has permissions to set something to the namespace.
                                                                      if (_setDefault) {
                                                                          setApp(KERNEL_APP_ADDR_NAMESPACE, _appId, appProxy);
                                                                      }
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Set the resolving address of an app instance or base implementation
                                                                  * @notice Set the resolving address of `_appId` in namespace `_namespace` to `_app`
                                                                  * @param _namespace App namespace to use
                                                                  * @param _appId Identifier for app
                                                                  * @param _app Address of the app instance or base implementation
                                                                  * @return ID of app
                                                                  */
                                                                  function setApp(bytes32 _namespace, bytes32 _appId, address _app)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(_namespace, _appId))
                                                                  {
                                                                      _setApp(_namespace, _appId, _app);
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Set the default vault id for the escape hatch mechanism
                                                                  * @param _recoveryVaultAppId Identifier of the recovery vault app
                                                                  */
                                                                  function setRecoveryVaultAppId(bytes32 _recoveryVaultAppId)
                                                                      public
                                                                      auth(APP_MANAGER_ROLE, arr(KERNEL_APP_ADDR_NAMESPACE, _recoveryVaultAppId))
                                                                  {
                                                                      recoveryVaultAppId = _recoveryVaultAppId;
                                                                  }
                                                              
                                                                  // External access to default app id and namespace constants to mimic default getters for constants
                                                                  /* solium-disable function-order, mixedcase */
                                                                  function CORE_NAMESPACE() external pure returns (bytes32) { return KERNEL_CORE_NAMESPACE; }
                                                                  function APP_BASES_NAMESPACE() external pure returns (bytes32) { return KERNEL_APP_BASES_NAMESPACE; }
                                                                  function APP_ADDR_NAMESPACE() external pure returns (bytes32) { return KERNEL_APP_ADDR_NAMESPACE; }
                                                                  function KERNEL_APP_ID() external pure returns (bytes32) { return KERNEL_CORE_APP_ID; }
                                                                  function DEFAULT_ACL_APP_ID() external pure returns (bytes32) { return KERNEL_DEFAULT_ACL_APP_ID; }
                                                                  /* solium-enable function-order, mixedcase */
                                                              
                                                                  /**
                                                                  * @dev Get the address of an app instance or base implementation
                                                                  * @param _namespace App namespace to use
                                                                  * @param _appId Identifier for app
                                                                  * @return Address of the app
                                                                  */
                                                                  function getApp(bytes32 _namespace, bytes32 _appId) public view returns (address) {
                                                                      return apps[_namespace][_appId];
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Get the address of the recovery Vault instance (to recover funds)
                                                                  * @return Address of the Vault
                                                                  */
                                                                  function getRecoveryVault() public view returns (address) {
                                                                      return apps[KERNEL_APP_ADDR_NAMESPACE][recoveryVaultAppId];
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Get the installed ACL app
                                                                  * @return ACL app
                                                                  */
                                                                  function acl() public view returns (IACL) {
                                                                      return IACL(getApp(KERNEL_APP_ADDR_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID));
                                                                  }
                                                              
                                                                  /**
                                                                  * @dev Function called by apps to check ACL on kernel or to check permission status
                                                                  * @param _who Sender of the original call
                                                                  * @param _where Address of the app
                                                                  * @param _what Identifier for a group of actions in app
                                                                  * @param _how Extra data for ACL auth
                                                                  * @return Boolean indicating whether the ACL allows the role or not.
                                                                  *         Always returns false if the kernel hasn't been initialized yet.
                                                                  */
                                                                  function hasPermission(address _who, address _where, bytes32 _what, bytes _how) public view returns (bool) {
                                                                      IACL defaultAcl = acl();
                                                                      return address(defaultAcl) != address(0) && // Poor man's initialization check (saves gas)
                                                                          defaultAcl.hasPermission(_who, _where, _what, _how);
                                                                  }
                                                              
                                                                  function _setApp(bytes32 _namespace, bytes32 _appId, address _app) internal {
                                                                      require(isContract(_app), ERROR_APP_NOT_CONTRACT);
                                                                      apps[_namespace][_appId] = _app;
                                                                      emit SetApp(_namespace, _appId, _app);
                                                                  }
                                                              
                                                                  function _setAppIfNew(bytes32 _namespace, bytes32 _appId, address _app) internal {
                                                                      address app = getApp(_namespace, _appId);
                                                                      if (app != address(0)) {
                                                                          // The only way to set an app is if it passes the isContract check, so no need to check it again
                                                                          require(app == _app, ERROR_INVALID_APP_CHANGE);
                                                                      } else {
                                                                          _setApp(_namespace, _appId, _app);
                                                                      }
                                                                  }
                                                              
                                                                  modifier auth(bytes32 _role, uint256[] memory _params) {
                                                                      require(
                                                                          hasPermission(msg.sender, address(this), _role, ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)),
                                                                          ERROR_AUTH_FAILED
                                                                      );
                                                                      _;
                                                                  }
                                                              }

                                                              File 7 of 14: Lido
                                                              // SPDX-FileCopyrightText: 2020 Lido <[email protected]>
                                                              // SPDX-License-Identifier: GPL-3.0
                                                              pragma solidity 0.4.24;
                                                              /**
                                                                * @title Deposit contract interface
                                                                */
                                                              interface IDepositContract {
                                                                  /**
                                                                    * @notice Top-ups deposit of a validator on the ETH 2.0 side
                                                                    * @param pubkey Validator signing key
                                                                    * @param withdrawal_credentials Credentials that allows to withdraw funds
                                                                    * @param signature Signature of the request
                                                                    * @param deposit_data_root The deposits Merkle tree node, used as a checksum
                                                                    */
                                                                  function deposit(
                                                                      bytes /* 48 */ pubkey,
                                                                      bytes /* 32 */ withdrawal_credentials,
                                                                      bytes /* 96 */ signature,
                                                                      bytes32 deposit_data_root
                                                                  )
                                                                      external payable;
                                                              }
                                                              // SPDX-FileCopyrightText: 2020 Lido <[email protected]>
                                                              // SPDX-License-Identifier: GPL-3.0
                                                              /* See contracts/COMPILERS.md */
                                                              pragma solidity 0.4.24;
                                                              import "@aragon/os/contracts/apps/AragonApp.sol";
                                                              import "@aragon/os/contracts/lib/math/SafeMath.sol";
                                                              import "@aragon/os/contracts/lib/math/SafeMath64.sol";
                                                              import "@aragon/os/contracts/common/IsContract.sol";
                                                              import "solidity-bytes-utils/contracts/BytesLib.sol";
                                                              import "./interfaces/ILido.sol";
                                                              import "./interfaces/INodeOperatorsRegistry.sol";
                                                              import "./interfaces/IDepositContract.sol";
                                                              import "./StETH.sol";
                                                              /**
                                                              * @title Liquid staking pool implementation
                                                              *
                                                              * Lido is an Ethereum 2.0 liquid staking protocol solving the problem of frozen staked Ethers
                                                              * until transfers become available in Ethereum 2.0.
                                                              * Whitepaper: https://lido.fi/static/Lido:Ethereum-Liquid-Staking.pdf
                                                              *
                                                              * NOTE: the code below assumes moderate amount of node operators, e.g. up to 50.
                                                              *
                                                              * Since balances of all token holders change when the amount of total pooled Ether
                                                              * changes, this token cannot fully implement ERC20 standard: it only emits `Transfer`
                                                              * events upon explicit transfer between holders. In contrast, when Lido oracle reports
                                                              * rewards, no Transfer events are generated: doing so would require emitting an event
                                                              * for each token holder and thus running an unbounded loop.
                                                              */
                                                              contract Lido is ILido, IsContract, StETH, AragonApp {
                                                                  using SafeMath for uint256;
                                                                  using SafeMath64 for uint64;
                                                                  using UnstructuredStorage for bytes32;
                                                                  /// ACL
                                                                  bytes32 constant public PAUSE_ROLE = keccak256("PAUSE_ROLE");
                                                                  bytes32 constant public MANAGE_FEE = keccak256("MANAGE_FEE");
                                                                  bytes32 constant public MANAGE_WITHDRAWAL_KEY = keccak256("MANAGE_WITHDRAWAL_KEY");
                                                                  bytes32 constant public SET_ORACLE = keccak256("SET_ORACLE");
                                                                  bytes32 constant public BURN_ROLE = keccak256("BURN_ROLE");
                                                                  bytes32 constant public SET_TREASURY = keccak256("SET_TREASURY");
                                                                  bytes32 constant public SET_INSURANCE_FUND = keccak256("SET_INSURANCE_FUND");
                                                                  uint256 constant public PUBKEY_LENGTH = 48;
                                                                  uint256 constant public WITHDRAWAL_CREDENTIALS_LENGTH = 32;
                                                                  uint256 constant public SIGNATURE_LENGTH = 96;
                                                                  uint256 constant public DEPOSIT_SIZE = 32 ether;
                                                                  uint256 internal constant DEPOSIT_AMOUNT_UNIT = 1000000000 wei;
                                                                  /// @dev default value for maximum number of Ethereum 2.0 validators registered in a single depositBufferedEther call
                                                                  uint256 internal constant DEFAULT_MAX_DEPOSITS_PER_CALL = 16;
                                                                  bytes32 internal constant FEE_POSITION = keccak256("lido.Lido.fee");
                                                                  bytes32 internal constant TREASURY_FEE_POSITION = keccak256("lido.Lido.treasuryFee");
                                                                  bytes32 internal constant INSURANCE_FEE_POSITION = keccak256("lido.Lido.insuranceFee");
                                                                  bytes32 internal constant NODE_OPERATORS_FEE_POSITION = keccak256("lido.Lido.nodeOperatorsFee");
                                                                  bytes32 internal constant DEPOSIT_CONTRACT_POSITION = keccak256("lido.Lido.depositContract");
                                                                  bytes32 internal constant ORACLE_POSITION = keccak256("lido.Lido.oracle");
                                                                  bytes32 internal constant NODE_OPERATORS_REGISTRY_POSITION = keccak256("lido.Lido.nodeOperatorsRegistry");
                                                                  bytes32 internal constant TREASURY_POSITION = keccak256("lido.Lido.treasury");
                                                                  bytes32 internal constant INSURANCE_FUND_POSITION = keccak256("lido.Lido.insuranceFund");
                                                                  /// @dev amount of Ether (on the current Ethereum side) buffered on this smart contract balance
                                                                  bytes32 internal constant BUFFERED_ETHER_POSITION = keccak256("lido.Lido.bufferedEther");
                                                                  /// @dev number of deposited validators (incrementing counter of deposit operations).
                                                                  bytes32 internal constant DEPOSITED_VALIDATORS_POSITION = keccak256("lido.Lido.depositedValidators");
                                                                  /// @dev total amount of Beacon-side Ether (sum of all the balances of Lido validators)
                                                                  bytes32 internal constant BEACON_BALANCE_POSITION = keccak256("lido.Lido.beaconBalance");
                                                                  /// @dev number of Lido's validators available in the Beacon state
                                                                  bytes32 internal constant BEACON_VALIDATORS_POSITION = keccak256("lido.Lido.beaconValidators");
                                                                  /// @dev Credentials which allows the DAO to withdraw Ether on the 2.0 side
                                                                  bytes32 internal constant WITHDRAWAL_CREDENTIALS_POSITION = keccak256("lido.Lido.withdrawalCredentials");
                                                                  /**
                                                                  * @dev As AragonApp, Lido contract must be initialized with following variables:
                                                                  * @param depositContract official ETH2 Deposit contract
                                                                  * @param _oracle oracle contract
                                                                  * @param _operators instance of Node Operators Registry
                                                                  */
                                                                  function initialize(
                                                                      IDepositContract depositContract,
                                                                      address _oracle,
                                                                      INodeOperatorsRegistry _operators,
                                                                      address _treasury,
                                                                      address _insuranceFund
                                                                  )
                                                                      public onlyInit
                                                                  {
                                                                      _setDepositContract(depositContract);
                                                                      _setOracle(_oracle);
                                                                      _setOperators(_operators);
                                                                      _setTreasury(_treasury);
                                                                      _setInsuranceFund(_insuranceFund);
                                                                      initialized();
                                                                  }
                                                                  /**
                                                                  * @notice Send funds to the pool
                                                                  * @dev Users are able to submit their funds by transacting to the fallback function.
                                                                  * Unlike vanilla Eth2.0 Deposit contract, accepting only 32-Ether transactions, Lido
                                                                  * accepts payments of any size. Submitted Ethers are stored in Buffer until someone calls
                                                                  * depositBufferedEther() and pushes them to the ETH2 Deposit contract.
                                                                  */
                                                                  function() external payable {
                                                                      // protection against accidental submissions by calling non-existent function
                                                                      require(msg.data.length == 0, "NON_EMPTY_DATA");
                                                                      _submit(0);
                                                                  }
                                                                  /**
                                                                  * @notice Send funds to the pool with optional _referral parameter
                                                                  * @dev This function is alternative way to submit funds. Supports optional referral address.
                                                                  * @return Amount of StETH shares generated
                                                                  */
                                                                  function submit(address _referral) external payable returns (uint256) {
                                                                      return _submit(_referral);
                                                                  }
                                                                  /**
                                                                  * @notice Deposits buffered ethers to the official DepositContract.
                                                                  * @dev This function is separated from submit() to reduce the cost of sending funds.
                                                                  */
                                                                  function depositBufferedEther() external {
                                                                      return _depositBufferedEther(DEFAULT_MAX_DEPOSITS_PER_CALL);
                                                                  }
                                                                  /**
                                                                    * @notice Deposits buffered ethers to the official DepositContract, making no more than `_maxDeposits` deposit calls.
                                                                    * @dev This function is separated from submit() to reduce the cost of sending funds.
                                                                    */
                                                                  function depositBufferedEther(uint256 _maxDeposits) external {
                                                                      return _depositBufferedEther(_maxDeposits);
                                                                  }
                                                                  function burnShares(address _account, uint256 _sharesAmount)
                                                                      external
                                                                      authP(BURN_ROLE, arr(_account, _sharesAmount))
                                                                      returns (uint256 newTotalShares)
                                                                  {
                                                                      return _burnShares(_account, _sharesAmount);
                                                                  }
                                                                  /**
                                                                    * @notice Stop pool routine operations
                                                                    */
                                                                  function stop() external auth(PAUSE_ROLE) {
                                                                      _stop();
                                                                  }
                                                                  /**
                                                                    * @notice Resume pool routine operations
                                                                    */
                                                                  function resume() external auth(PAUSE_ROLE) {
                                                                      _resume();
                                                                  }
                                                                  /**
                                                                    * @notice Set fee rate to `_feeBasisPoints` basis points. The fees are accrued when oracles report staking results
                                                                    * @param _feeBasisPoints Fee rate, in basis points
                                                                    */
                                                                  function setFee(uint16 _feeBasisPoints) external auth(MANAGE_FEE) {
                                                                      _setBPValue(FEE_POSITION, _feeBasisPoints);
                                                                      emit FeeSet(_feeBasisPoints);
                                                                  }
                                                                  /**
                                                                    * @notice Set fee distribution: `_treasuryFeeBasisPoints` basis points go to the treasury, `_insuranceFeeBasisPoints` basis points go to the insurance fund, `_operatorsFeeBasisPoints` basis points go to node operators. The sum has to be 10 000.
                                                                    */
                                                                  function setFeeDistribution(
                                                                      uint16 _treasuryFeeBasisPoints,
                                                                      uint16 _insuranceFeeBasisPoints,
                                                                      uint16 _operatorsFeeBasisPoints
                                                                  )
                                                                      external auth(MANAGE_FEE)
                                                                  {
                                                                      require(
                                                                          10000 == uint256(_treasuryFeeBasisPoints)
                                                                          .add(uint256(_insuranceFeeBasisPoints))
                                                                          .add(uint256(_operatorsFeeBasisPoints)),
                                                                          "FEES_DONT_ADD_UP"
                                                                      );
                                                                      _setBPValue(TREASURY_FEE_POSITION, _treasuryFeeBasisPoints);
                                                                      _setBPValue(INSURANCE_FEE_POSITION, _insuranceFeeBasisPoints);
                                                                      _setBPValue(NODE_OPERATORS_FEE_POSITION, _operatorsFeeBasisPoints);
                                                                      emit FeeDistributionSet(_treasuryFeeBasisPoints, _insuranceFeeBasisPoints, _operatorsFeeBasisPoints);
                                                                  }
                                                                  /**
                                                                    * @notice Set authorized oracle contract address to `_oracle`
                                                                    * @dev Contract specified here is allowed to make periodical updates of beacon states
                                                                    * by calling pushBeacon.
                                                                    * @param _oracle oracle contract
                                                                    */
                                                                  function setOracle(address _oracle) external auth(SET_ORACLE) {
                                                                      _setOracle(_oracle);
                                                                  }
                                                                  /**
                                                                    * @notice Set treasury contract address to `_treasury`
                                                                    * @dev Contract specified here is used to accumulate the protocol treasury fee.
                                                                    * @param _treasury contract which accumulates treasury fee.
                                                                    */
                                                                  function setTreasury(address _treasury) external auth(SET_TREASURY) {
                                                                      _setTreasury(_treasury);
                                                                  }
                                                                  /**
                                                                    * @notice Set insuranceFund contract address to `_insuranceFund`
                                                                    * @dev Contract specified here is used to accumulate the protocol insurance fee.
                                                                    * @param _insuranceFund contract which accumulates insurance fee.
                                                                    */
                                                                  function setInsuranceFund(address _insuranceFund) external auth(SET_INSURANCE_FUND) {
                                                                      _setInsuranceFund(_insuranceFund);
                                                                  }
                                                                  /**
                                                                    * @notice Set credentials to withdraw ETH on ETH 2.0 side after the phase 2 is launched to `_withdrawalCredentials`
                                                                    * @dev Note that setWithdrawalCredentials discards all unused signing keys as the signatures are invalidated.
                                                                    * @param _withdrawalCredentials hash of withdrawal multisignature key as accepted by
                                                                    *        the deposit_contract.deposit function
                                                                    */
                                                                  function setWithdrawalCredentials(bytes32 _withdrawalCredentials) external auth(MANAGE_WITHDRAWAL_KEY) {
                                                                      WITHDRAWAL_CREDENTIALS_POSITION.setStorageBytes32(_withdrawalCredentials);
                                                                      getOperators().trimUnusedKeys();
                                                                      emit WithdrawalCredentialsSet(_withdrawalCredentials);
                                                                  }
                                                                  /**
                                                                    * @notice Issues withdrawal request. Not implemented.
                                                                    * @param _amount Amount of StETH to withdraw
                                                                    * @param _pubkeyHash Receiving address
                                                                    */
                                                                  function withdraw(uint256 _amount, bytes32 _pubkeyHash) external whenNotStopped { /* solhint-disable-line no-unused-vars */
                                                                      //will be upgraded to an actual implementation when withdrawals are enabled (Phase 1.5 or 2 of Eth2 launch, likely late 2021 or 2022).
                                                                      //at the moment withdrawals are not possible in the beacon chain and there's no workaround
                                                                      revert("NOT_IMPLEMENTED_YET");
                                                                  }
                                                                  /**
                                                                  * @notice Updates the number of Lido-controlled keys in the beacon validators set and their total balance.
                                                                  * @dev periodically called by the Oracle contract
                                                                  * @param _beaconValidators number of Lido's keys in the beacon state
                                                                  * @param _beaconBalance simmarized balance of Lido-controlled keys in wei
                                                                  */
                                                                  function pushBeacon(uint256 _beaconValidators, uint256 _beaconBalance) external whenNotStopped {
                                                                      require(msg.sender == getOracle(), "APP_AUTH_FAILED");
                                                                      uint256 depositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256();
                                                                      require(_beaconValidators <= depositedValidators, "REPORTED_MORE_DEPOSITED");
                                                                      uint256 beaconValidators = BEACON_VALIDATORS_POSITION.getStorageUint256();
                                                                      // Since the calculation of funds in the ingress queue is based on the number of validators
                                                                      // that are in a transient state (deposited but not seen on beacon yet), we can't decrease the previously
                                                                      // reported number (we'll be unable to figure out who is in the queue and count them).
                                                                      // See LIP-1 for details https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-1.md
                                                                      require(_beaconValidators >= beaconValidators, "REPORTED_LESS_VALIDATORS");
                                                                      uint256 appearedValidators = _beaconValidators.sub(beaconValidators);
                                                                      // RewardBase is the amount of money that is not included in the reward calculation
                                                                      // Just appeared validators * 32 added to the previously reported beacon balance
                                                                      uint256 rewardBase = (appearedValidators.mul(DEPOSIT_SIZE)).add(BEACON_BALANCE_POSITION.getStorageUint256());
                                                                      // Save the current beacon balance and validators to
                                                                      // calcuate rewards on the next push
                                                                      BEACON_BALANCE_POSITION.setStorageUint256(_beaconBalance);
                                                                      BEACON_VALIDATORS_POSITION.setStorageUint256(_beaconValidators);
                                                                      if (_beaconBalance > rewardBase) {
                                                                          uint256 rewards = _beaconBalance.sub(rewardBase);
                                                                          distributeRewards(rewards);
                                                                      }
                                                                  }
                                                                  /**
                                                                    * @notice Send funds to recovery Vault. Overrides default AragonApp behaviour.
                                                                    * @param _token Token to be sent to recovery vault.
                                                                    */
                                                                  function transferToVault(address _token) external {
                                                                      require(allowRecoverability(_token), "RECOVER_DISALLOWED");
                                                                      address vault = getRecoveryVault();
                                                                      require(isContract(vault), "RECOVER_VAULT_NOT_CONTRACT");
                                                                      uint256 balance;
                                                                      if (_token == ETH) {
                                                                          balance = _getUnaccountedEther();
                                                                          vault.transfer(balance);
                                                                      } else {
                                                                          ERC20 token = ERC20(_token);
                                                                          balance = token.staticBalanceOf(this);
                                                                          // safeTransfer comes from overriden default implementation
                                                                          require(token.safeTransfer(vault, balance), "RECOVER_TOKEN_TRANSFER_FAILED");
                                                                      }
                                                                      emit RecoverToVault(vault, _token, balance);
                                                                  }
                                                                  /**
                                                                    * @notice Returns staking rewards fee rate
                                                                    */
                                                                  function getFee() external view returns (uint16 feeBasisPoints) {
                                                                      return _getFee();
                                                                  }
                                                                  /**
                                                                    * @notice Returns fee distribution proportion
                                                                    */
                                                                  function getFeeDistribution()
                                                                      external
                                                                      view
                                                                      returns (
                                                                          uint16 treasuryFeeBasisPoints,
                                                                          uint16 insuranceFeeBasisPoints,
                                                                          uint16 operatorsFeeBasisPoints
                                                                      )
                                                                  {
                                                                      return _getFeeDistribution();
                                                                  }
                                                                  /**
                                                                    * @notice Returns current credentials to withdraw ETH on ETH 2.0 side after the phase 2 is launched
                                                                    */
                                                                  function getWithdrawalCredentials() public view returns (bytes32) {
                                                                      return WITHDRAWAL_CREDENTIALS_POSITION.getStorageBytes32();
                                                                  }
                                                                  /**
                                                                  * @notice Get the amount of Ether temporary buffered on this contract balance
                                                                  * @dev Buffered balance is kept on the contract from the moment the funds are received from user
                                                                  * until the moment they are actually sent to the official Deposit contract.
                                                                  * @return uint256 of buffered funds in wei
                                                                  */
                                                                  function getBufferedEther() external view returns (uint256) {
                                                                      return _getBufferedEther();
                                                                  }
                                                                  /**
                                                                    * @notice Gets deposit contract handle
                                                                    */
                                                                  function getDepositContract() public view returns (IDepositContract) {
                                                                      return IDepositContract(DEPOSIT_CONTRACT_POSITION.getStorageAddress());
                                                                  }
                                                                  /**
                                                                  * @notice Gets authorized oracle address
                                                                  * @return address of oracle contract
                                                                  */
                                                                  function getOracle() public view returns (address) {
                                                                      return ORACLE_POSITION.getStorageAddress();
                                                                  }
                                                                  /**
                                                                    * @notice Gets node operators registry interface handle
                                                                    */
                                                                  function getOperators() public view returns (INodeOperatorsRegistry) {
                                                                      return INodeOperatorsRegistry(NODE_OPERATORS_REGISTRY_POSITION.getStorageAddress());
                                                                  }
                                                                  /**
                                                                    * @notice Returns the treasury address
                                                                    */
                                                                  function getTreasury() public view returns (address) {
                                                                      return TREASURY_POSITION.getStorageAddress();
                                                                  }
                                                                  /**
                                                                    * @notice Returns the insurance fund address
                                                                    */
                                                                  function getInsuranceFund() public view returns (address) {
                                                                      return INSURANCE_FUND_POSITION.getStorageAddress();
                                                                  }
                                                                  /**
                                                                  * @notice Returns the key values related to Beacon-side
                                                                  * @return depositedValidators - number of deposited validators
                                                                  * @return beaconValidators - number of Lido's validators visible in the Beacon state, reported by oracles
                                                                  * @return beaconBalance - total amount of Beacon-side Ether (sum of all the balances of Lido validators)
                                                                  */
                                                                  function getBeaconStat() public view returns (uint256 depositedValidators, uint256 beaconValidators, uint256 beaconBalance) {
                                                                      depositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256();
                                                                      beaconValidators = BEACON_VALIDATORS_POSITION.getStorageUint256();
                                                                      beaconBalance = BEACON_BALANCE_POSITION.getStorageUint256();
                                                                  }
                                                                  /**
                                                                  * @dev Sets the address of Deposit contract
                                                                  * @param _contract the address of Deposit contract
                                                                  */
                                                                  function _setDepositContract(IDepositContract _contract) internal {
                                                                      require(isContract(address(_contract)), "NOT_A_CONTRACT");
                                                                      DEPOSIT_CONTRACT_POSITION.setStorageAddress(address(_contract));
                                                                  }
                                                                  /**
                                                                  * @dev Internal function to set authorized oracle address
                                                                  * @param _oracle oracle contract
                                                                  */
                                                                  function _setOracle(address _oracle) internal {
                                                                      require(isContract(_oracle), "NOT_A_CONTRACT");
                                                                      ORACLE_POSITION.setStorageAddress(_oracle);
                                                                  }
                                                                  /**
                                                                  * @dev Internal function to set node operator registry address
                                                                  * @param _r registry of node operators
                                                                  */
                                                                  function _setOperators(INodeOperatorsRegistry _r) internal {
                                                                      require(isContract(_r), "NOT_A_CONTRACT");
                                                                      NODE_OPERATORS_REGISTRY_POSITION.setStorageAddress(_r);
                                                                  }
                                                                  function _setTreasury(address _treasury) internal {
                                                                      require(_treasury != address(0), "SET_TREASURY_ZERO_ADDRESS");
                                                                      TREASURY_POSITION.setStorageAddress(_treasury);
                                                                  }
                                                                  function _setInsuranceFund(address _insuranceFund) internal {
                                                                      require(_insuranceFund != address(0), "SET_INSURANCE_FUND_ZERO_ADDRESS");
                                                                      INSURANCE_FUND_POSITION.setStorageAddress(_insuranceFund);
                                                                  }
                                                                  /**
                                                                  * @dev Process user deposit, mints liquid tokens and increase the pool buffer
                                                                  * @param _referral address of referral.
                                                                  * @return amount of StETH shares generated
                                                                  */
                                                                  function _submit(address _referral) internal whenNotStopped returns (uint256) {
                                                                      address sender = msg.sender;
                                                                      uint256 deposit = msg.value;
                                                                      require(deposit != 0, "ZERO_DEPOSIT");
                                                                      uint256 sharesAmount = getSharesByPooledEth(deposit);
                                                                      if (sharesAmount == 0) {
                                                                          // totalControlledEther is 0: either the first-ever deposit or complete slashing
                                                                          // assume that shares correspond to Ether 1-to-1
                                                                          sharesAmount = deposit;
                                                                      }
                                                                      _mintShares(sender, sharesAmount);
                                                                      _submitted(sender, deposit, _referral);
                                                                      _emitTransferAfterMintingShares(sender, sharesAmount);
                                                                      return sharesAmount;
                                                                  }
                                                                  /**
                                                                   * @dev Emits an {Transfer} event where from is 0 address. Indicates mint events.
                                                                   */
                                                                  function _emitTransferAfterMintingShares(address _to, uint256 _sharesAmount) internal {
                                                                      emit Transfer(address(0), _to, getPooledEthByShares(_sharesAmount));
                                                                  }
                                                                  /**
                                                                  * @dev Deposits buffered eth to the DepositContract and assigns chunked deposits to node operators
                                                                  */
                                                                  function _depositBufferedEther(uint256 _maxDeposits) internal whenNotStopped {
                                                                      uint256 buffered = _getBufferedEther();
                                                                      if (buffered >= DEPOSIT_SIZE) {
                                                                          uint256 unaccounted = _getUnaccountedEther();
                                                                          uint256 numDeposits = buffered.div(DEPOSIT_SIZE);
                                                                          _markAsUnbuffered(_ETH2Deposit(numDeposits < _maxDeposits ? numDeposits : _maxDeposits));
                                                                          assert(_getUnaccountedEther() == unaccounted);
                                                                      }
                                                                  }
                                                                  /**
                                                                  * @dev Performs deposits to the ETH 2.0 side
                                                                  * @param _numDeposits Number of deposits to perform
                                                                  * @return actually deposited Ether amount
                                                                  */
                                                                  function _ETH2Deposit(uint256 _numDeposits) internal returns (uint256) {
                                                                      (bytes memory pubkeys, bytes memory signatures) = getOperators().assignNextSigningKeys(_numDeposits);
                                                                      if (pubkeys.length == 0) {
                                                                          return 0;
                                                                      }
                                                                      require(pubkeys.length.mod(PUBKEY_LENGTH) == 0, "REGISTRY_INCONSISTENT_PUBKEYS_LEN");
                                                                      require(signatures.length.mod(SIGNATURE_LENGTH) == 0, "REGISTRY_INCONSISTENT_SIG_LEN");
                                                                      uint256 numKeys = pubkeys.length.div(PUBKEY_LENGTH);
                                                                      require(numKeys == signatures.length.div(SIGNATURE_LENGTH), "REGISTRY_INCONSISTENT_SIG_COUNT");
                                                                      for (uint256 i = 0; i < numKeys; ++i) {
                                                                          bytes memory pubkey = BytesLib.slice(pubkeys, i * PUBKEY_LENGTH, PUBKEY_LENGTH);
                                                                          bytes memory signature = BytesLib.slice(signatures, i * SIGNATURE_LENGTH, SIGNATURE_LENGTH);
                                                                          _stake(pubkey, signature);
                                                                      }
                                                                      DEPOSITED_VALIDATORS_POSITION.setStorageUint256(
                                                                          DEPOSITED_VALIDATORS_POSITION.getStorageUint256().add(numKeys)
                                                                      );
                                                                      return numKeys.mul(DEPOSIT_SIZE);
                                                                  }
                                                                  /**
                                                                  * @dev Invokes a deposit call to the official Deposit contract
                                                                  * @param _pubkey Validator to stake for
                                                                  * @param _signature Signature of the deposit call
                                                                  */
                                                                  function _stake(bytes memory _pubkey, bytes memory _signature) internal {
                                                                      bytes32 withdrawalCredentials = getWithdrawalCredentials();
                                                                      require(withdrawalCredentials != 0, "EMPTY_WITHDRAWAL_CREDENTIALS");
                                                                      uint256 value = DEPOSIT_SIZE;
                                                                      // The following computations and Merkle tree-ization will make official Deposit contract happy
                                                                      uint256 depositAmount = value.div(DEPOSIT_AMOUNT_UNIT);
                                                                      assert(depositAmount.mul(DEPOSIT_AMOUNT_UNIT) == value);    // properly rounded
                                                                      // Compute deposit data root (`DepositData` hash tree root) according to deposit_contract.sol
                                                                      bytes32 pubkeyRoot = sha256(_pad64(_pubkey));
                                                                      bytes32 signatureRoot = sha256(
                                                                          abi.encodePacked(
                                                                              sha256(BytesLib.slice(_signature, 0, 64)),
                                                                              sha256(_pad64(BytesLib.slice(_signature, 64, SIGNATURE_LENGTH.sub(64))))
                                                                          )
                                                                      );
                                                                      bytes32 depositDataRoot = sha256(
                                                                          abi.encodePacked(
                                                                              sha256(abi.encodePacked(pubkeyRoot, withdrawalCredentials)),
                                                                              sha256(abi.encodePacked(_toLittleEndian64(depositAmount), signatureRoot))
                                                                          )
                                                                      );
                                                                      uint256 targetBalance = address(this).balance.sub(value);
                                                                      getDepositContract().deposit.value(value)(
                                                                          _pubkey, abi.encodePacked(withdrawalCredentials), _signature, depositDataRoot);
                                                                      require(address(this).balance == targetBalance, "EXPECTING_DEPOSIT_TO_HAPPEN");
                                                                  }
                                                                  /**
                                                                  * @dev Distributes rewards by minting and distributing corresponding amount of liquid tokens.
                                                                  * @param _totalRewards Total rewards accrued on the Ethereum 2.0 side in wei
                                                                  */
                                                                  function distributeRewards(uint256 _totalRewards) internal {
                                                                      // We need to take a defined percentage of the reported reward as a fee, and we do
                                                                      // this by minting new token shares and assigning them to the fee recipients (see
                                                                      // StETH docs for the explanation of the shares mechanics). The staking rewards fee
                                                                      // is defined in basis points (1 basis point is equal to 0.01%, 10000 is 100%).
                                                                      //
                                                                      // Since we've increased totalPooledEther by _totalRewards (which is already
                                                                      // performed by the time this function is called), the combined cost of all holders'
                                                                      // shares has became _totalRewards StETH tokens more, effectively splitting the reward
                                                                      // between each token holder proportionally to their token share.
                                                                      //
                                                                      // Now we want to mint new shares to the fee recipient, so that the total cost of the
                                                                      // newly-minted shares exactly corresponds to the fee taken:
                                                                      //
                                                                      // shares2mint * newShareCost = (_totalRewards * feeBasis) / 10000
                                                                      // newShareCost = newTotalPooledEther / (prevTotalShares + shares2mint)
                                                                      //
                                                                      // which follows to:
                                                                      //
                                                                      //                        _totalRewards * feeBasis * prevTotalShares
                                                                      // shares2mint = --------------------------------------------------------------
                                                                      //                 (newTotalPooledEther * 10000) - (feeBasis * _totalRewards)
                                                                      //
                                                                      // The effect is that the given percentage of the reward goes to the fee recipient, and
                                                                      // the rest of the reward is distributed between token holders proportionally to their
                                                                      // token shares.
                                                                      uint256 feeBasis = _getFee();
                                                                      uint256 shares2mint = (
                                                                          _totalRewards.mul(feeBasis).mul(_getTotalShares())
                                                                          .div(
                                                                              _getTotalPooledEther().mul(10000)
                                                                              .sub(feeBasis.mul(_totalRewards))
                                                                          )
                                                                      );
                                                                      // Mint the calculated amount of shares to this contract address. This will reduce the
                                                                      // balances of the holders, as if the fee was taken in parts from each of them.
                                                                      _mintShares(address(this), shares2mint);
                                                                      (,uint16 insuranceFeeBasisPoints, uint16 operatorsFeeBasisPoints) = _getFeeDistribution();
                                                                      uint256 toInsuranceFund = shares2mint.mul(insuranceFeeBasisPoints).div(10000);
                                                                      address insuranceFund = getInsuranceFund();
                                                                      _transferShares(address(this), insuranceFund, toInsuranceFund);
                                                                      _emitTransferAfterMintingShares(insuranceFund, toInsuranceFund);
                                                                      uint256 distributedToOperatorsShares = _distributeNodeOperatorsReward(
                                                                          shares2mint.mul(operatorsFeeBasisPoints).div(10000)
                                                                      );
                                                                      // Transfer the rest of the fee to treasury
                                                                      uint256 toTreasury = shares2mint.sub(toInsuranceFund).sub(distributedToOperatorsShares);
                                                                      address treasury = getTreasury();
                                                                      _transferShares(address(this), treasury, toTreasury);
                                                                      _emitTransferAfterMintingShares(treasury, toTreasury);
                                                                  }
                                                                  function _distributeNodeOperatorsReward(uint256 _sharesToDistribute) internal returns (uint256 distributed) {
                                                                      (address[] memory recipients, uint256[] memory shares) = getOperators().getRewardsDistribution(_sharesToDistribute);
                                                                      assert(recipients.length == shares.length);
                                                                      distributed = 0;
                                                                      for (uint256 idx = 0; idx < recipients.length; ++idx) {
                                                                          _transferShares(
                                                                              address(this),
                                                                              recipients[idx],
                                                                              shares[idx]
                                                                          );
                                                                          _emitTransferAfterMintingShares(recipients[idx], shares[idx]);
                                                                          distributed = distributed.add(shares[idx]);
                                                                      }
                                                                  }
                                                                  /**
                                                                  * @dev Records a deposit made by a user with optional referral
                                                                  * @param _sender sender's address
                                                                  * @param _value Deposit value in wei
                                                                  * @param _referral address of the referral
                                                                  */
                                                                  function _submitted(address _sender, uint256 _value, address _referral) internal {
                                                                      BUFFERED_ETHER_POSITION.setStorageUint256(_getBufferedEther().add(_value));
                                                                      emit Submitted(_sender, _value, _referral);
                                                                  }
                                                                  /**
                                                                    * @dev Records a deposit to the deposit_contract.deposit function.
                                                                    * @param _amount Total amount deposited to the ETH 2.0 side
                                                                    */
                                                                  function _markAsUnbuffered(uint256 _amount) internal {
                                                                      BUFFERED_ETHER_POSITION.setStorageUint256(
                                                                          BUFFERED_ETHER_POSITION.getStorageUint256().sub(_amount));
                                                                      emit Unbuffered(_amount);
                                                                  }
                                                                  /**
                                                                    * @dev Write a value nominated in basis points
                                                                    */
                                                                  function _setBPValue(bytes32 _slot, uint16 _value) internal {
                                                                      require(_value <= 10000, "VALUE_OVER_100_PERCENT");
                                                                      _slot.setStorageUint256(uint256(_value));
                                                                  }
                                                                  /**
                                                                    * @dev Returns staking rewards fee rate
                                                                    */
                                                                  function _getFee() internal view returns (uint16) {
                                                                      return _readBPValue(FEE_POSITION);
                                                                  }
                                                                  /**
                                                                    * @dev Returns fee distribution proportion
                                                                    */
                                                                  function _getFeeDistribution() internal view
                                                                      returns (uint16 treasuryFeeBasisPoints, uint16 insuranceFeeBasisPoints, uint16 operatorsFeeBasisPoints)
                                                                  {
                                                                      treasuryFeeBasisPoints = _readBPValue(TREASURY_FEE_POSITION);
                                                                      insuranceFeeBasisPoints = _readBPValue(INSURANCE_FEE_POSITION);
                                                                      operatorsFeeBasisPoints = _readBPValue(NODE_OPERATORS_FEE_POSITION);
                                                                  }
                                                                  /**
                                                                    * @dev Read a value nominated in basis points
                                                                    */
                                                                  function _readBPValue(bytes32 _slot) internal view returns (uint16) {
                                                                      uint256 v = _slot.getStorageUint256();
                                                                      assert(v <= 10000);
                                                                      return uint16(v);
                                                                  }
                                                                  /**
                                                                    * @dev Gets the amount of Ether temporary buffered on this contract balance
                                                                    */
                                                                  function _getBufferedEther() internal view returns (uint256) {
                                                                      uint256 buffered = BUFFERED_ETHER_POSITION.getStorageUint256();
                                                                      assert(address(this).balance >= buffered);
                                                                      return buffered;
                                                                  }
                                                                  /**
                                                                    * @dev Gets unaccounted (excess) Ether on this contract balance
                                                                    */
                                                                  function _getUnaccountedEther() internal view returns (uint256) {
                                                                      return address(this).balance.sub(_getBufferedEther());
                                                                  }
                                                                  /**
                                                                  * @dev Calculates and returns the total base balance (multiple of 32) of validators in transient state,
                                                                  *      i.e. submitted to the official Deposit contract but not yet visible in the beacon state.
                                                                  * @return transient balance in wei (1e-18 Ether)
                                                                  */
                                                                  function _getTransientBalance() internal view returns (uint256) {
                                                                      uint256 depositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256();
                                                                      uint256 beaconValidators = BEACON_VALIDATORS_POSITION.getStorageUint256();
                                                                      // beaconValidators can never be less than deposited ones.
                                                                      assert(depositedValidators >= beaconValidators);
                                                                      uint256 transientValidators = depositedValidators.sub(beaconValidators);
                                                                      return transientValidators.mul(DEPOSIT_SIZE);
                                                                  }
                                                                  /**
                                                                  * @dev Gets the total amount of Ether controlled by the system
                                                                  * @return total balance in wei
                                                                  */
                                                                  function _getTotalPooledEther() internal view returns (uint256) {
                                                                      uint256 bufferedBalance = _getBufferedEther();
                                                                      uint256 beaconBalance = BEACON_BALANCE_POSITION.getStorageUint256();
                                                                      uint256 transientBalance = _getTransientBalance();
                                                                      return bufferedBalance.add(beaconBalance).add(transientBalance);
                                                                  }
                                                                  /**
                                                                    * @dev Padding memory array with zeroes up to 64 bytes on the right
                                                                    * @param _b Memory array of size 32 .. 64
                                                                    */
                                                                  function _pad64(bytes memory _b) internal pure returns (bytes memory) {
                                                                      assert(_b.length >= 32 && _b.length <= 64);
                                                                      if (64 == _b.length)
                                                                          return _b;
                                                                      bytes memory zero32 = new bytes(32);
                                                                      assembly { mstore(add(zero32, 0x20), 0) }
                                                                      if (32 == _b.length)
                                                                          return BytesLib.concat(_b, zero32);
                                                                      else
                                                                          return BytesLib.concat(_b, BytesLib.slice(zero32, 0, uint256(64).sub(_b.length)));
                                                                  }
                                                                  /**
                                                                    * @dev Converting value to little endian bytes and padding up to 32 bytes on the right
                                                                    * @param _value Number less than `2**64` for compatibility reasons
                                                                    */
                                                                  function _toLittleEndian64(uint256 _value) internal pure returns (uint256 result) {
                                                                      result = 0;
                                                                      uint256 temp_value = _value;
                                                                      for (uint256 i = 0; i < 8; ++i) {
                                                                          result = (result << 8) | (temp_value & 0xFF);
                                                                          temp_value >>= 8;
                                                                      }
                                                                      assert(0 == temp_value);    // fully converted
                                                                      result <<= (24 * 8);
                                                                  }
                                                                  function to64(uint256 v) internal pure returns (uint64) {
                                                                      assert(v <= uint256(uint64(-1)));
                                                                      return uint64(v);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./AppStorage.sol";
                                                              import "../acl/ACLSyntaxSugar.sol";
                                                              import "../common/Autopetrified.sol";
                                                              import "../common/ConversionHelpers.sol";
                                                              import "../common/ReentrancyGuard.sol";
                                                              import "../common/VaultRecoverable.sol";
                                                              import "../evmscript/EVMScriptRunner.sol";
                                                              // Contracts inheriting from AragonApp are, by default, immediately petrified upon deployment so
                                                              // that they can never be initialized.
                                                              // Unless overriden, this behaviour enforces those contracts to be usable only behind an AppProxy.
                                                              // ReentrancyGuard, EVMScriptRunner, and ACLSyntaxSugar are not directly used by this contract, but
                                                              // are included so that they are automatically usable by subclassing contracts
                                                              contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGuard, EVMScriptRunner, ACLSyntaxSugar {
                                                                  string private constant ERROR_AUTH_FAILED = "APP_AUTH_FAILED";
                                                                  modifier auth(bytes32 _role) {
                                                                      require(canPerform(msg.sender, _role, new uint256[](0)), ERROR_AUTH_FAILED);
                                                                      _;
                                                                  }
                                                                  modifier authP(bytes32 _role, uint256[] _params) {
                                                                      require(canPerform(msg.sender, _role, _params), ERROR_AUTH_FAILED);
                                                                      _;
                                                                  }
                                                                  /**
                                                                  * @dev Check whether an action can be performed by a sender for a particular role on this app
                                                                  * @param _sender Sender of the call
                                                                  * @param _role Role on this app
                                                                  * @param _params Permission params for the role
                                                                  * @return Boolean indicating whether the sender has the permissions to perform the action.
                                                                  *         Always returns false if the app hasn't been initialized yet.
                                                                  */
                                                                  function canPerform(address _sender, bytes32 _role, uint256[] _params) public view returns (bool) {
                                                                      if (!hasInitialized()) {
                                                                          return false;
                                                                      }
                                                                      IKernel linkedKernel = kernel();
                                                                      if (address(linkedKernel) == address(0)) {
                                                                          return false;
                                                                      }
                                                                      return linkedKernel.hasPermission(
                                                                          _sender,
                                                                          address(this),
                                                                          _role,
                                                                          ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)
                                                                      );
                                                                  }
                                                                  /**
                                                                  * @dev Get the recovery vault for the app
                                                                  * @return Recovery vault address for the app
                                                                  */
                                                                  function getRecoveryVault() public view returns (address) {
                                                                      // Funds recovery via a vault is only available when used with a kernel
                                                                      return kernel().getRecoveryVault(); // if kernel is not set, it will revert
                                                                  }
                                                              }
                                                              // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol
                                                              // Adapted to use pragma ^0.4.24 and satisfy our linter rules
                                                              pragma solidity ^0.4.24;
                                                              /**
                                                               * @title SafeMath
                                                               * @dev Math operations with safety checks that revert on error
                                                               */
                                                              library SafeMath {
                                                                  string private constant ERROR_ADD_OVERFLOW = "MATH_ADD_OVERFLOW";
                                                                  string private constant ERROR_SUB_UNDERFLOW = "MATH_SUB_UNDERFLOW";
                                                                  string private constant ERROR_MUL_OVERFLOW = "MATH_MUL_OVERFLOW";
                                                                  string private constant ERROR_DIV_ZERO = "MATH_DIV_ZERO";
                                                                  /**
                                                                  * @dev Multiplies two numbers, reverts on overflow.
                                                                  */
                                                                  function mul(uint256 _a, uint256 _b) internal pure returns (uint256) {
                                                                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                                                                      // benefit is lost if 'b' is also tested.
                                                                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                                                                      if (_a == 0) {
                                                                          return 0;
                                                                      }
                                                                      uint256 c = _a * _b;
                                                                      require(c / _a == _b, ERROR_MUL_OVERFLOW);
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
                                                                  */
                                                                  function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
                                                                      require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
                                                                      uint256 c = _a / _b;
                                                                      // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                                                                  */
                                                                  function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
                                                                      require(_b <= _a, ERROR_SUB_UNDERFLOW);
                                                                      uint256 c = _a - _b;
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Adds two numbers, reverts on overflow.
                                                                  */
                                                                  function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
                                                                      uint256 c = _a + _b;
                                                                      require(c >= _a, ERROR_ADD_OVERFLOW);
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
                                                                  * reverts when dividing by zero.
                                                                  */
                                                                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                      require(b != 0, ERROR_DIV_ZERO);
                                                                      return a % b;
                                                                  }
                                                              }
                                                              // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol
                                                              // Adapted for uint64, pragma ^0.4.24, and satisfying our linter rules
                                                              // Also optimized the mul() implementation, see https://github.com/aragon/aragonOS/pull/417
                                                              pragma solidity ^0.4.24;
                                                              /**
                                                               * @title SafeMath64
                                                               * @dev Math operations for uint64 with safety checks that revert on error
                                                               */
                                                              library SafeMath64 {
                                                                  string private constant ERROR_ADD_OVERFLOW = "MATH64_ADD_OVERFLOW";
                                                                  string private constant ERROR_SUB_UNDERFLOW = "MATH64_SUB_UNDERFLOW";
                                                                  string private constant ERROR_MUL_OVERFLOW = "MATH64_MUL_OVERFLOW";
                                                                  string private constant ERROR_DIV_ZERO = "MATH64_DIV_ZERO";
                                                                  /**
                                                                  * @dev Multiplies two numbers, reverts on overflow.
                                                                  */
                                                                  function mul(uint64 _a, uint64 _b) internal pure returns (uint64) {
                                                                      uint256 c = uint256(_a) * uint256(_b);
                                                                      require(c < 0x010000000000000000, ERROR_MUL_OVERFLOW); // 2**64 (less gas this way)
                                                                      return uint64(c);
                                                                  }
                                                                  /**
                                                                  * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
                                                                  */
                                                                  function div(uint64 _a, uint64 _b) internal pure returns (uint64) {
                                                                      require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
                                                                      uint64 c = _a / _b;
                                                                      // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                                                                  */
                                                                  function sub(uint64 _a, uint64 _b) internal pure returns (uint64) {
                                                                      require(_b <= _a, ERROR_SUB_UNDERFLOW);
                                                                      uint64 c = _a - _b;
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Adds two numbers, reverts on overflow.
                                                                  */
                                                                  function add(uint64 _a, uint64 _b) internal pure returns (uint64) {
                                                                      uint64 c = _a + _b;
                                                                      require(c >= _a, ERROR_ADD_OVERFLOW);
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
                                                                  * reverts when dividing by zero.
                                                                  */
                                                                  function mod(uint64 a, uint64 b) internal pure returns (uint64) {
                                                                      require(b != 0, ERROR_DIV_ZERO);
                                                                      return a % b;
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              contract IsContract {
                                                                  /*
                                                                  * NOTE: this should NEVER be used for authentication
                                                                  * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                                                                  *
                                                                  * This is only intended to be used as a sanity check that an address is actually a contract,
                                                                  * RATHER THAN an address not being a contract.
                                                                  */
                                                                  function isContract(address _target) internal view returns (bool) {
                                                                      if (_target == address(0)) {
                                                                          return false;
                                                                      }
                                                                      uint256 size;
                                                                      assembly { size := extcodesize(_target) }
                                                                      return size > 0;
                                                                  }
                                                              }
                                                              /*
                                                               * @title Solidity Bytes Arrays Utils
                                                               * @author Gonçalo Sá <[email protected]>
                                                               *
                                                               * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
                                                               *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
                                                               */
                                                              pragma solidity ^0.4.19;
                                                              library BytesLib {
                                                                  function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes) {
                                                                      bytes memory tempBytes;
                                                                      assembly {
                                                                          // Get a location of some free memory and store it in tempBytes as
                                                                          // Solidity does for memory variables.
                                                                          tempBytes := mload(0x40)
                                                                          // Store the length of the first bytes array at the beginning of
                                                                          // the memory for tempBytes.
                                                                          let length := mload(_preBytes)
                                                                          mstore(tempBytes, length)
                                                                          // Maintain a memory counter for the current write location in the
                                                                          // temp bytes array by adding the 32 bytes for the array length to
                                                                          // the starting location.
                                                                          let mc := add(tempBytes, 0x20)
                                                                          // Stop copying when the memory counter reaches the length of the
                                                                          // first bytes array.
                                                                          let end := add(mc, length)
                                                                          for {
                                                                              // Initialize a copy counter to the start of the _preBytes data,
                                                                              // 32 bytes into its memory.
                                                                              let cc := add(_preBytes, 0x20)
                                                                          } lt(mc, end) {
                                                                              // Increase both counters by 32 bytes each iteration.
                                                                              mc := add(mc, 0x20)
                                                                              cc := add(cc, 0x20)
                                                                          } {
                                                                              // Write the _preBytes data into the tempBytes memory 32 bytes
                                                                              // at a time.
                                                                              mstore(mc, mload(cc))
                                                                          }
                                                                          // Add the length of _postBytes to the current length of tempBytes
                                                                          // and store it as the new length in the first 32 bytes of the
                                                                          // tempBytes memory.
                                                                          length := mload(_postBytes)
                                                                          mstore(tempBytes, add(length, mload(tempBytes)))
                                                                          // Move the memory counter back from a multiple of 0x20 to the
                                                                          // actual end of the _preBytes data.
                                                                          mc := end
                                                                          // Stop copying when the memory counter reaches the new combined
                                                                          // length of the arrays.
                                                                          end := add(mc, length)
                                                                          for {
                                                                              let cc := add(_postBytes, 0x20)
                                                                          } lt(mc, end) {
                                                                              mc := add(mc, 0x20)
                                                                              cc := add(cc, 0x20)
                                                                          } {
                                                                              mstore(mc, mload(cc))
                                                                          }
                                                                          // Update the free-memory pointer by padding our last write location
                                                                          // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
                                                                          // next 32 byte block, then round down to the nearest multiple of
                                                                          // 32. If the sum of the length of the two arrays is zero then add 
                                                                          // one before rounding down to leave a blank 32 bytes (the length block with 0).
                                                                          mstore(0x40, and(
                                                                            add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                                                                            not(31) // Round down to the nearest 32 bytes.
                                                                          ))
                                                                      }
                                                                      return tempBytes;
                                                                  }
                                                                  function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
                                                                      assembly {
                                                                          // Read the first 32 bytes of _preBytes storage, which is the length
                                                                          // of the array. (We don't need to use the offset into the slot
                                                                          // because arrays use the entire slot.)
                                                                          let fslot := sload(_preBytes_slot)
                                                                          // Arrays of 31 bytes or less have an even value in their slot,
                                                                          // while longer arrays have an odd value. The actual length is
                                                                          // the slot divided by two for odd values, and the lowest order
                                                                          // byte divided by two for even values.
                                                                          // If the slot is even, bitwise and the slot with 255 and divide by
                                                                          // two to get the length. If the slot is odd, bitwise and the slot
                                                                          // with -1 and divide by two.
                                                                          let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                                                                          let mlength := mload(_postBytes)
                                                                          let newlength := add(slength, mlength)
                                                                          // slength can contain both the length and contents of the array
                                                                          // if length < 32 bytes so let's prepare for that
                                                                          // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                                                                          switch add(lt(slength, 32), lt(newlength, 32))
                                                                          case 2 {
                                                                              // Since the new array still fits in the slot, we just need to
                                                                              // update the contents of the slot.
                                                                              // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                                                                              sstore(
                                                                                  _preBytes_slot,
                                                                                  // all the modifications to the slot are inside this
                                                                                  // next block
                                                                                  add(
                                                                                      // we can just add to the slot contents because the
                                                                                      // bytes we want to change are the LSBs
                                                                                      fslot,
                                                                                      add(
                                                                                          mul(
                                                                                              div(
                                                                                                  // load the bytes from memory
                                                                                                  mload(add(_postBytes, 0x20)),
                                                                                                  // zero all bytes to the right
                                                                                                  exp(0x100, sub(32, mlength))
                                                                                              ),
                                                                                              // and now shift left the number of bytes to
                                                                                              // leave space for the length in the slot
                                                                                              exp(0x100, sub(32, newlength))
                                                                                          ),
                                                                                          // increase length by the double of the memory
                                                                                          // bytes length
                                                                                          mul(mlength, 2)
                                                                                      )
                                                                                  )
                                                                              )
                                                                          }
                                                                          case 1 {
                                                                              // The stored value fits in the slot, but the combined value
                                                                              // will exceed it.
                                                                              // get the keccak hash to get the contents of the array
                                                                              mstore(0x0, _preBytes_slot)
                                                                              let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                                                                              // save new length
                                                                              sstore(_preBytes_slot, add(mul(newlength, 2), 1))
                                                                              // The contents of the _postBytes array start 32 bytes into
                                                                              // the structure. Our first read should obtain the `submod`
                                                                              // bytes that can fit into the unused space in the last word
                                                                              // of the stored array. To get this, we read 32 bytes starting
                                                                              // from `submod`, so the data we read overlaps with the array
                                                                              // contents by `submod` bytes. Masking the lowest-order
                                                                              // `submod` bytes allows us to add that value directly to the
                                                                              // stored value.
                                                                              let submod := sub(32, slength)
                                                                              let mc := add(_postBytes, submod)
                                                                              let end := add(_postBytes, mlength)
                                                                              let mask := sub(exp(0x100, submod), 1)
                                                                              sstore(
                                                                                  sc,
                                                                                  add(
                                                                                      and(
                                                                                          fslot,
                                                                                          0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                                                                                      ),
                                                                                      and(mload(mc), mask)
                                                                                  )
                                                                              )
                                                                              for {
                                                                                  mc := add(mc, 0x20)
                                                                                  sc := add(sc, 1)
                                                                              } lt(mc, end) {
                                                                                  sc := add(sc, 1)
                                                                                  mc := add(mc, 0x20)
                                                                              } {
                                                                                  sstore(sc, mload(mc))
                                                                              }
                                                                              mask := exp(0x100, sub(mc, end))
                                                                              sstore(sc, mul(div(mload(mc), mask), mask))
                                                                          }
                                                                          default {
                                                                              // get the keccak hash to get the contents of the array
                                                                              mstore(0x0, _preBytes_slot)
                                                                              // Start copying to the last used word of the stored array.
                                                                              let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                                                                              // save new length
                                                                              sstore(_preBytes_slot, add(mul(newlength, 2), 1))
                                                                              // Copy over the first `submod` bytes of the new data as in
                                                                              // case 1 above.
                                                                              let slengthmod := mod(slength, 32)
                                                                              let mlengthmod := mod(mlength, 32)
                                                                              let submod := sub(32, slengthmod)
                                                                              let mc := add(_postBytes, submod)
                                                                              let end := add(_postBytes, mlength)
                                                                              let mask := sub(exp(0x100, submod), 1)
                                                                              sstore(sc, add(sload(sc), and(mload(mc), mask)))
                                                                              
                                                                              for { 
                                                                                  sc := add(sc, 1)
                                                                                  mc := add(mc, 0x20)
                                                                              } lt(mc, end) {
                                                                                  sc := add(sc, 1)
                                                                                  mc := add(mc, 0x20)
                                                                              } {
                                                                                  sstore(sc, mload(mc))
                                                                              }
                                                                              mask := exp(0x100, sub(mc, end))
                                                                              sstore(sc, mul(div(mload(mc), mask), mask))
                                                                          }
                                                                      }
                                                                  }
                                                                  function slice(bytes _bytes, uint _start, uint _length) internal  pure returns (bytes) {
                                                                      require(_bytes.length >= (_start + _length));
                                                                      bytes memory tempBytes;
                                                                      assembly {
                                                                          switch iszero(_length)
                                                                          case 0 {
                                                                              // Get a location of some free memory and store it in tempBytes as
                                                                              // Solidity does for memory variables.
                                                                              tempBytes := mload(0x40)
                                                                              // The first word of the slice result is potentially a partial
                                                                              // word read from the original array. To read it, we calculate
                                                                              // the length of that partial word and start copying that many
                                                                              // bytes into the array. The first word we copy will start with
                                                                              // data we don't care about, but the last `lengthmod` bytes will
                                                                              // land at the beginning of the contents of the new array. When
                                                                              // we're done copying, we overwrite the full first word with
                                                                              // the actual length of the slice.
                                                                              let lengthmod := and(_length, 31)
                                                                              // The multiplication in the next line is necessary
                                                                              // because when slicing multiples of 32 bytes (lengthmod == 0)
                                                                              // the following copy loop was copying the origin's length
                                                                              // and then ending prematurely not copying everything it should.
                                                                              let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                                                                              let end := add(mc, _length)
                                                                              for {
                                                                                  // The multiplication in the next line has the same exact purpose
                                                                                  // as the one above.
                                                                                  let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                                                                              } lt(mc, end) {
                                                                                  mc := add(mc, 0x20)
                                                                                  cc := add(cc, 0x20)
                                                                              } {
                                                                                  mstore(mc, mload(cc))
                                                                              }
                                                                              mstore(tempBytes, _length)
                                                                              //update free-memory pointer
                                                                              //allocating the array padded to 32 bytes like the compiler does now
                                                                              mstore(0x40, and(add(mc, 31), not(31)))
                                                                          }
                                                                          //if we want a zero-length slice let's just return a zero-length array
                                                                          default {
                                                                              tempBytes := mload(0x40)
                                                                              mstore(0x40, add(tempBytes, 0x20))
                                                                          }
                                                                      }
                                                                      return tempBytes;
                                                                  }
                                                                  function toAddress(bytes _bytes, uint _start) internal  pure returns (address) {
                                                                      require(_bytes.length >= (_start + 20));
                                                                      address tempAddress;
                                                                      assembly {
                                                                          tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
                                                                      }
                                                                      return tempAddress;
                                                                  }
                                                                  function toUint8(bytes _bytes, uint _start) internal  pure returns (uint8) {
                                                                      require(_bytes.length >= (_start + 1));
                                                                      uint8 tempUint;
                                                                      assembly {
                                                                          tempUint := mload(add(add(_bytes, 0x1), _start))
                                                                      }
                                                                      return tempUint;
                                                                  }
                                                                  function toUint16(bytes _bytes, uint _start) internal  pure returns (uint16) {
                                                                      require(_bytes.length >= (_start + 2));
                                                                      uint16 tempUint;
                                                                      assembly {
                                                                          tempUint := mload(add(add(_bytes, 0x2), _start))
                                                                      }
                                                                      return tempUint;
                                                                  }
                                                                  function toUint32(bytes _bytes, uint _start) internal  pure returns (uint32) {
                                                                      require(_bytes.length >= (_start + 4));
                                                                      uint32 tempUint;
                                                                      assembly {
                                                                          tempUint := mload(add(add(_bytes, 0x4), _start))
                                                                      }
                                                                      return tempUint;
                                                                  }
                                                                  function toUint(bytes _bytes, uint _start) internal  pure returns (uint256) {
                                                                      require(_bytes.length >= (_start + 32));
                                                                      uint256 tempUint;
                                                                      assembly {
                                                                          tempUint := mload(add(add(_bytes, 0x20), _start))
                                                                      }
                                                                      return tempUint;
                                                                  }
                                                                  function toBytes32(bytes _bytes, uint _start) internal  pure returns (bytes32) {
                                                                      require(_bytes.length >= (_start + 32));
                                                                      bytes32 tempBytes32;
                                                                      assembly {
                                                                          tempBytes32 := mload(add(add(_bytes, 0x20), _start))
                                                                      }
                                                                      return tempBytes32;
                                                                  }
                                                                  function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
                                                                      bool success = true;
                                                                      assembly {
                                                                          let length := mload(_preBytes)
                                                                          // if lengths don't match the arrays are not equal
                                                                          switch eq(length, mload(_postBytes))
                                                                          case 1 {
                                                                              // cb is a circuit breaker in the for loop since there's
                                                                              //  no said feature for inline assembly loops
                                                                              // cb = 1 - don't breaker
                                                                              // cb = 0 - break
                                                                              let cb := 1
                                                                              let mc := add(_preBytes, 0x20)
                                                                              let end := add(mc, length)
                                                                              for {
                                                                                  let cc := add(_postBytes, 0x20)
                                                                              // the next line is the loop condition:
                                                                              // while(uint(mc < end) + cb == 2)
                                                                              } eq(add(lt(mc, end), cb), 2) {
                                                                                  mc := add(mc, 0x20)
                                                                                  cc := add(cc, 0x20)
                                                                              } {
                                                                                  // if any of these checks fails then arrays are not equal
                                                                                  if iszero(eq(mload(mc), mload(cc))) {
                                                                                      // unsuccess:
                                                                                      success := 0
                                                                                      cb := 0
                                                                                  }
                                                                              }
                                                                          }
                                                                          default {
                                                                              // unsuccess:
                                                                              success := 0
                                                                          }
                                                                      }
                                                                      return success;
                                                                  }
                                                                  function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
                                                                      bool success = true;
                                                                      assembly {
                                                                          // we know _preBytes_offset is 0
                                                                          let fslot := sload(_preBytes_slot)
                                                                          // Decode the length of the stored array like in concatStorage().
                                                                          let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                                                                          let mlength := mload(_postBytes)
                                                                          // if lengths don't match the arrays are not equal
                                                                          switch eq(slength, mlength)
                                                                          case 1 {
                                                                              // slength can contain both the length and contents of the array
                                                                              // if length < 32 bytes so let's prepare for that
                                                                              // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                                                                              if iszero(iszero(slength)) {
                                                                                  switch lt(slength, 32)
                                                                                  case 1 {
                                                                                      // blank the last byte which is the length
                                                                                      fslot := mul(div(fslot, 0x100), 0x100)
                                                                                      if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                                                                                          // unsuccess:
                                                                                          success := 0
                                                                                      }
                                                                                  }
                                                                                  default {
                                                                                      // cb is a circuit breaker in the for loop since there's
                                                                                      //  no said feature for inline assembly loops
                                                                                      // cb = 1 - don't breaker
                                                                                      // cb = 0 - break
                                                                                      let cb := 1
                                                                                      // get the keccak hash to get the contents of the array
                                                                                      mstore(0x0, _preBytes_slot)
                                                                                      let sc := keccak256(0x0, 0x20)
                                                                                      let mc := add(_postBytes, 0x20)
                                                                                      let end := add(mc, mlength)
                                                                                      // the next line is the loop condition:
                                                                                      // while(uint(mc < end) + cb == 2)
                                                                                      for {} eq(add(lt(mc, end), cb), 2) {
                                                                                          sc := add(sc, 1)
                                                                                          mc := add(mc, 0x20)
                                                                                      } {
                                                                                          if iszero(eq(sload(sc), mload(mc))) {
                                                                                              // unsuccess:
                                                                                              success := 0
                                                                                              cb := 0
                                                                                          }
                                                                                      }
                                                                                  }
                                                                              }
                                                                          }
                                                                          default {
                                                                              // unsuccess:
                                                                              success := 0
                                                                          }
                                                                      }
                                                                      return success;
                                                                  }
                                                              }
                                                              // SPDX-FileCopyrightText: 2020 Lido <[email protected]>
                                                              // SPDX-License-Identifier: GPL-3.0
                                                              pragma solidity 0.4.24;
                                                              /**
                                                                * @title Liquid staking pool
                                                                *
                                                                * For the high-level description of the pool operation please refer to the paper.
                                                                * Pool manages withdrawal keys and fees. It receives ether submitted by users on the ETH 1 side
                                                                * and stakes it via the deposit_contract.sol contract. It doesn't hold ether on it's balance,
                                                                * only a small portion (buffer) of it.
                                                                * It also mints new tokens for rewards generated at the ETH 2.0 side.
                                                                */
                                                              interface ILido {
                                                                  /**
                                                                    * @notice Stop pool routine operations
                                                                    */
                                                                  function stop() external;
                                                                  /**
                                                                    * @notice Resume pool routine operations
                                                                    */
                                                                  function resume() external;
                                                                  event Stopped();
                                                                  event Resumed();
                                                                  /**
                                                                    * @notice Set fee rate to `_feeBasisPoints` basis points. The fees are accrued when oracles report staking results
                                                                    * @param _feeBasisPoints Fee rate, in basis points
                                                                    */
                                                                  function setFee(uint16 _feeBasisPoints) external;
                                                                  /**
                                                                    * @notice Set fee distribution: `_treasuryFeeBasisPoints` basis points go to the treasury, `_insuranceFeeBasisPoints` basis points go to the insurance fund, `_operatorsFeeBasisPoints` basis points go to node operators. The sum has to be 10 000.
                                                                    */
                                                                  function setFeeDistribution(
                                                                      uint16 _treasuryFeeBasisPoints,
                                                                      uint16 _insuranceFeeBasisPoints,
                                                                      uint16 _operatorsFeeBasisPoints)
                                                                      external;
                                                                  /**
                                                                    * @notice Returns staking rewards fee rate
                                                                    */
                                                                  function getFee() external view returns (uint16 feeBasisPoints);
                                                                  /**
                                                                    * @notice Returns fee distribution proportion
                                                                    */
                                                                  function getFeeDistribution() external view returns (uint16 treasuryFeeBasisPoints, uint16 insuranceFeeBasisPoints,
                                                                                                                       uint16 operatorsFeeBasisPoints);
                                                                  event FeeSet(uint16 feeBasisPoints);
                                                                  event FeeDistributionSet(uint16 treasuryFeeBasisPoints, uint16 insuranceFeeBasisPoints, uint16 operatorsFeeBasisPoints);
                                                                  /**
                                                                    * @notice Set credentials to withdraw ETH on ETH 2.0 side after the phase 2 is launched to `_withdrawalCredentials`
                                                                    * @dev Note that setWithdrawalCredentials discards all unused signing keys as the signatures are invalidated.
                                                                    * @param _withdrawalCredentials hash of withdrawal multisignature key as accepted by
                                                                    *        the deposit_contract.deposit function
                                                                    */
                                                                  function setWithdrawalCredentials(bytes32 _withdrawalCredentials) external;
                                                                  /**
                                                                    * @notice Returns current credentials to withdraw ETH on ETH 2.0 side after the phase 2 is launched
                                                                    */
                                                                  function getWithdrawalCredentials() external view returns (bytes);
                                                                  event WithdrawalCredentialsSet(bytes32 withdrawalCredentials);
                                                                  /**
                                                                    * @notice Ether on the ETH 2.0 side reported by the oracle
                                                                    * @param _epoch Epoch id
                                                                    * @param _eth2balance Balance in wei on the ETH 2.0 side
                                                                    */
                                                                  function pushBeacon(uint256 _epoch, uint256 _eth2balance) external;
                                                                  // User functions
                                                                  /**
                                                                    * @notice Adds eth to the pool
                                                                    * @return StETH Amount of StETH generated
                                                                    */
                                                                  function submit(address _referral) external payable returns (uint256 StETH);
                                                                  // Records a deposit made by a user
                                                                  event Submitted(address indexed sender, uint256 amount, address referral);
                                                                  // The `_amount` of ether was sent to the deposit_contract.deposit function.
                                                                  event Unbuffered(uint256 amount);
                                                                  /**
                                                                    * @notice Issues withdrawal request. Large withdrawals will be processed only after the phase 2 launch.
                                                                    * @param _amount Amount of StETH to burn
                                                                    * @param _pubkeyHash Receiving address
                                                                    */
                                                                  function withdraw(uint256 _amount, bytes32 _pubkeyHash) external;
                                                                  // Requested withdrawal of `etherAmount` to `pubkeyHash` on the ETH 2.0 side, `tokenAmount` burned by `sender`,
                                                                  // `sentFromBuffer` was sent on the current Ethereum side.
                                                                  event Withdrawal(address indexed sender, uint256 tokenAmount, uint256 sentFromBuffer,
                                                                                   bytes32 indexed pubkeyHash, uint256 etherAmount);
                                                                  // Info functions
                                                                  /**
                                                                    * @notice Gets the amount of Ether controlled by the system
                                                                    */
                                                                  function getTotalPooledEther() external view returns (uint256);
                                                                  /**
                                                                    * @notice Gets the amount of Ether temporary buffered on this contract balance
                                                                    */
                                                                  function getBufferedEther() external view returns (uint256);
                                                                  /**
                                                                    * @notice Returns the key values related to Beacon-side
                                                                    * @return depositedValidators - number of deposited validators
                                                                    * @return beaconValidators - number of Lido's validators visible in the Beacon state, reported by oracles
                                                                    * @return beaconBalance - total amount of Beacon-side Ether (sum of all the balances of Lido validators)
                                                                    */
                                                                  function getBeaconStat() external view returns (uint256 depositedValidators, uint256 beaconValidators, uint256 beaconBalance);
                                                              }
                                                              // SPDX-FileCopyrightText: 2020 Lido <[email protected]>
                                                              // SPDX-License-Identifier: GPL-3.0
                                                              pragma solidity 0.4.24;
                                                              /**
                                                                * @title Node Operator registry
                                                                *
                                                                * Node Operator registry manages signing keys and other node operator data.
                                                                * It's also responsible for distributing rewards to node operators.
                                                                */
                                                              interface INodeOperatorsRegistry {
                                                                  /**
                                                                    * @notice Add node operator named `name` with reward address `rewardAddress` and staking limit `stakingLimit` validators
                                                                    * @param _name Human-readable name
                                                                    * @param _rewardAddress Ethereum 1 address which receives stETH rewards for this operator
                                                                    * @param _stakingLimit the maximum number of validators to stake for this operator
                                                                    * @return a unique key of the added operator
                                                                    */
                                                                  function addNodeOperator(string _name, address _rewardAddress, uint64 _stakingLimit) external returns (uint256 id);
                                                                  /**
                                                                    * @notice `_active ? 'Enable' : 'Disable'` the node operator #`_id`
                                                                    */
                                                                  function setNodeOperatorActive(uint256 _id, bool _active) external;
                                                                  /**
                                                                    * @notice Change human-readable name of the node operator #`_id` to `_name`
                                                                    */
                                                                  function setNodeOperatorName(uint256 _id, string _name) external;
                                                                  /**
                                                                    * @notice Change reward address of the node operator #`_id` to `_rewardAddress`
                                                                    */
                                                                  function setNodeOperatorRewardAddress(uint256 _id, address _rewardAddress) external;
                                                                  /**
                                                                    * @notice Set the maximum number of validators to stake for the node operator #`_id` to `_stakingLimit`
                                                                    */
                                                                  function setNodeOperatorStakingLimit(uint256 _id, uint64 _stakingLimit) external;
                                                                  /**
                                                                    * @notice Report `_stoppedIncrement` more stopped validators of the node operator #`_id`
                                                                    */
                                                                  function reportStoppedValidators(uint256 _id, uint64 _stoppedIncrement) external;
                                                                  /**
                                                                    * @notice Remove unused signing keys
                                                                    * @dev Function is used by the pool
                                                                    */
                                                                  function trimUnusedKeys() external;
                                                                  /**
                                                                    * @notice Returns total number of node operators
                                                                    */
                                                                  function getNodeOperatorsCount() external view returns (uint256);
                                                                  /**
                                                                    * @notice Returns number of active node operators
                                                                    */
                                                                  function getActiveNodeOperatorsCount() external view returns (uint256);
                                                                  /**
                                                                    * @notice Returns the n-th node operator
                                                                    * @param _id Node Operator id
                                                                    * @param _fullInfo If true, name will be returned as well
                                                                    */
                                                                  function getNodeOperator(uint256 _id, bool _fullInfo) external view returns (
                                                                      bool active,
                                                                      string name,
                                                                      address rewardAddress,
                                                                      uint64 stakingLimit,
                                                                      uint64 stoppedValidators,
                                                                      uint64 totalSigningKeys,
                                                                      uint64 usedSigningKeys);
                                                                  /**
                                                                    * @notice Returns the rewards distribution proportional to the effective stake for each node operator.
                                                                    * @param _totalRewardShares Total amount of reward shares to distribute.
                                                                    */
                                                                  function getRewardsDistribution(uint256 _totalRewardShares) external view returns (
                                                                      address[] memory recipients,
                                                                      uint256[] memory shares
                                                                  );
                                                                  event NodeOperatorAdded(uint256 id, string name, address rewardAddress, uint64 stakingLimit);
                                                                  event NodeOperatorActiveSet(uint256 indexed id, bool active);
                                                                  event NodeOperatorNameSet(uint256 indexed id, string name);
                                                                  event NodeOperatorRewardAddressSet(uint256 indexed id, address rewardAddress);
                                                                  event NodeOperatorStakingLimitSet(uint256 indexed id, uint64 stakingLimit);
                                                                  event NodeOperatorTotalStoppedValidatorsReported(uint256 indexed id, uint64 totalStopped);
                                                                  /**
                                                                   * @notice Selects and returns at most `_numKeys` signing keys (as well as the corresponding
                                                                   *         signatures) from the set of active keys and marks the selected keys as used.
                                                                   *         May only be called by the pool contract.
                                                                   *
                                                                   * @param _numKeys The number of keys to select. The actual number of selected keys may be less
                                                                   *        due to the lack of active keys.
                                                                   */
                                                                  function assignNextSigningKeys(uint256 _numKeys) external returns (bytes memory pubkeys, bytes memory signatures);
                                                                  /**
                                                                    * @notice Add `_quantity` validator signing keys to the keys of the node operator #`_operator_id`. Concatenated keys are: `_pubkeys`
                                                                    * @dev Along with each key the DAO has to provide a signatures for the
                                                                    *      (pubkey, withdrawal_credentials, 32000000000) message.
                                                                    *      Given that information, the contract'll be able to call
                                                                    *      deposit_contract.deposit on-chain.
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _quantity Number of signing keys provided
                                                                    * @param _pubkeys Several concatenated validator signing keys
                                                                    * @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages
                                                                    */
                                                                  function addSigningKeys(uint256 _operator_id, uint256 _quantity, bytes _pubkeys, bytes _signatures) external;
                                                                  /**
                                                                    * @notice Removes a validator signing key #`_index` from the keys of the node operator #`_operator_id`
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _index Index of the key, starting with 0
                                                                    */
                                                                  function removeSigningKey(uint256 _operator_id, uint256 _index) external;
                                                                  /**
                                                                    * @notice Returns total number of signing keys of the node operator #`_operator_id`
                                                                    */
                                                                  function getTotalSigningKeyCount(uint256 _operator_id) external view returns (uint256);
                                                                  /**
                                                                    * @notice Returns number of usable signing keys of the node operator #`_operator_id`
                                                                    */
                                                                  function getUnusedSigningKeyCount(uint256 _operator_id) external view returns (uint256);
                                                                  /**
                                                                    * @notice Returns n-th signing key of the node operator #`_operator_id`
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _index Index of the key, starting with 0
                                                                    * @return key Key
                                                                    * @return depositSignature Signature needed for a deposit_contract.deposit call
                                                                    * @return used Flag indication if the key was used in the staking
                                                                    */
                                                                  function getSigningKey(uint256 _operator_id, uint256 _index) external view returns
                                                                          (bytes key, bytes depositSignature, bool used);
                                                                  event SigningKeyAdded(uint256 indexed operatorId, bytes pubkey);
                                                                  event SigningKeyRemoved(uint256 indexed operatorId, bytes pubkey);
                                                              }
                                                              // SPDX-FileCopyrightText: 2020 Lido <[email protected]>
                                                              // SPDX-License-Identifier: GPL-3.0
                                                              /* See contracts/COMPILERS.md */
                                                              pragma solidity 0.4.24;
                                                              import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
                                                              import "@aragon/os/contracts/common/UnstructuredStorage.sol";
                                                              import "@aragon/os/contracts/lib/math/SafeMath.sol";
                                                              import "./lib/Pausable.sol";
                                                              /**
                                                               * @title Interest-bearing ERC20-like token for Lido Liquid Stacking protocol.
                                                               *
                                                               * This contract is abstract. To make the contract deployable override the
                                                               * `_getTotalPooledEther` function. `Lido.sol` contract inherits StETH and defines
                                                               * the `_getTotalPooledEther` function.
                                                               *
                                                               * StETH balances are dynamic and represent the holder's share in the total amount
                                                               * of Ether controlled by the protocol. Account shares aren't normalized, so the
                                                               * contract also stores the sum of all shares to calculate each account's token balance
                                                               * which equals to:
                                                               *
                                                               *   shares[account] * _getTotalPooledEther() / _getTotalShares()
                                                               *
                                                               * For example, assume that we have:
                                                               *
                                                               *   _getTotalPooledEther() -> 10 ETH
                                                               *   sharesOf(user1) -> 100
                                                               *   sharesOf(user2) -> 400
                                                               *
                                                               * Therefore:
                                                               *
                                                               *   balanceOf(user1) -> 2 tokens which corresponds 2 ETH
                                                               *   balanceOf(user2) -> 8 tokens which corresponds 8 ETH
                                                               *
                                                               * Since balances of all token holders change when the amount of total pooled Ether
                                                               * changes, this token cannot fully implement ERC20 standard: it only emits `Transfer`
                                                               * events upon explicit transfer between holders. In contrast, when total amount of
                                                               * pooled Ether increases, no `Transfer` events are generated: doing so would require
                                                               * emitting an event for each token holder and thus running an unbounded loop.
                                                               *
                                                               * The token inherits from `Pausable` and uses `whenNotStopped` modifier for methods
                                                               * which change `shares` or `allowances`. `_stop` and `_resume` functions are overriden
                                                               * in `Lido.sol` and might be called by an account with the `PAUSE_ROLE` assigned by the
                                                               * DAO. This is useful for emergency scenarios, e.g. a protocol bug, where one might want
                                                               * to freeze all token transfers and approvals until the emergency is resolved.
                                                               */
                                                              contract StETH is IERC20, Pausable {
                                                                  using SafeMath for uint256;
                                                                  using UnstructuredStorage for bytes32;
                                                                  /**
                                                                   * @dev StETH balances are dynamic and are calculated based on the accounts' shares
                                                                   * and the total amount of Ether controlled by the protocol. Account shares aren't
                                                                   * normalized, so the contract also stores the sum of all shares to calculate
                                                                   * each account's token balance which equals to:
                                                                   *
                                                                   *   shares[account] * _getTotalPooledEther() / _getTotalShares()
                                                                  */
                                                                  mapping (address => uint256) private shares;
                                                                  /**
                                                                   * @dev Allowances are nominated in tokens, not token shares.
                                                                   */
                                                                  mapping (address => mapping (address => uint256)) private allowances;
                                                                  /**
                                                                   * @dev Storage position used for holding the total amount of shares in existence.
                                                                   *
                                                                   * The Lido protocol is built on top of Aragon and uses the Unstructured Storage pattern
                                                                   * for value types:
                                                                   *
                                                                   * https://blog.openzeppelin.com/upgradeability-using-unstructured-storage
                                                                   * https://blog.8bitzen.com/posts/20-02-2020-understanding-how-solidity-upgradeable-unstructured-proxies-work
                                                                   *
                                                                   * For reference types, conventional storage variables are used since it's non-trivial
                                                                   * and error-prone to implement reference-type unstructured storage using Solidity v0.4;
                                                                   * see https://github.com/lidofinance/lido-dao/issues/181#issuecomment-736098834
                                                                   */
                                                                  bytes32 internal constant TOTAL_SHARES_POSITION = keccak256("lido.StETH.totalShares");
                                                                  /**
                                                                   * @return the name of the token.
                                                                   */
                                                                  function name() public pure returns (string) {
                                                                      return "Liquid staked Ether 2.0";
                                                                  }
                                                                  /**
                                                                   * @return the symbol of the token, usually a shorter version of the
                                                                   * name.
                                                                   */
                                                                  function symbol() public pure returns (string) {
                                                                      return "stETH";
                                                                  }
                                                                  /**
                                                                   * @return the number of decimals for getting user representation of a token amount.
                                                                   */
                                                                  function decimals() public pure returns (uint8) {
                                                                      return 18;
                                                                  }
                                                                  /**
                                                                   * @return the amount of tokens in existence.
                                                                   *
                                                                   * @dev Always equals to `_getTotalPooledEther()` since token amount
                                                                   * is pegged to the total amount of Ether controlled by the protocol.
                                                                   */
                                                                  function totalSupply() public view returns (uint256) {
                                                                      return _getTotalPooledEther();
                                                                  }
                                                                  /**
                                                                   * @return the entire amount of Ether controlled by the protocol.
                                                                   *
                                                                   * @dev The sum of all ETH balances in the protocol, equals to the total supply of stETH.
                                                                   */
                                                                  function getTotalPooledEther() public view returns (uint256) {
                                                                      return _getTotalPooledEther();
                                                                  }
                                                                  /**
                                                                   * @return the amount of tokens owned by the `_account`.
                                                                   *
                                                                   * @dev Balances are dynamic and equal the `_account`'s share in the amount of the
                                                                   * total Ether controlled by the protocol. See `sharesOf`.
                                                                   */
                                                                  function balanceOf(address _account) public view returns (uint256) {
                                                                      return getPooledEthByShares(_sharesOf(_account));
                                                                  }
                                                                  /**
                                                                   * @notice Moves `_amount` tokens from the caller's account to the `_recipient` account.
                                                                   *
                                                                   * @return a boolean value indicating whether the operation succeeded.
                                                                   * Emits a `Transfer` event.
                                                                   *
                                                                   * Requirements:
                                                                   *
                                                                   * - `_recipient` cannot be the zero address.
                                                                   * - the caller must have a balance of at least `_amount`.
                                                                   * - the contract must not be paused.
                                                                   *
                                                                   * @dev The `_amount` argument is the amount of tokens, not shares.
                                                                   */
                                                                  function transfer(address _recipient, uint256 _amount) public returns (bool) {
                                                                      _transfer(msg.sender, _recipient, _amount);
                                                                      return true;
                                                                  }
                                                                  /**
                                                                   * @return the remaining number of tokens that `_spender` is allowed to spend
                                                                   * on behalf of `_owner` through `transferFrom`. This is zero by default.
                                                                   *
                                                                   * @dev This value changes when `approve` or `transferFrom` is called.
                                                                   */
                                                                  function allowance(address _owner, address _spender) public view returns (uint256) {
                                                                      return allowances[_owner][_spender];
                                                                  }
                                                                  /**
                                                                   * @notice Sets `_amount` as the allowance of `_spender` over the caller's tokens.
                                                                   *
                                                                   * @return a boolean value indicating whether the operation succeeded.
                                                                   * Emits an `Approval` event.
                                                                   *
                                                                   * Requirements:
                                                                   *
                                                                   * - `_spender` cannot be the zero address.
                                                                   * - the contract must not be paused.
                                                                   *
                                                                   * @dev The `_amount` argument is the amount of tokens, not shares.
                                                                   */
                                                                  function approve(address _spender, uint256 _amount) public returns (bool) {
                                                                      _approve(msg.sender, _spender, _amount);
                                                                      return true;
                                                                  }
                                                                  /**
                                                                   * @notice Moves `_amount` tokens from `_sender` to `_recipient` using the
                                                                   * allowance mechanism. `_amount` is then deducted from the caller's
                                                                   * allowance.
                                                                   *
                                                                   * @return a boolean value indicating whether the operation succeeded.
                                                                   *
                                                                   * Emits a `Transfer` event.
                                                                   * Emits an `Approval` event indicating the updated allowance.
                                                                   *
                                                                   * Requirements:
                                                                   *
                                                                   * - `_sender` and `_recipient` cannot be the zero addresses.
                                                                   * - `_sender` must have a balance of at least `_amount`.
                                                                   * - the caller must have allowance for `_sender`'s tokens of at least `_amount`.
                                                                   * - the contract must not be paused.
                                                                   *
                                                                   * @dev The `_amount` argument is the amount of tokens, not shares.
                                                                   */
                                                                  function transferFrom(address _sender, address _recipient, uint256 _amount) public returns (bool) {
                                                                      uint256 currentAllowance = allowances[_sender][msg.sender];
                                                                      require(currentAllowance >= _amount, "TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE");
                                                                      _transfer(_sender, _recipient, _amount);
                                                                      _approve(_sender, msg.sender, currentAllowance.sub(_amount));
                                                                      return true;
                                                                  }
                                                                  /**
                                                                   * @notice Atomically increases the allowance granted to `_spender` by the caller by `_addedValue`.
                                                                   *
                                                                   * This is an alternative to `approve` that can be used as a mitigation for
                                                                   * problems described in:
                                                                   * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42
                                                                   * Emits an `Approval` event indicating the updated allowance.
                                                                   *
                                                                   * Requirements:
                                                                   *
                                                                   * - `_spender` cannot be the the zero address.
                                                                   * - the contract must not be paused.
                                                                   */
                                                                  function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool) {
                                                                      _approve(msg.sender, _spender, allowances[msg.sender][_spender].add(_addedValue));
                                                                      return true;
                                                                  }
                                                                  /**
                                                                   * @notice Atomically decreases the allowance granted to `_spender` by the caller by `_subtractedValue`.
                                                                   *
                                                                   * This is an alternative to `approve` that can be used as a mitigation for
                                                                   * problems described in:
                                                                   * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42
                                                                   * Emits an `Approval` event indicating the updated allowance.
                                                                   *
                                                                   * Requirements:
                                                                   *
                                                                   * - `_spender` cannot be the zero address.
                                                                   * - `_spender` must have allowance for the caller of at least `_subtractedValue`.
                                                                   * - the contract must not be paused.
                                                                   */
                                                                  function decreaseAllowance(address _spender, uint256 _subtractedValue) public returns (bool) {
                                                                      uint256 currentAllowance = allowances[msg.sender][_spender];
                                                                      require(currentAllowance >= _subtractedValue, "DECREASED_ALLOWANCE_BELOW_ZERO");
                                                                      _approve(msg.sender, _spender, currentAllowance.sub(_subtractedValue));
                                                                      return true;
                                                                  }
                                                                  /**
                                                                   * @return the total amount of shares in existence.
                                                                   *
                                                                   * @dev The sum of all accounts' shares can be an arbitrary number, therefore
                                                                   * it is necessary to store it in order to calculate each account's relative share.
                                                                   */
                                                                  function getTotalShares() public view returns (uint256) {
                                                                      return _getTotalShares();
                                                                  }
                                                                  /**
                                                                   * @return the amount of shares owned by `_account`.
                                                                   */
                                                                  function sharesOf(address _account) public view returns (uint256) {
                                                                      return _sharesOf(_account);
                                                                  }
                                                                  /**
                                                                   * @return the amount of shares that corresponds to `_ethAmount` protocol-controlled Ether.
                                                                   */
                                                                  function getSharesByPooledEth(uint256 _ethAmount) public view returns (uint256) {
                                                                      uint256 totalPooledEther = _getTotalPooledEther();
                                                                      if (totalPooledEther == 0) {
                                                                          return 0;
                                                                      } else {
                                                                          return _ethAmount
                                                                              .mul(_getTotalShares())
                                                                              .div(totalPooledEther);
                                                                      }
                                                                  }
                                                                  /**
                                                                   * @return the amount of Ether that corresponds to `_sharesAmount` token shares.
                                                                   */
                                                                  function getPooledEthByShares(uint256 _sharesAmount) public view returns (uint256) {
                                                                      uint256 totalShares = _getTotalShares();
                                                                      if (totalShares == 0) {
                                                                          return 0;
                                                                      } else {
                                                                          return _sharesAmount
                                                                              .mul(_getTotalPooledEther())
                                                                              .div(totalShares);
                                                                      }
                                                                  }
                                                                  /**
                                                                   * @return the total amount (in wei) of Ether controlled by the protocol.
                                                                   * @dev This is used for calaulating tokens from shares and vice versa.
                                                                   * @dev This function is required to be implemented in a derived contract.
                                                                   */
                                                                  function _getTotalPooledEther() internal view returns (uint256);
                                                                  /**
                                                                   * @notice Moves `_amount` tokens from `_sender` to `_recipient`.
                                                                   * Emits a `Transfer` event.
                                                                   */
                                                                  function _transfer(address _sender, address _recipient, uint256 _amount) internal {
                                                                      uint256 _sharesToTransfer = getSharesByPooledEth(_amount);
                                                                      _transferShares(_sender, _recipient, _sharesToTransfer);
                                                                      emit Transfer(_sender, _recipient, _amount);
                                                                  }
                                                                  /**
                                                                   * @notice Sets `_amount` as the allowance of `_spender` over the `_owner` s tokens.
                                                                   *
                                                                   * Emits an `Approval` event.
                                                                   *
                                                                   * Requirements:
                                                                   *
                                                                   * - `_owner` cannot be the zero address.
                                                                   * - `_spender` cannot be the zero address.
                                                                   * - the contract must not be paused.
                                                                   */
                                                                  function _approve(address _owner, address _spender, uint256 _amount) internal whenNotStopped {
                                                                      require(_owner != address(0), "APPROVE_FROM_ZERO_ADDRESS");
                                                                      require(_spender != address(0), "APPROVE_TO_ZERO_ADDRESS");
                                                                      allowances[_owner][_spender] = _amount;
                                                                      emit Approval(_owner, _spender, _amount);
                                                                  }
                                                                  /**
                                                                   * @return the total amount of shares in existence.
                                                                   */
                                                                  function _getTotalShares() internal view returns (uint256) {
                                                                      return TOTAL_SHARES_POSITION.getStorageUint256();
                                                                  }
                                                                  /**
                                                                   * @return the amount of shares owned by `_account`.
                                                                   */
                                                                  function _sharesOf(address _account) internal view returns (uint256) {
                                                                      return shares[_account];
                                                                  }
                                                                  /**
                                                                   * @notice Moves `_sharesAmount` shares from `_sender` to `_recipient`.
                                                                   *
                                                                   * Requirements:
                                                                   *
                                                                   * - `_sender` cannot be the zero address.
                                                                   * - `_recipient` cannot be the zero address.
                                                                   * - `_sender` must hold at least `_sharesAmount` shares.
                                                                   * - the contract must not be paused.
                                                                   */
                                                                  function _transferShares(address _sender, address _recipient, uint256 _sharesAmount) internal whenNotStopped {
                                                                      require(_sender != address(0), "TRANSFER_FROM_THE_ZERO_ADDRESS");
                                                                      require(_recipient != address(0), "TRANSFER_TO_THE_ZERO_ADDRESS");
                                                                      uint256 currentSenderShares = shares[_sender];
                                                                      require(_sharesAmount <= currentSenderShares, "TRANSFER_AMOUNT_EXCEEDS_BALANCE");
                                                                      shares[_sender] = currentSenderShares.sub(_sharesAmount);
                                                                      shares[_recipient] = shares[_recipient].add(_sharesAmount);
                                                                  }
                                                                  /**
                                                                   * @notice Creates `_sharesAmount` shares and assigns them to `_recipient`, increasing the total amount of shares.
                                                                   * @dev This doesn't increase the token total supply.
                                                                   *
                                                                   * Requirements:
                                                                   *
                                                                   * - `_recipient` cannot be the zero address.
                                                                   * - the contract must not be paused.
                                                                   */
                                                                  function _mintShares(address _recipient, uint256 _sharesAmount) internal whenNotStopped returns (uint256 newTotalShares) {
                                                                      require(_recipient != address(0), "MINT_TO_THE_ZERO_ADDRESS");
                                                                      newTotalShares = _getTotalShares().add(_sharesAmount);
                                                                      TOTAL_SHARES_POSITION.setStorageUint256(newTotalShares);
                                                                      shares[_recipient] = shares[_recipient].add(_sharesAmount);
                                                                      // Notice: we're not emitting a Transfer event from the zero address here since shares mint
                                                                      // works by taking the amount of tokens corresponding to the minted shares from all other
                                                                      // token holders, proportionally to their share. The total supply of the token doesn't change
                                                                      // as the result. This is equivalent to performing a send from each other token holder's
                                                                      // address to `address`, but we cannot reflect this as it would require sending an unbounded
                                                                      // number of events.
                                                                  }
                                                                  /**
                                                                   * @notice Destroys `_sharesAmount` shares from `_account`'s holdings, decreasing the total amount of shares.
                                                                   * @dev This doesn't decrease the token total supply.
                                                                   *
                                                                   * Requirements:
                                                                   *
                                                                   * - `_account` cannot be the zero address.
                                                                   * - `_account` must hold at least `_sharesAmount` shares.
                                                                   * - the contract must not be paused.
                                                                   */
                                                                  function _burnShares(address _account, uint256 _sharesAmount) internal whenNotStopped returns (uint256 newTotalShares) {
                                                                      require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS");
                                                                      uint256 accountShares = shares[_account];
                                                                      require(_sharesAmount <= accountShares, "BURN_AMOUNT_EXCEEDS_BALANCE");
                                                                      newTotalShares = _getTotalShares().sub(_sharesAmount);
                                                                      TOTAL_SHARES_POSITION.setStorageUint256(newTotalShares);
                                                                      shares[_account] = accountShares.sub(_sharesAmount);
                                                                      // Notice: we're not emitting a Transfer event to the zero address here since shares burn
                                                                      // works by redistributing the amount of tokens corresponding to the burned shares between
                                                                      // all other token holders. The total supply of the token doesn't change as the result.
                                                                      // This is equivalent to performing a send from `address` to each other token holder address,
                                                                      // but we cannot reflect this as it would require sending an unbounded number of events.
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "../common/UnstructuredStorage.sol";
                                                              import "../kernel/IKernel.sol";
                                                              contract AppStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
                                                                  bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
                                                                  */
                                                                  bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
                                                                  bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
                                                                  function kernel() public view returns (IKernel) {
                                                                      return IKernel(KERNEL_POSITION.getStorageAddress());
                                                                  }
                                                                  function appId() public view returns (bytes32) {
                                                                      return APP_ID_POSITION.getStorageBytes32();
                                                                  }
                                                                  function setKernel(IKernel _kernel) internal {
                                                                      KERNEL_POSITION.setStorageAddress(address(_kernel));
                                                                  }
                                                                  function setAppId(bytes32 _appId) internal {
                                                                      APP_ID_POSITION.setStorageBytes32(_appId);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              contract ACLSyntaxSugar {
                                                                  function arr() internal pure returns (uint256[]) {
                                                                      return new uint256[](0);
                                                                  }
                                                                  function arr(bytes32 _a) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a));
                                                                  }
                                                                  function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                                  function arr(address _a) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a));
                                                                  }
                                                                  function arr(address _a, address _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                                  function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), _b, _c);
                                                                  }
                                                                  function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), _b, _c, _d);
                                                                  }
                                                                  function arr(address _a, uint256 _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                                  function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), _c, _d, _e);
                                                                  }
                                                                  function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), uint256(_c));
                                                                  }
                                                                  function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), uint256(_c));
                                                                  }
                                                                  function arr(uint256 _a) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](1);
                                                                      r[0] = _a;
                                                                  }
                                                                  function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](2);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                  }
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](3);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                  }
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](4);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                      r[3] = _d;
                                                                  }
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](5);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                      r[3] = _d;
                                                                      r[4] = _e;
                                                                  }
                                                              }
                                                              contract ACLHelpers {
                                                                  function decodeParamOp(uint256 _x) internal pure returns (uint8 b) {
                                                                      return uint8(_x >> (8 * 30));
                                                                  }
                                                                  function decodeParamId(uint256 _x) internal pure returns (uint8 b) {
                                                                      return uint8(_x >> (8 * 31));
                                                                  }
                                                                  function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) {
                                                                      a = uint32(_x);
                                                                      b = uint32(_x >> (8 * 4));
                                                                      c = uint32(_x >> (8 * 8));
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./Petrifiable.sol";
                                                              contract Autopetrified is Petrifiable {
                                                                  constructor() public {
                                                                      // Immediately petrify base (non-proxy) instances of inherited contracts on deploy.
                                                                      // This renders them uninitializable (and unusable without a proxy).
                                                                      petrify();
                                                                  }
                                                              }
                                                              pragma solidity ^0.4.24;
                                                              library ConversionHelpers {
                                                                  string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH";
                                                                  function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) {
                                                                      // Force cast the uint256[] into a bytes array, by overwriting its length
                                                                      // Note that the bytes array doesn't need to be initialized as we immediately overwrite it
                                                                      // with the input and a new length. The input becomes invalid from this point forward.
                                                                      uint256 byteLength = _input.length * 32;
                                                                      assembly {
                                                                          output := _input
                                                                          mstore(output, byteLength)
                                                                      }
                                                                  }
                                                                  function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) {
                                                                      // Force cast the bytes array into a uint256[], by overwriting its length
                                                                      // Note that the uint256[] doesn't need to be initialized as we immediately overwrite it
                                                                      // with the input and a new length. The input becomes invalid from this point forward.
                                                                      uint256 intsLength = _input.length / 32;
                                                                      require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH);
                                                                      assembly {
                                                                          output := _input
                                                                          mstore(output, intsLength)
                                                                      }
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "../common/UnstructuredStorage.sol";
                                                              contract ReentrancyGuard {
                                                                  using UnstructuredStorage for bytes32;
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant REENTRANCY_MUTEX_POSITION = keccak256("aragonOS.reentrancyGuard.mutex");
                                                                  */
                                                                  bytes32 private constant REENTRANCY_MUTEX_POSITION = 0xe855346402235fdd185c890e68d2c4ecad599b88587635ee285bce2fda58dacb;
                                                                  string private constant ERROR_REENTRANT = "REENTRANCY_REENTRANT_CALL";
                                                                  modifier nonReentrant() {
                                                                      // Ensure mutex is unlocked
                                                                      require(!REENTRANCY_MUTEX_POSITION.getStorageBool(), ERROR_REENTRANT);
                                                                      // Lock mutex before function call
                                                                      REENTRANCY_MUTEX_POSITION.setStorageBool(true);
                                                                      // Perform function call
                                                                      _;
                                                                      // Unlock mutex after function call
                                                                      REENTRANCY_MUTEX_POSITION.setStorageBool(false);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "../lib/token/ERC20.sol";
                                                              import "./EtherTokenConstant.sol";
                                                              import "./IsContract.sol";
                                                              import "./IVaultRecoverable.sol";
                                                              import "./SafeERC20.sol";
                                                              contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract {
                                                                  using SafeERC20 for ERC20;
                                                                  string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED";
                                                                  string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT";
                                                                  string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED";
                                                                  /**
                                                                   * @notice Send funds to recovery Vault. This contract should never receive funds,
                                                                   *         but in case it does, this function allows one to recover them.
                                                                   * @param _token Token balance to be sent to recovery vault.
                                                                   */
                                                                  function transferToVault(address _token) external {
                                                                      require(allowRecoverability(_token), ERROR_DISALLOWED);
                                                                      address vault = getRecoveryVault();
                                                                      require(isContract(vault), ERROR_VAULT_NOT_CONTRACT);
                                                                      uint256 balance;
                                                                      if (_token == ETH) {
                                                                          balance = address(this).balance;
                                                                          vault.transfer(balance);
                                                                      } else {
                                                                          ERC20 token = ERC20(_token);
                                                                          balance = token.staticBalanceOf(this);
                                                                          require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED);
                                                                      }
                                                                      emit RecoverToVault(vault, _token, balance);
                                                                  }
                                                                  /**
                                                                  * @dev By default deriving from AragonApp makes it recoverable
                                                                  * @param token Token address that would be recovered
                                                                  * @return bool whether the app allows the recovery
                                                                  */
                                                                  function allowRecoverability(address token) public view returns (bool) {
                                                                      return true;
                                                                  }
                                                                  // Cast non-implemented interface to be public so we can use it internally
                                                                  function getRecoveryVault() public view returns (address);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./IEVMScriptExecutor.sol";
                                                              import "./IEVMScriptRegistry.sol";
                                                              import "../apps/AppStorage.sol";
                                                              import "../kernel/KernelConstants.sol";
                                                              import "../common/Initializable.sol";
                                                              contract EVMScriptRunner is AppStorage, Initializable, EVMScriptRegistryConstants, KernelNamespaceConstants {
                                                                  string private constant ERROR_EXECUTOR_UNAVAILABLE = "EVMRUN_EXECUTOR_UNAVAILABLE";
                                                                  string private constant ERROR_PROTECTED_STATE_MODIFIED = "EVMRUN_PROTECTED_STATE_MODIFIED";
                                                                  /* This is manually crafted in assembly
                                                                  string private constant ERROR_EXECUTOR_INVALID_RETURN = "EVMRUN_EXECUTOR_INVALID_RETURN";
                                                                  */
                                                                  event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData);
                                                                  function getEVMScriptExecutor(bytes _script) public view returns (IEVMScriptExecutor) {
                                                                      return IEVMScriptExecutor(getEVMScriptRegistry().getScriptExecutor(_script));
                                                                  }
                                                                  function getEVMScriptRegistry() public view returns (IEVMScriptRegistry) {
                                                                      address registryAddr = kernel().getApp(KERNEL_APP_ADDR_NAMESPACE, EVMSCRIPT_REGISTRY_APP_ID);
                                                                      return IEVMScriptRegistry(registryAddr);
                                                                  }
                                                                  function runScript(bytes _script, bytes _input, address[] _blacklist)
                                                                      internal
                                                                      isInitialized
                                                                      protectState
                                                                      returns (bytes)
                                                                  {
                                                                      IEVMScriptExecutor executor = getEVMScriptExecutor(_script);
                                                                      require(address(executor) != address(0), ERROR_EXECUTOR_UNAVAILABLE);
                                                                      bytes4 sig = executor.execScript.selector;
                                                                      bytes memory data = abi.encodeWithSelector(sig, _script, _input, _blacklist);
                                                                      bytes memory output;
                                                                      assembly {
                                                                          let success := delegatecall(
                                                                              gas,                // forward all gas
                                                                              executor,           // address
                                                                              add(data, 0x20),    // calldata start
                                                                              mload(data),        // calldata length
                                                                              0,                  // don't write output (we'll handle this ourselves)
                                                                              0                   // don't write output
                                                                          )
                                                                          output := mload(0x40) // free mem ptr get
                                                                          switch success
                                                                          case 0 {
                                                                              // If the call errored, forward its full error data
                                                                              returndatacopy(output, 0, returndatasize)
                                                                              revert(output, returndatasize)
                                                                          }
                                                                          default {
                                                                              switch gt(returndatasize, 0x3f)
                                                                              case 0 {
                                                                                  // Need at least 0x40 bytes returned for properly ABI-encoded bytes values,
                                                                                  // revert with "EVMRUN_EXECUTOR_INVALID_RETURN"
                                                                                  // See remix: doing a `revert("EVMRUN_EXECUTOR_INVALID_RETURN")` always results in
                                                                                  // this memory layout
                                                                                  mstore(output, 0x08c379a000000000000000000000000000000000000000000000000000000000)         // error identifier
                                                                                  mstore(add(output, 0x04), 0x0000000000000000000000000000000000000000000000000000000000000020) // starting offset
                                                                                  mstore(add(output, 0x24), 0x000000000000000000000000000000000000000000000000000000000000001e) // reason length
                                                                                  mstore(add(output, 0x44), 0x45564d52554e5f4558454355544f525f494e56414c49445f52455455524e0000) // reason
                                                                                  revert(output, 100) // 100 = 4 + 3 * 32 (error identifier + 3 words for the ABI encoded error)
                                                                              }
                                                                              default {
                                                                                  // Copy result
                                                                                  //
                                                                                  // Needs to perform an ABI decode for the expected `bytes` return type of
                                                                                  // `executor.execScript()` as solidity will automatically ABI encode the returned bytes as:
                                                                                  //    [ position of the first dynamic length return value = 0x20 (32 bytes) ]
                                                                                  //    [ output length (32 bytes) ]
                                                                                  //    [ output content (N bytes) ]
                                                                                  //
                                                                                  // Perform the ABI decode by ignoring the first 32 bytes of the return data
                                                                                  let copysize := sub(returndatasize, 0x20)
                                                                                  returndatacopy(output, 0x20, copysize)
                                                                                  mstore(0x40, add(output, copysize)) // free mem ptr set
                                                                              }
                                                                          }
                                                                      }
                                                                      emit ScriptResult(address(executor), _script, _input, output);
                                                                      return output;
                                                                  }
                                                                  modifier protectState {
                                                                      address preKernel = address(kernel());
                                                                      bytes32 preAppId = appId();
                                                                      _; // exec
                                                                      require(address(kernel()) == preKernel, ERROR_PROTECTED_STATE_MODIFIED);
                                                                      require(appId() == preAppId, ERROR_PROTECTED_STATE_MODIFIED);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              library UnstructuredStorage {
                                                                  function getStorageBool(bytes32 position) internal view returns (bool data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                                  function getStorageAddress(bytes32 position) internal view returns (address data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                                  function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                                  function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                                  function setStorageBool(bytes32 position, bool data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                                  function setStorageAddress(bytes32 position, address data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                                  function setStorageBytes32(bytes32 position, bytes32 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                                  function setStorageUint256(bytes32 position, uint256 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "../acl/IACL.sol";
                                                              import "../common/IVaultRecoverable.sol";
                                                              interface IKernelEvents {
                                                                  event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                                                              }
                                                              // This should be an interface, but interfaces can't inherit yet :(
                                                              contract IKernel is IKernelEvents, IVaultRecoverable {
                                                                  function acl() public view returns (IACL);
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                                  function setApp(bytes32 namespace, bytes32 appId, address app) public;
                                                                  function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              interface IACL {
                                                                  function initialize(address permissionsCreator) external;
                                                                  // TODO: this should be external
                                                                  // See https://github.com/ethereum/solidity/issues/4832
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              interface IVaultRecoverable {
                                                                  event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                                                                  function transferToVault(address token) external;
                                                                  function allowRecoverability(address token) external view returns (bool);
                                                                  function getRecoveryVault() external view returns (address);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./Initializable.sol";
                                                              contract Petrifiable is Initializable {
                                                                  // Use block UINT256_MAX (which should be never) as the initializable date
                                                                  uint256 internal constant PETRIFIED_BLOCK = uint256(-1);
                                                                  function isPetrified() public view returns (bool) {
                                                                      return getInitializationBlock() == PETRIFIED_BLOCK;
                                                                  }
                                                                  /**
                                                                  * @dev Function to be called by top level contract to prevent being initialized.
                                                                  *      Useful for freezing base contracts when they're used behind proxies.
                                                                  */
                                                                  function petrify() internal onlyInit {
                                                                      initializedAt(PETRIFIED_BLOCK);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./TimeHelpers.sol";
                                                              import "./UnstructuredStorage.sol";
                                                              contract Initializable is TimeHelpers {
                                                                  using UnstructuredStorage for bytes32;
                                                                  // keccak256("aragonOS.initializable.initializationBlock")
                                                                  bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e;
                                                                  string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED";
                                                                  string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED";
                                                                  modifier onlyInit {
                                                                      require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED);
                                                                      _;
                                                                  }
                                                                  modifier isInitialized {
                                                                      require(hasInitialized(), ERROR_NOT_INITIALIZED);
                                                                      _;
                                                                  }
                                                                  /**
                                                                  * @return Block number in which the contract was initialized
                                                                  */
                                                                  function getInitializationBlock() public view returns (uint256) {
                                                                      return INITIALIZATION_BLOCK_POSITION.getStorageUint256();
                                                                  }
                                                                  /**
                                                                  * @return Whether the contract has been initialized by the time of the current block
                                                                  */
                                                                  function hasInitialized() public view returns (bool) {
                                                                      uint256 initializationBlock = getInitializationBlock();
                                                                      return initializationBlock != 0 && getBlockNumber() >= initializationBlock;
                                                                  }
                                                                  /**
                                                                  * @dev Function to be called by top level contract after initialization has finished.
                                                                  */
                                                                  function initialized() internal onlyInit {
                                                                      INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber());
                                                                  }
                                                                  /**
                                                                  * @dev Function to be called by top level contract after initialization to enable the contract
                                                                  *      at a future block number rather than immediately.
                                                                  */
                                                                  function initializedAt(uint256 _blockNumber) internal onlyInit {
                                                                      INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./Uint256Helpers.sol";
                                                              contract TimeHelpers {
                                                                  using Uint256Helpers for uint256;
                                                                  /**
                                                                  * @dev Returns the current block number.
                                                                  *      Using a function rather than `block.number` allows us to easily mock the block number in
                                                                  *      tests.
                                                                  */
                                                                  function getBlockNumber() internal view returns (uint256) {
                                                                      return block.number;
                                                                  }
                                                                  /**
                                                                  * @dev Returns the current block number, converted to uint64.
                                                                  *      Using a function rather than `block.number` allows us to easily mock the block number in
                                                                  *      tests.
                                                                  */
                                                                  function getBlockNumber64() internal view returns (uint64) {
                                                                      return getBlockNumber().toUint64();
                                                                  }
                                                                  /**
                                                                  * @dev Returns the current timestamp.
                                                                  *      Using a function rather than `block.timestamp` allows us to easily mock it in
                                                                  *      tests.
                                                                  */
                                                                  function getTimestamp() internal view returns (uint256) {
                                                                      return block.timestamp; // solium-disable-line security/no-block-members
                                                                  }
                                                                  /**
                                                                  * @dev Returns the current timestamp, converted to uint64.
                                                                  *      Using a function rather than `block.timestamp` allows us to easily mock it in
                                                                  *      tests.
                                                                  */
                                                                  function getTimestamp64() internal view returns (uint64) {
                                                                      return getTimestamp().toUint64();
                                                                  }
                                                              }
                                                              pragma solidity ^0.4.24;
                                                              library Uint256Helpers {
                                                                  uint256 private constant MAX_UINT64 = uint64(-1);
                                                                  string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG";
                                                                  function toUint64(uint256 a) internal pure returns (uint64) {
                                                                      require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG);
                                                                      return uint64(a);
                                                                  }
                                                              }
                                                              // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol
                                                              pragma solidity ^0.4.24;
                                                              /**
                                                               * @title ERC20 interface
                                                               * @dev see https://github.com/ethereum/EIPs/issues/20
                                                               */
                                                              contract ERC20 {
                                                                  function totalSupply() public view returns (uint256);
                                                                  function balanceOf(address _who) public view returns (uint256);
                                                                  function allowance(address _owner, address _spender)
                                                                      public view returns (uint256);
                                                                  function transfer(address _to, uint256 _value) public returns (bool);
                                                                  function approve(address _spender, uint256 _value)
                                                                      public returns (bool);
                                                                  function transferFrom(address _from, address _to, uint256 _value)
                                                                      public returns (bool);
                                                                  event Transfer(
                                                                      address indexed from,
                                                                      address indexed to,
                                                                      uint256 value
                                                                  );
                                                                  event Approval(
                                                                      address indexed owner,
                                                                      address indexed spender,
                                                                      uint256 value
                                                                  );
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              // aragonOS and aragon-apps rely on address(0) to denote native ETH, in
                                                              // contracts where both tokens and ETH are accepted
                                                              contract EtherTokenConstant {
                                                                  address internal constant ETH = address(0);
                                                              }
                                                              // Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol)
                                                              // and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143)
                                                              pragma solidity ^0.4.24;
                                                              import "../lib/token/ERC20.sol";
                                                              library SafeERC20 {
                                                                  // Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`:
                                                                  // https://github.com/ethereum/solidity/issues/3544
                                                                  bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb;
                                                                  string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED";
                                                                  string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED";
                                                                  function invokeAndCheckSuccess(address _addr, bytes memory _calldata)
                                                                      private
                                                                      returns (bool)
                                                                  {
                                                                      bool ret;
                                                                      assembly {
                                                                          let ptr := mload(0x40)    // free memory pointer
                                                                          let success := call(
                                                                              gas,                  // forward all gas
                                                                              _addr,                // address
                                                                              0,                    // no value
                                                                              add(_calldata, 0x20), // calldata start
                                                                              mload(_calldata),     // calldata length
                                                                              ptr,                  // write output over free memory
                                                                              0x20                  // uint256 return
                                                                          )
                                                                          if gt(success, 0) {
                                                                              // Check number of bytes returned from last function call
                                                                              switch returndatasize
                                                                              // No bytes returned: assume success
                                                                              case 0 {
                                                                                  ret := 1
                                                                              }
                                                                              // 32 bytes returned: check if non-zero
                                                                              case 0x20 {
                                                                                  // Only return success if returned data was true
                                                                                  // Already have output in ptr
                                                                                  ret := eq(mload(ptr), 1)
                                                                              }
                                                                              // Not sure what was returned: don't mark as success
                                                                              default { }
                                                                          }
                                                                      }
                                                                      return ret;
                                                                  }
                                                                  function staticInvoke(address _addr, bytes memory _calldata)
                                                                      private
                                                                      view
                                                                      returns (bool, uint256)
                                                                  {
                                                                      bool success;
                                                                      uint256 ret;
                                                                      assembly {
                                                                          let ptr := mload(0x40)    // free memory pointer
                                                                          success := staticcall(
                                                                              gas,                  // forward all gas
                                                                              _addr,                // address
                                                                              add(_calldata, 0x20), // calldata start
                                                                              mload(_calldata),     // calldata length
                                                                              ptr,                  // write output over free memory
                                                                              0x20                  // uint256 return
                                                                          )
                                                                          if gt(success, 0) {
                                                                              ret := mload(ptr)
                                                                          }
                                                                      }
                                                                      return (success, ret);
                                                                  }
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) {
                                                                      bytes memory transferCallData = abi.encodeWithSelector(
                                                                          TRANSFER_SELECTOR,
                                                                          _to,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, transferCallData);
                                                                  }
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
                                                                      bytes memory transferFromCallData = abi.encodeWithSelector(
                                                                          _token.transferFrom.selector,
                                                                          _from,
                                                                          _to,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, transferFromCallData);
                                                                  }
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) {
                                                                      bytes memory approveCallData = abi.encodeWithSelector(
                                                                          _token.approve.selector,
                                                                          _spender,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, approveCallData);
                                                                  }
                                                                  /**
                                                                  * @dev Static call into ERC20.balanceOf().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) {
                                                                      bytes memory balanceOfCallData = abi.encodeWithSelector(
                                                                          _token.balanceOf.selector,
                                                                          _owner
                                                                      );
                                                                      (bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData);
                                                                      require(success, ERROR_TOKEN_BALANCE_REVERTED);
                                                                      return tokenBalance;
                                                                  }
                                                                  /**
                                                                  * @dev Static call into ERC20.allowance().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) {
                                                                      bytes memory allowanceCallData = abi.encodeWithSelector(
                                                                          _token.allowance.selector,
                                                                          _owner,
                                                                          _spender
                                                                      );
                                                                      (bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData);
                                                                      require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                                                                      return allowance;
                                                                  }
                                                                  /**
                                                                  * @dev Static call into ERC20.totalSupply().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticTotalSupply(ERC20 _token) internal view returns (uint256) {
                                                                      bytes memory totalSupplyCallData = abi.encodeWithSelector(_token.totalSupply.selector);
                                                                      (bool success, uint256 totalSupply) = staticInvoke(_token, totalSupplyCallData);
                                                                      require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                                                                      return totalSupply;
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              interface IEVMScriptExecutor {
                                                                  function execScript(bytes script, bytes input, address[] blacklist) external returns (bytes);
                                                                  function executorType() external pure returns (bytes32);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./IEVMScriptExecutor.sol";
                                                              contract EVMScriptRegistryConstants {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = apmNamehash("evmreg");
                                                                  */
                                                                  bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = 0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61;
                                                              }
                                                              interface IEVMScriptRegistry {
                                                                  function addScriptExecutor(IEVMScriptExecutor executor) external returns (uint id);
                                                                  function disableScriptExecutor(uint256 executorId) external;
                                                                  // TODO: this should be external
                                                                  // See https://github.com/ethereum/solidity/issues/4832
                                                                  function getScriptExecutor(bytes script) public view returns (IEVMScriptExecutor);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              contract KernelAppIds {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                                                              }
                                                              contract KernelNamespaceConstants {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                                                              }
                                                              pragma solidity ^0.4.24;
                                                              /**
                                                               * @title ERC20 interface
                                                               * @dev see https://github.com/ethereum/EIPs/issues/20
                                                               */
                                                              interface IERC20 {
                                                                function totalSupply() external view returns (uint256);
                                                                function balanceOf(address who) external view returns (uint256);
                                                                function allowance(address owner, address spender)
                                                                  external view returns (uint256);
                                                                function transfer(address to, uint256 value) external returns (bool);
                                                                function approve(address spender, uint256 value)
                                                                  external returns (bool);
                                                                function transferFrom(address from, address to, uint256 value)
                                                                  external returns (bool);
                                                                event Transfer(
                                                                  address indexed from,
                                                                  address indexed to,
                                                                  uint256 value
                                                                );
                                                                event Approval(
                                                                  address indexed owner,
                                                                  address indexed spender,
                                                                  uint256 value
                                                                );
                                                              }
                                                              // SPDX-FileCopyrightText: 2020 Lido <[email protected]>
                                                              // SPDX-License-Identifier: GPL-3.0
                                                              pragma solidity 0.4.24;
                                                              import "@aragon/os/contracts/common/UnstructuredStorage.sol";
                                                              contract Pausable {
                                                                  using UnstructuredStorage for bytes32;
                                                                  event Stopped();
                                                                  event Resumed();
                                                                  bytes32 internal constant ACTIVE_FLAG_POSITION = keccak256("lido.Pausable.activeFlag");
                                                                  modifier whenNotStopped() {
                                                                      require(ACTIVE_FLAG_POSITION.getStorageBool(), "CONTRACT_IS_STOPPED");
                                                                      _;
                                                                  }
                                                                  modifier whenStopped() {
                                                                      require(!ACTIVE_FLAG_POSITION.getStorageBool(), "CONTRACT_IS_ACTIVE");
                                                                      _;
                                                                  }
                                                                  function isStopped() external view returns (bool) {
                                                                      return !ACTIVE_FLAG_POSITION.getStorageBool();
                                                                  }
                                                                  function _stop() internal whenNotStopped {
                                                                      ACTIVE_FLAG_POSITION.setStorageBool(false);
                                                                      emit Stopped();
                                                                  }
                                                                  function _resume() internal whenStopped {
                                                                      ACTIVE_FLAG_POSITION.setStorageBool(true);
                                                                      emit Resumed();
                                                                  }
                                                              }
                                                              

                                                              File 8 of 14: AppProxyUpgradeable
                                                              // File: contracts/common/UnstructuredStorage.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              library UnstructuredStorage {
                                                                  function getStorageBool(bytes32 position) internal view returns (bool data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageAddress(bytes32 position) internal view returns (address data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                              
                                                                  function setStorageBool(bytes32 position, bool data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageAddress(bytes32 position, address data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageBytes32(bytes32 position, bytes32 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              
                                                                  function setStorageUint256(bytes32 position, uint256 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/acl/IACL.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IACL {
                                                                  function initialize(address permissionsCreator) external;
                                                              
                                                                  // TODO: this should be external
                                                                  // See https://github.com/ethereum/solidity/issues/4832
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              }
                                                              
                                                              // File: contracts/common/IVaultRecoverable.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              interface IVaultRecoverable {
                                                                  event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                                                              
                                                                  function transferToVault(address token) external;
                                                              
                                                                  function allowRecoverability(address token) external view returns (bool);
                                                                  function getRecoveryVault() external view returns (address);
                                                              }
                                                              
                                                              // File: contracts/kernel/IKernel.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              interface IKernelEvents {
                                                                  event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                                                              }
                                                              
                                                              
                                                              // This should be an interface, but interfaces can't inherit yet :(
                                                              contract IKernel is IKernelEvents, IVaultRecoverable {
                                                                  function acl() public view returns (IACL);
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              
                                                                  function setApp(bytes32 namespace, bytes32 appId, address app) public;
                                                                  function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                                                              }
                                                              
                                                              // File: contracts/apps/AppStorage.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract AppStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
                                                                  bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
                                                                  */
                                                                  bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
                                                                  bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
                                                              
                                                                  function kernel() public view returns (IKernel) {
                                                                      return IKernel(KERNEL_POSITION.getStorageAddress());
                                                                  }
                                                              
                                                                  function appId() public view returns (bytes32) {
                                                                      return APP_ID_POSITION.getStorageBytes32();
                                                                  }
                                                              
                                                                  function setKernel(IKernel _kernel) internal {
                                                                      KERNEL_POSITION.setStorageAddress(address(_kernel));
                                                                  }
                                                              
                                                                  function setAppId(bytes32 _appId) internal {
                                                                      APP_ID_POSITION.setStorageBytes32(_appId);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/IsContract.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract IsContract {
                                                                  /*
                                                                  * NOTE: this should NEVER be used for authentication
                                                                  * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                                                                  *
                                                                  * This is only intended to be used as a sanity check that an address is actually a contract,
                                                                  * RATHER THAN an address not being a contract.
                                                                  */
                                                                  function isContract(address _target) internal view returns (bool) {
                                                                      if (_target == address(0)) {
                                                                          return false;
                                                                      }
                                                              
                                                                      uint256 size;
                                                                      assembly { size := extcodesize(_target) }
                                                                      return size > 0;
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/lib/misc/ERCProxy.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract ERCProxy {
                                                                  uint256 internal constant FORWARDING = 1;
                                                                  uint256 internal constant UPGRADEABLE = 2;
                                                              
                                                                  function proxyType() public pure returns (uint256 proxyTypeId);
                                                                  function implementation() public view returns (address codeAddr);
                                                              }
                                                              
                                                              // File: contracts/common/DelegateProxy.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract DelegateProxy is ERCProxy, IsContract {
                                                                  uint256 internal constant FWD_GAS_LIMIT = 10000;
                                                              
                                                                  /**
                                                                  * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
                                                                  * @param _dst Destination address to perform the delegatecall
                                                                  * @param _calldata Calldata for the delegatecall
                                                                  */
                                                                  function delegatedFwd(address _dst, bytes _calldata) internal {
                                                                      require(isContract(_dst));
                                                                      uint256 fwdGasLimit = FWD_GAS_LIMIT;
                                                              
                                                                      assembly {
                                                                          let result := delegatecall(sub(gas, fwdGasLimit), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
                                                                          let size := returndatasize
                                                                          let ptr := mload(0x40)
                                                                          returndatacopy(ptr, 0, size)
                                                              
                                                                          // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
                                                                          // if the call returned error data, forward it
                                                                          switch result case 0 { revert(ptr, size) }
                                                                          default { return(ptr, size) }
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/DepositableStorage.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              contract DepositableStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                              
                                                                  // keccak256("aragonOS.depositableStorage.depositable")
                                                                  bytes32 internal constant DEPOSITABLE_POSITION = 0x665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea;
                                                              
                                                                  function isDepositable() public view returns (bool) {
                                                                      return DEPOSITABLE_POSITION.getStorageBool();
                                                                  }
                                                              
                                                                  function setDepositable(bool _depositable) internal {
                                                                      DEPOSITABLE_POSITION.setStorageBool(_depositable);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/common/DepositableDelegateProxy.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              contract DepositableDelegateProxy is DepositableStorage, DelegateProxy {
                                                                  event ProxyDeposit(address sender, uint256 value);
                                                              
                                                                  function () external payable {
                                                                      uint256 forwardGasThreshold = FWD_GAS_LIMIT;
                                                                      bytes32 isDepositablePosition = DEPOSITABLE_POSITION;
                                                              
                                                                      // Optimized assembly implementation to prevent EIP-1884 from breaking deposits, reference code in Solidity:
                                                                      // https://github.com/aragon/aragonOS/blob/v4.2.1/contracts/common/DepositableDelegateProxy.sol#L10-L20
                                                                      assembly {
                                                                          // Continue only if the gas left is lower than the threshold for forwarding to the implementation code,
                                                                          // otherwise continue outside of the assembly block.
                                                                          if lt(gas, forwardGasThreshold) {
                                                                              // Only accept the deposit and emit an event if all of the following are true:
                                                                              // the proxy accepts deposits (isDepositable), msg.data.length == 0, and msg.value > 0
                                                                              if and(and(sload(isDepositablePosition), iszero(calldatasize)), gt(callvalue, 0)) {
                                                                                  // Equivalent Solidity code for emitting the event:
                                                                                  // emit ProxyDeposit(msg.sender, msg.value);
                                                              
                                                                                  let logData := mload(0x40) // free memory pointer
                                                                                  mstore(logData, caller) // add 'msg.sender' to the log data (first event param)
                                                                                  mstore(add(logData, 0x20), callvalue) // add 'msg.value' to the log data (second event param)
                                                              
                                                                                  // Emit an event with one topic to identify the event: keccak256('ProxyDeposit(address,uint256)') = 0x15ee...dee1
                                                                                  log1(logData, 0x40, 0x15eeaa57c7bd188c1388020bcadc2c436ec60d647d36ef5b9eb3c742217ddee1)
                                                              
                                                                                  stop() // Stop. Exits execution context
                                                                              }
                                                              
                                                                              // If any of above checks failed, revert the execution (if ETH was sent, it is returned to the sender)
                                                                              revert(0, 0)
                                                                          }
                                                                      }
                                                              
                                                                      address target = implementation();
                                                                      delegatedFwd(target, msg.data);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/kernel/KernelConstants.sol
                                                              
                                                              /*
                                                               * SPDX-License-Identitifer:    MIT
                                                               */
                                                              
                                                              pragma solidity ^0.4.24;
                                                              
                                                              
                                                              contract KernelAppIds {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                                                              }
                                                              
                                                              
                                                              contract KernelNamespaceConstants {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyBase.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              contract AppProxyBase is AppStorage, DepositableDelegateProxy, KernelNamespaceConstants {
                                                                  /**
                                                                  * @dev Initialize AppProxy
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload) public {
                                                                      setKernel(_kernel);
                                                                      setAppId(_appId);
                                                              
                                                                      // Implicit check that kernel is actually a Kernel
                                                                      // The EVM doesn't actually provide a way for us to make sure, but we can force a revert to
                                                                      // occur if the kernel is set to 0x0 or a non-code address when we try to call a method on
                                                                      // it.
                                                                      address appCode = getAppBase(_appId);
                                                              
                                                                      // If initialize payload is provided, it will be executed
                                                                      if (_initializePayload.length > 0) {
                                                                          require(isContract(appCode));
                                                                          // Cannot make delegatecall as a delegateproxy.delegatedFwd as it
                                                                          // returns ending execution context and halts contract deployment
                                                                          require(appCode.delegatecall(_initializePayload));
                                                                      }
                                                                  }
                                                              
                                                                  function getAppBase(bytes32 _appId) internal view returns (address) {
                                                                      return kernel().getApp(KERNEL_APP_BASES_NAMESPACE, _appId);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/apps/AppProxyUpgradeable.sol
                                                              
                                                              pragma solidity 0.4.24;
                                                              
                                                              
                                                              
                                                              contract AppProxyUpgradeable is AppProxyBase {
                                                                  /**
                                                                  * @dev Initialize AppProxyUpgradeable (makes it an upgradeable Aragon app)
                                                                  * @param _kernel Reference to organization kernel for the app
                                                                  * @param _appId Identifier for app
                                                                  * @param _initializePayload Payload for call to be made after setup to initialize
                                                                  */
                                                                  constructor(IKernel _kernel, bytes32 _appId, bytes _initializePayload)
                                                                      AppProxyBase(_kernel, _appId, _initializePayload)
                                                                      public // solium-disable-line visibility-first
                                                                  {
                                                                      // solium-disable-previous-line no-empty-blocks
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, the address the proxy would delegate calls to
                                                                   */
                                                                  function implementation() public view returns (address) {
                                                                      return getAppBase(appId());
                                                                  }
                                                              
                                                                  /**
                                                                   * @dev ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy
                                                                   */
                                                                  function proxyType() public pure returns (uint256 proxyTypeId) {
                                                                      return UPGRADEABLE;
                                                                  }
                                                              }

                                                              File 9 of 14: NodeOperatorsRegistry
                                                              // SPDX-FileCopyrightText: 2020 Lido <[email protected]>
                                                              // SPDX-License-Identifier: GPL-3.0
                                                              pragma solidity 0.4.24;
                                                              /**
                                                                * @title Node Operator registry
                                                                *
                                                                * Node Operator registry manages signing keys and other node operator data.
                                                                * It's also responsible for distributing rewards to node operators.
                                                                */
                                                              interface INodeOperatorsRegistry {
                                                                  /**
                                                                    * @notice Add node operator named `name` with reward address `rewardAddress` and staking limit `stakingLimit` validators
                                                                    * @param _name Human-readable name
                                                                    * @param _rewardAddress Ethereum 1 address which receives stETH rewards for this operator
                                                                    * @param _stakingLimit the maximum number of validators to stake for this operator
                                                                    * @return a unique key of the added operator
                                                                    */
                                                                  function addNodeOperator(string _name, address _rewardAddress, uint64 _stakingLimit) external returns (uint256 id);
                                                                  /**
                                                                    * @notice `_active ? 'Enable' : 'Disable'` the node operator #`_id`
                                                                    */
                                                                  function setNodeOperatorActive(uint256 _id, bool _active) external;
                                                                  /**
                                                                    * @notice Change human-readable name of the node operator #`_id` to `_name`
                                                                    */
                                                                  function setNodeOperatorName(uint256 _id, string _name) external;
                                                                  /**
                                                                    * @notice Change reward address of the node operator #`_id` to `_rewardAddress`
                                                                    */
                                                                  function setNodeOperatorRewardAddress(uint256 _id, address _rewardAddress) external;
                                                                  /**
                                                                    * @notice Set the maximum number of validators to stake for the node operator #`_id` to `_stakingLimit`
                                                                    */
                                                                  function setNodeOperatorStakingLimit(uint256 _id, uint64 _stakingLimit) external;
                                                                  /**
                                                                    * @notice Report `_stoppedIncrement` more stopped validators of the node operator #`_id`
                                                                    */
                                                                  function reportStoppedValidators(uint256 _id, uint64 _stoppedIncrement) external;
                                                                  /**
                                                                    * @notice Remove unused signing keys
                                                                    * @dev Function is used by the pool
                                                                    */
                                                                  function trimUnusedKeys() external;
                                                                  /**
                                                                    * @notice Returns total number of node operators
                                                                    */
                                                                  function getNodeOperatorsCount() external view returns (uint256);
                                                                  /**
                                                                    * @notice Returns number of active node operators
                                                                    */
                                                                  function getActiveNodeOperatorsCount() external view returns (uint256);
                                                                  /**
                                                                    * @notice Returns the n-th node operator
                                                                    * @param _id Node Operator id
                                                                    * @param _fullInfo If true, name will be returned as well
                                                                    */
                                                                  function getNodeOperator(uint256 _id, bool _fullInfo) external view returns (
                                                                      bool active,
                                                                      string name,
                                                                      address rewardAddress,
                                                                      uint64 stakingLimit,
                                                                      uint64 stoppedValidators,
                                                                      uint64 totalSigningKeys,
                                                                      uint64 usedSigningKeys);
                                                                  /**
                                                                    * @notice Returns the rewards distribution proportional to the effective stake for each node operator.
                                                                    * @param _totalRewardShares Total amount of reward shares to distribute.
                                                                    */
                                                                  function getRewardsDistribution(uint256 _totalRewardShares) external view returns (
                                                                      address[] memory recipients,
                                                                      uint256[] memory shares
                                                                  );
                                                                  event NodeOperatorAdded(uint256 id, string name, address rewardAddress, uint64 stakingLimit);
                                                                  event NodeOperatorActiveSet(uint256 indexed id, bool active);
                                                                  event NodeOperatorNameSet(uint256 indexed id, string name);
                                                                  event NodeOperatorRewardAddressSet(uint256 indexed id, address rewardAddress);
                                                                  event NodeOperatorStakingLimitSet(uint256 indexed id, uint64 stakingLimit);
                                                                  event NodeOperatorTotalStoppedValidatorsReported(uint256 indexed id, uint64 totalStopped);
                                                                  /**
                                                                   * @notice Selects and returns at most `_numKeys` signing keys (as well as the corresponding
                                                                   *         signatures) from the set of active keys and marks the selected keys as used.
                                                                   *         May only be called by the pool contract.
                                                                   *
                                                                   * @param _numKeys The number of keys to select. The actual number of selected keys may be less
                                                                   *        due to the lack of active keys.
                                                                   */
                                                                  function assignNextSigningKeys(uint256 _numKeys) external returns (bytes memory pubkeys, bytes memory signatures);
                                                                  /**
                                                                    * @notice Add `_quantity` validator signing keys to the keys of the node operator #`_operator_id`. Concatenated keys are: `_pubkeys`
                                                                    * @dev Along with each key the DAO has to provide a signatures for the
                                                                    *      (pubkey, withdrawal_credentials, 32000000000) message.
                                                                    *      Given that information, the contract'll be able to call
                                                                    *      deposit_contract.deposit on-chain.
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _quantity Number of signing keys provided
                                                                    * @param _pubkeys Several concatenated validator signing keys
                                                                    * @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages
                                                                    */
                                                                  function addSigningKeys(uint256 _operator_id, uint256 _quantity, bytes _pubkeys, bytes _signatures) external;
                                                                  /**
                                                                    * @notice Removes a validator signing key #`_index` from the keys of the node operator #`_operator_id`
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _index Index of the key, starting with 0
                                                                    */
                                                                  function removeSigningKey(uint256 _operator_id, uint256 _index) external;
                                                                  /**
                                                                    * @notice Returns total number of signing keys of the node operator #`_operator_id`
                                                                    */
                                                                  function getTotalSigningKeyCount(uint256 _operator_id) external view returns (uint256);
                                                                  /**
                                                                    * @notice Returns number of usable signing keys of the node operator #`_operator_id`
                                                                    */
                                                                  function getUnusedSigningKeyCount(uint256 _operator_id) external view returns (uint256);
                                                                  /**
                                                                    * @notice Returns n-th signing key of the node operator #`_operator_id`
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _index Index of the key, starting with 0
                                                                    * @return key Key
                                                                    * @return depositSignature Signature needed for a deposit_contract.deposit call
                                                                    * @return used Flag indication if the key was used in the staking
                                                                    */
                                                                  function getSigningKey(uint256 _operator_id, uint256 _index) external view returns
                                                                          (bytes key, bytes depositSignature, bool used);
                                                                  event SigningKeyAdded(uint256 indexed operatorId, bytes pubkey);
                                                                  event SigningKeyRemoved(uint256 indexed operatorId, bytes pubkey);
                                                              }
                                                              // SPDX-FileCopyrightText: 2020 Lido <[email protected]>
                                                              // SPDX-License-Identifier: GPL-3.0
                                                              /* See contracts/COMPILERS.md */
                                                              pragma solidity 0.4.24;
                                                              import "@aragon/os/contracts/apps/AragonApp.sol";
                                                              import "@aragon/os/contracts/common/IsContract.sol";
                                                              import "@aragon/os/contracts/lib/math/SafeMath.sol";
                                                              import "@aragon/os/contracts/lib/math/SafeMath64.sol";
                                                              import "solidity-bytes-utils/contracts/BytesLib.sol";
                                                              import "../interfaces/INodeOperatorsRegistry.sol";
                                                              import "../lib/MemUtils.sol";
                                                              /**
                                                                * @title Node Operator registry implementation
                                                                *
                                                                * See the comment of `INodeOperatorsRegistry`.
                                                                *
                                                                * NOTE: the code below assumes moderate amount of node operators, e.g. up to 50.
                                                                */
                                                              contract NodeOperatorsRegistry is INodeOperatorsRegistry, IsContract, AragonApp {
                                                                  using SafeMath for uint256;
                                                                  using SafeMath64 for uint64;
                                                                  using UnstructuredStorage for bytes32;
                                                                  /// ACL
                                                                  bytes32 constant public MANAGE_SIGNING_KEYS = keccak256("MANAGE_SIGNING_KEYS");
                                                                  bytes32 constant public ADD_NODE_OPERATOR_ROLE = keccak256("ADD_NODE_OPERATOR_ROLE");
                                                                  bytes32 constant public SET_NODE_OPERATOR_ACTIVE_ROLE = keccak256("SET_NODE_OPERATOR_ACTIVE_ROLE");
                                                                  bytes32 constant public SET_NODE_OPERATOR_NAME_ROLE = keccak256("SET_NODE_OPERATOR_NAME_ROLE");
                                                                  bytes32 constant public SET_NODE_OPERATOR_ADDRESS_ROLE = keccak256("SET_NODE_OPERATOR_ADDRESS_ROLE");
                                                                  bytes32 constant public SET_NODE_OPERATOR_LIMIT_ROLE = keccak256("SET_NODE_OPERATOR_LIMIT_ROLE");
                                                                  bytes32 constant public REPORT_STOPPED_VALIDATORS_ROLE = keccak256("REPORT_STOPPED_VALIDATORS_ROLE");
                                                                  uint256 constant public PUBKEY_LENGTH = 48;
                                                                  uint256 constant public SIGNATURE_LENGTH = 96;
                                                                  uint256 internal constant UINT64_MAX = uint256(uint64(-1));
                                                                  bytes32 internal constant SIGNING_KEYS_MAPPING_NAME = keccak256("lido.NodeOperatorsRegistry.signingKeysMappingName");
                                                                  /// @dev Node Operator parameters and internal state
                                                                  struct NodeOperator {
                                                                      bool active;    // a flag indicating if the operator can participate in further staking and reward distribution
                                                                      address rewardAddress;  // Ethereum 1 address which receives steth rewards for this operator
                                                                      string name;    // human-readable name
                                                                      uint64 stakingLimit;    // the maximum number of validators to stake for this operator
                                                                      uint64 stoppedValidators;   // number of signing keys which stopped validation (e.g. were slashed)
                                                                      uint64 totalSigningKeys;    // total amount of signing keys of this operator
                                                                      uint64 usedSigningKeys;     // number of signing keys of this operator which were used in deposits to the Ethereum 2
                                                                  }
                                                                  /// @dev Memory cache entry used in the assignNextKeys function
                                                                  struct DepositLookupCacheEntry {
                                                                      // Makes no sense to pack types since reading memory is as fast as any op
                                                                      uint256 id;
                                                                      uint256 stakingLimit;
                                                                      uint256 stoppedValidators;
                                                                      uint256 totalSigningKeys;
                                                                      uint256 usedSigningKeys;
                                                                      uint256 initialUsedSigningKeys;
                                                                  }
                                                                  /// @dev Mapping of all node operators. Mapping is used to be able to extend the struct.
                                                                  mapping(uint256 => NodeOperator) internal operators;
                                                                  // @dev Total number of operators
                                                                  bytes32 internal constant TOTAL_OPERATORS_COUNT_POSITION = keccak256("lido.NodeOperatorsRegistry.totalOperatorsCount");
                                                                  // @dev Cached number of active operators
                                                                  bytes32 internal constant ACTIVE_OPERATORS_COUNT_POSITION = keccak256("lido.NodeOperatorsRegistry.activeOperatorsCount");
                                                                  /// @dev link to the Lido contract
                                                                  bytes32 internal constant LIDO_POSITION = keccak256("lido.NodeOperatorsRegistry.lido");
                                                                  modifier onlyLido() {
                                                                      require(msg.sender == LIDO_POSITION.getStorageAddress(), "APP_AUTH_FAILED");
                                                                      _;
                                                                  }
                                                                  modifier validAddress(address _a) {
                                                                      require(_a != address(0), "EMPTY_ADDRESS");
                                                                      _;
                                                                  }
                                                                  modifier operatorExists(uint256 _id) {
                                                                      require(_id < getNodeOperatorsCount(), "NODE_OPERATOR_NOT_FOUND");
                                                                      _;
                                                                  }
                                                                  function initialize(address _lido) public onlyInit {
                                                                      TOTAL_OPERATORS_COUNT_POSITION.setStorageUint256(0);
                                                                      ACTIVE_OPERATORS_COUNT_POSITION.setStorageUint256(0);
                                                                      LIDO_POSITION.setStorageAddress(_lido);
                                                                      initialized();
                                                                  }
                                                                  /**
                                                                    * @notice Add node operator named `_name` with reward address `_rewardAddress` and staking limit `_stakingLimit`
                                                                    * @param _name Human-readable name
                                                                    * @param _rewardAddress Ethereum 1 address which receives stETH rewards for this operator
                                                                    * @param _stakingLimit the maximum number of validators to stake for this operator
                                                                    * @return a unique key of the added operator
                                                                    */
                                                                  function addNodeOperator(string _name, address _rewardAddress, uint64 _stakingLimit) external
                                                                      auth(ADD_NODE_OPERATOR_ROLE)
                                                                      validAddress(_rewardAddress)
                                                                      returns (uint256 id)
                                                                  {
                                                                      id = getNodeOperatorsCount();
                                                                      TOTAL_OPERATORS_COUNT_POSITION.setStorageUint256(id.add(1));
                                                                      NodeOperator storage operator = operators[id];
                                                                      uint256 activeOperatorsCount = getActiveNodeOperatorsCount();
                                                                      ACTIVE_OPERATORS_COUNT_POSITION.setStorageUint256(activeOperatorsCount.add(1));
                                                                      operator.active = true;
                                                                      operator.name = _name;
                                                                      operator.rewardAddress = _rewardAddress;
                                                                      operator.stakingLimit = _stakingLimit;
                                                                      emit NodeOperatorAdded(id, _name, _rewardAddress, _stakingLimit);
                                                                      return id;
                                                                  }
                                                                  /**
                                                                    * @notice `_active ? 'Enable' : 'Disable'` the node operator #`_id`
                                                                    */
                                                                  function setNodeOperatorActive(uint256 _id, bool _active) external
                                                                      authP(SET_NODE_OPERATOR_ACTIVE_ROLE, arr(_id, _active ? uint256(1) : uint256(0)))
                                                                      operatorExists(_id)
                                                                  {
                                                                      if (operators[_id].active != _active) {
                                                                          uint256 activeOperatorsCount = getActiveNodeOperatorsCount();
                                                                          if (_active)
                                                                              ACTIVE_OPERATORS_COUNT_POSITION.setStorageUint256(activeOperatorsCount.add(1));
                                                                          else
                                                                              ACTIVE_OPERATORS_COUNT_POSITION.setStorageUint256(activeOperatorsCount.sub(1));
                                                                      }
                                                                      operators[_id].active = _active;
                                                                      emit NodeOperatorActiveSet(_id, _active);
                                                                  }
                                                                  /**
                                                                    * @notice Change human-readable name of the node operator #`_id` to `_name`
                                                                    */
                                                                  function setNodeOperatorName(uint256 _id, string _name) external
                                                                      authP(SET_NODE_OPERATOR_NAME_ROLE, arr(_id))
                                                                      operatorExists(_id)
                                                                  {
                                                                      operators[_id].name = _name;
                                                                      emit NodeOperatorNameSet(_id, _name);
                                                                  }
                                                                  /**
                                                                    * @notice Change reward address of the node operator #`_id` to `_rewardAddress`
                                                                    */
                                                                  function setNodeOperatorRewardAddress(uint256 _id, address _rewardAddress) external
                                                                      authP(SET_NODE_OPERATOR_ADDRESS_ROLE, arr(_id, uint256(_rewardAddress)))
                                                                      operatorExists(_id)
                                                                      validAddress(_rewardAddress)
                                                                  {
                                                                      operators[_id].rewardAddress = _rewardAddress;
                                                                      emit NodeOperatorRewardAddressSet(_id, _rewardAddress);
                                                                  }
                                                                  /**
                                                                    * @notice Set the maximum number of validators to stake for the node operator #`_id` to `_stakingLimit`
                                                                    */
                                                                  function setNodeOperatorStakingLimit(uint256 _id, uint64 _stakingLimit) external
                                                                      authP(SET_NODE_OPERATOR_LIMIT_ROLE, arr(_id, uint256(_stakingLimit)))
                                                                      operatorExists(_id)
                                                                  {
                                                                      operators[_id].stakingLimit = _stakingLimit;
                                                                      emit NodeOperatorStakingLimitSet(_id, _stakingLimit);
                                                                  }
                                                                  /**
                                                                    * @notice Report `_stoppedIncrement` more stopped validators of the node operator #`_id`
                                                                    */
                                                                  function reportStoppedValidators(uint256 _id, uint64 _stoppedIncrement) external
                                                                      authP(REPORT_STOPPED_VALIDATORS_ROLE, arr(_id, uint256(_stoppedIncrement)))
                                                                      operatorExists(_id)
                                                                  {
                                                                      require(0 != _stoppedIncrement, "EMPTY_VALUE");
                                                                      operators[_id].stoppedValidators = operators[_id].stoppedValidators.add(_stoppedIncrement);
                                                                      require(operators[_id].stoppedValidators <= operators[_id].usedSigningKeys, "STOPPED_MORE_THAN_LAUNCHED");
                                                                      emit NodeOperatorTotalStoppedValidatorsReported(_id, operators[_id].stoppedValidators);
                                                                  }
                                                                  /**
                                                                    * @notice Remove unused signing keys
                                                                    * @dev Function is used by the Lido contract
                                                                    */
                                                                  function trimUnusedKeys() external onlyLido {
                                                                      uint256 length = getNodeOperatorsCount();
                                                                      for (uint256 operatorId = 0; operatorId < length; ++operatorId) {
                                                                          if (operators[operatorId].totalSigningKeys != operators[operatorId].usedSigningKeys)  // write only if update is needed
                                                                              operators[operatorId].totalSigningKeys = operators[operatorId].usedSigningKeys;  // discard unused keys
                                                                      }
                                                                  }
                                                                  /**
                                                                    * @notice Add `_quantity` validator signing keys of operator #`_id` to the set of usable keys. Concatenated keys are: `_pubkeys`. Can be done by the DAO in question by using the designated rewards address.
                                                                    * @dev Along with each key the DAO has to provide a signatures for the
                                                                    *      (pubkey, withdrawal_credentials, 32000000000) message.
                                                                    *      Given that information, the contract'll be able to call
                                                                    *      deposit_contract.deposit on-chain.
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _quantity Number of signing keys provided
                                                                    * @param _pubkeys Several concatenated validator signing keys
                                                                    * @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages
                                                                    */
                                                                  function addSigningKeys(uint256 _operator_id, uint256 _quantity, bytes _pubkeys, bytes _signatures) external
                                                                      authP(MANAGE_SIGNING_KEYS, arr(_operator_id))
                                                                  {
                                                                      _addSigningKeys(_operator_id, _quantity, _pubkeys, _signatures);
                                                                  }
                                                                  /**
                                                                    * @notice Add `_quantity` validator signing keys of operator #`_id` to the set of usable keys. Concatenated keys are: `_pubkeys`. Can be done by node operator in question by using the designated rewards address.
                                                                    * @dev Along with each key the DAO has to provide a signatures for the
                                                                    *      (pubkey, withdrawal_credentials, 32000000000) message.
                                                                    *      Given that information, the contract'll be able to call
                                                                    *      deposit_contract.deposit on-chain.
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _quantity Number of signing keys provided
                                                                    * @param _pubkeys Several concatenated validator signing keys
                                                                    * @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages
                                                                    */
                                                                  function addSigningKeysOperatorBH(
                                                                      uint256 _operator_id,
                                                                      uint256 _quantity,
                                                                      bytes _pubkeys,
                                                                      bytes _signatures
                                                                  )
                                                                      external
                                                                  {
                                                                      require(msg.sender == operators[_operator_id].rewardAddress, "APP_AUTH_FAILED");
                                                                      _addSigningKeys(_operator_id, _quantity, _pubkeys, _signatures);
                                                                  }
                                                                  /**
                                                                    * @notice Removes a validator signing key #`_index` of operator #`_id` from the set of usable keys. Executed on behalf of DAO.
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _index Index of the key, starting with 0
                                                                    */
                                                                  function removeSigningKey(uint256 _operator_id, uint256 _index)
                                                                      external
                                                                      authP(MANAGE_SIGNING_KEYS, arr(_operator_id))
                                                                  {
                                                                      _removeSigningKey(_operator_id, _index);
                                                                  }
                                                                  /**
                                                                    * @notice Removes a validator signing key #`_index` of operator #`_id` from the set of usable keys. Executed on behalf of Node Operator.
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _index Index of the key, starting with 0
                                                                    */
                                                                  function removeSigningKeyOperatorBH(uint256 _operator_id, uint256 _index) external {
                                                                      require(msg.sender == operators[_operator_id].rewardAddress, "APP_AUTH_FAILED");
                                                                      _removeSigningKey(_operator_id, _index);
                                                                  }
                                                                  /**
                                                                   * @notice Selects and returns at most `_numKeys` signing keys (as well as the corresponding
                                                                   *         signatures) from the set of active keys and marks the selected keys as used.
                                                                   *         May only be called by the Lido contract.
                                                                   *
                                                                   * @param _numKeys The number of keys to select. The actual number of selected keys may be less
                                                                   *        due to the lack of active keys.
                                                                   */
                                                                  function assignNextSigningKeys(uint256 _numKeys) external onlyLido returns (bytes memory pubkeys, bytes memory signatures) {
                                                                      // Memory is very cheap, although you don't want to grow it too much
                                                                      DepositLookupCacheEntry[] memory cache = _loadOperatorCache();
                                                                      if (0 == cache.length)
                                                                          return (new bytes(0), new bytes(0));
                                                                      uint256 numAssignedKeys = 0;
                                                                      DepositLookupCacheEntry memory entry;
                                                                      while (numAssignedKeys < _numKeys) {
                                                                          // Finding the best suitable operator
                                                                          uint256 bestOperatorIdx = cache.length;   // 'not found' flag
                                                                          uint256 smallestStake;
                                                                          // The loop is ligthweight comparing to an ether transfer and .deposit invocation
                                                                          for (uint256 idx = 0; idx < cache.length; ++idx) {
                                                                              entry = cache[idx];
                                                                              assert(entry.usedSigningKeys <= entry.totalSigningKeys);
                                                                              if (entry.usedSigningKeys == entry.totalSigningKeys)
                                                                                  continue;
                                                                              uint256 stake = entry.usedSigningKeys.sub(entry.stoppedValidators);
                                                                              if (stake + 1 > entry.stakingLimit)
                                                                                  continue;
                                                                              if (bestOperatorIdx == cache.length || stake < smallestStake) {
                                                                                  bestOperatorIdx = idx;
                                                                                  smallestStake = stake;
                                                                              }
                                                                          }
                                                                          if (bestOperatorIdx == cache.length)  // not found
                                                                              break;
                                                                          entry = cache[bestOperatorIdx];
                                                                          assert(entry.usedSigningKeys < UINT64_MAX);
                                                                          ++entry.usedSigningKeys;
                                                                          ++numAssignedKeys;
                                                                      }
                                                                      if (numAssignedKeys == 0) {
                                                                          return (new bytes(0), new bytes(0));
                                                                      }
                                                                      if (numAssignedKeys > 1) {
                                                                          // we can allocate without zeroing out since we're going to rewrite the whole array
                                                                          pubkeys = MemUtils.unsafeAllocateBytes(numAssignedKeys * PUBKEY_LENGTH);
                                                                          signatures = MemUtils.unsafeAllocateBytes(numAssignedKeys * SIGNATURE_LENGTH);
                                                                      }
                                                                      uint256 numLoadedKeys = 0;
                                                                      for (uint256 i = 0; i < cache.length; ++i) {
                                                                          entry = cache[i];
                                                                          if (entry.usedSigningKeys == entry.initialUsedSigningKeys) {
                                                                              continue;
                                                                          }
                                                                          operators[entry.id].usedSigningKeys = uint64(entry.usedSigningKeys);
                                                                          for (uint256 keyIndex = entry.initialUsedSigningKeys; keyIndex < entry.usedSigningKeys; ++keyIndex) {
                                                                              (bytes memory pubkey, bytes memory signature) = _loadSigningKey(entry.id, keyIndex);
                                                                              if (numAssignedKeys == 1) {
                                                                                  return (pubkey, signature);
                                                                              } else {
                                                                                  MemUtils.copyBytes(pubkey, pubkeys, numLoadedKeys * PUBKEY_LENGTH);
                                                                                  MemUtils.copyBytes(signature, signatures, numLoadedKeys * SIGNATURE_LENGTH);
                                                                                  ++numLoadedKeys;
                                                                              }
                                                                          }
                                                                          if (numLoadedKeys == numAssignedKeys) {
                                                                              break;
                                                                          }
                                                                      }
                                                                      assert(numLoadedKeys == numAssignedKeys);
                                                                      return (pubkeys, signatures);
                                                                  }
                                                                  /**
                                                                    * @notice Returns the rewards distribution proportional to the effective stake for each node operator.
                                                                    * @param _totalRewardShares Total amount of reward shares to distribute.
                                                                    */
                                                                  function getRewardsDistribution(uint256 _totalRewardShares) external view
                                                                      returns (
                                                                          address[] memory recipients,
                                                                          uint256[] memory shares
                                                                      )
                                                                  {
                                                                      uint256 nodeOperatorCount = getNodeOperatorsCount();
                                                                      uint256 activeCount = getActiveNodeOperatorsCount();
                                                                      recipients = new address[](activeCount);
                                                                      shares = new uint256[](activeCount);
                                                                      uint256 idx = 0;
                                                                      uint256 effectiveStakeTotal = 0;
                                                                      for (uint256 operatorId = 0; operatorId < nodeOperatorCount; ++operatorId) {
                                                                          NodeOperator storage operator = operators[operatorId];
                                                                          if (!operator.active)
                                                                              continue;
                                                                          uint256 effectiveStake = operator.usedSigningKeys.sub(operator.stoppedValidators);
                                                                          effectiveStakeTotal = effectiveStakeTotal.add(effectiveStake);
                                                                          recipients[idx] = operator.rewardAddress;
                                                                          shares[idx] = effectiveStake;
                                                                          ++idx;
                                                                      }
                                                                      if (effectiveStakeTotal == 0)
                                                                          return (recipients, shares);
                                                                      uint256 perValidatorReward = _totalRewardShares.div(effectiveStakeTotal);
                                                                      for (idx = 0; idx < activeCount; ++idx) {
                                                                          shares[idx] = shares[idx].mul(perValidatorReward);
                                                                      }
                                                                      return (recipients, shares);
                                                                  }
                                                                  /**
                                                                    * @notice Returns number of active node operators
                                                                    */
                                                                  function getActiveNodeOperatorsCount() public view returns (uint256) {
                                                                      return ACTIVE_OPERATORS_COUNT_POSITION.getStorageUint256();
                                                                  }
                                                                  /**
                                                                    * @notice Returns the n-th node operator
                                                                    * @param _id Node Operator id
                                                                    * @param _fullInfo If true, name will be returned as well
                                                                    */
                                                                  function getNodeOperator(uint256 _id, bool _fullInfo) external view
                                                                      operatorExists(_id)
                                                                      returns
                                                                      (
                                                                          bool active,
                                                                          string name,
                                                                          address rewardAddress,
                                                                          uint64 stakingLimit,
                                                                          uint64 stoppedValidators,
                                                                          uint64 totalSigningKeys,
                                                                          uint64 usedSigningKeys
                                                                      )
                                                                  {
                                                                      NodeOperator storage operator = operators[_id];
                                                                      active = operator.active;
                                                                      name = _fullInfo ? operator.name : "";    // reading name is 2+ SLOADs
                                                                      rewardAddress = operator.rewardAddress;
                                                                      stakingLimit = operator.stakingLimit;
                                                                      stoppedValidators = operator.stoppedValidators;
                                                                      totalSigningKeys = operator.totalSigningKeys;
                                                                      usedSigningKeys = operator.usedSigningKeys;
                                                                  }
                                                                  /**
                                                                    * @notice Returns total number of signing keys of the node operator #`_operator_id`
                                                                    */
                                                                  function getTotalSigningKeyCount(uint256 _operator_id) external view operatorExists(_operator_id) returns (uint256) {
                                                                      return operators[_operator_id].totalSigningKeys;
                                                                  }
                                                                  /**
                                                                    * @notice Returns number of usable signing keys of the node operator #`_operator_id`
                                                                    */
                                                                  function getUnusedSigningKeyCount(uint256 _operator_id) external view operatorExists(_operator_id) returns (uint256) {
                                                                      return operators[_operator_id].totalSigningKeys.sub(operators[_operator_id].usedSigningKeys);
                                                                  }
                                                                  /**
                                                                    * @notice Returns n-th signing key of the node operator #`_operator_id`
                                                                    * @param _operator_id Node Operator id
                                                                    * @param _index Index of the key, starting with 0
                                                                    * @return key Key
                                                                    * @return depositSignature Signature needed for a deposit_contract.deposit call
                                                                    * @return used Flag indication if the key was used in the staking
                                                                    */
                                                                  function getSigningKey(uint256 _operator_id, uint256 _index) external view
                                                                      operatorExists(_operator_id)
                                                                      returns (bytes key, bytes depositSignature, bool used)
                                                                  {
                                                                      require(_index < operators[_operator_id].totalSigningKeys, "KEY_NOT_FOUND");
                                                                      (bytes memory key_, bytes memory signature) = _loadSigningKey(_operator_id, _index);
                                                                      return (key_, signature, _index < operators[_operator_id].usedSigningKeys);
                                                                  }
                                                                  /**
                                                                    * @notice Returns total number of node operators
                                                                    */
                                                                  function getNodeOperatorsCount() public view returns (uint256) {
                                                                      return TOTAL_OPERATORS_COUNT_POSITION.getStorageUint256();
                                                                  }
                                                                  function _isEmptySigningKey(bytes memory _key) internal pure returns (bool) {
                                                                      assert(_key.length == PUBKEY_LENGTH);
                                                                      // algorithm applicability constraint
                                                                      assert(PUBKEY_LENGTH >= 32 && PUBKEY_LENGTH <= 64);
                                                                      uint256 k1;
                                                                      uint256 k2;
                                                                      assembly {
                                                                          k1 := mload(add(_key, 0x20))
                                                                          k2 := mload(add(_key, 0x40))
                                                                      }
                                                                      return 0 == k1 && 0 == (k2 >> ((2 * 32 - PUBKEY_LENGTH) * 8));
                                                                  }
                                                                  function to64(uint256 v) internal pure returns (uint64) {
                                                                      assert(v <= uint256(uint64(-1)));
                                                                      return uint64(v);
                                                                  }
                                                                  function _signingKeyOffset(uint256 _operator_id, uint256 _keyIndex) internal pure returns (uint256) {
                                                                      return uint256(keccak256(abi.encodePacked(SIGNING_KEYS_MAPPING_NAME, _operator_id, _keyIndex)));
                                                                  }
                                                                  function _storeSigningKey(uint256 _operator_id, uint256 _keyIndex, bytes memory _key, bytes memory _signature) internal {
                                                                      assert(_key.length == PUBKEY_LENGTH);
                                                                      assert(_signature.length == SIGNATURE_LENGTH);
                                                                      // algorithm applicability constraints
                                                                      assert(PUBKEY_LENGTH >= 32 && PUBKEY_LENGTH <= 64);
                                                                      assert(0 == SIGNATURE_LENGTH % 32);
                                                                      // key
                                                                      uint256 offset = _signingKeyOffset(_operator_id, _keyIndex);
                                                                      uint256 keyExcessBits = (2 * 32 - PUBKEY_LENGTH) * 8;
                                                                      assembly {
                                                                          sstore(offset, mload(add(_key, 0x20)))
                                                                          sstore(add(offset, 1), shl(keyExcessBits, shr(keyExcessBits, mload(add(_key, 0x40)))))
                                                                      }
                                                                      offset += 2;
                                                                      // signature
                                                                      for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) {
                                                                          assembly {
                                                                              sstore(offset, mload(add(_signature, add(0x20, i))))
                                                                          }
                                                                          offset++;
                                                                      }
                                                                  }
                                                                  function _addSigningKeys(uint256 _operator_id, uint256 _quantity, bytes _pubkeys, bytes _signatures) internal
                                                                      operatorExists(_operator_id)
                                                                  {
                                                                      require(_quantity != 0, "NO_KEYS");
                                                                      require(_pubkeys.length == _quantity.mul(PUBKEY_LENGTH), "INVALID_LENGTH");
                                                                      require(_signatures.length == _quantity.mul(SIGNATURE_LENGTH), "INVALID_LENGTH");
                                                                      for (uint256 i = 0; i < _quantity; ++i) {
                                                                          bytes memory key = BytesLib.slice(_pubkeys, i * PUBKEY_LENGTH, PUBKEY_LENGTH);
                                                                          require(!_isEmptySigningKey(key), "EMPTY_KEY");
                                                                          bytes memory sig = BytesLib.slice(_signatures, i * SIGNATURE_LENGTH, SIGNATURE_LENGTH);
                                                                          _storeSigningKey(_operator_id, operators[_operator_id].totalSigningKeys + i, key, sig);
                                                                          emit SigningKeyAdded(_operator_id, key);
                                                                      }
                                                                      operators[_operator_id].totalSigningKeys = operators[_operator_id].totalSigningKeys.add(to64(_quantity));
                                                                  }
                                                                  function _removeSigningKey(uint256 _operator_id, uint256 _index) internal
                                                                      operatorExists(_operator_id)
                                                                  {
                                                                      require(_index < operators[_operator_id].totalSigningKeys, "KEY_NOT_FOUND");
                                                                      require(_index >= operators[_operator_id].usedSigningKeys, "KEY_WAS_USED");
                                                                      (bytes memory removedKey, ) = _loadSigningKey(_operator_id, _index);
                                                                      uint256 lastIndex = operators[_operator_id].totalSigningKeys.sub(1);
                                                                      if (_index < lastIndex) {
                                                                          (bytes memory key, bytes memory signature) = _loadSigningKey(_operator_id, lastIndex);
                                                                          _storeSigningKey(_operator_id, _index, key, signature);
                                                                      }
                                                                      _deleteSigningKey(_operator_id, lastIndex);
                                                                      operators[_operator_id].totalSigningKeys = operators[_operator_id].totalSigningKeys.sub(1);
                                                                      emit SigningKeyRemoved(_operator_id, removedKey);
                                                                  }
                                                                  function _deleteSigningKey(uint256 _operator_id, uint256 _keyIndex) internal {
                                                                      uint256 offset = _signingKeyOffset(_operator_id, _keyIndex);
                                                                      for (uint256 i = 0; i < (PUBKEY_LENGTH + SIGNATURE_LENGTH) / 32 + 1; ++i) {
                                                                          assembly {
                                                                              sstore(add(offset, i), 0)
                                                                          }
                                                                      }
                                                                  }
                                                                  function _loadSigningKey(uint256 _operator_id, uint256 _keyIndex) internal view returns (bytes memory key, bytes memory signature) {
                                                                      // algorithm applicability constraints
                                                                      assert(PUBKEY_LENGTH >= 32 && PUBKEY_LENGTH <= 64);
                                                                      assert(0 == SIGNATURE_LENGTH % 32);
                                                                      uint256 offset = _signingKeyOffset(_operator_id, _keyIndex);
                                                                      // key
                                                                      bytes memory tmpKey = new bytes(64);
                                                                      assembly {
                                                                          mstore(add(tmpKey, 0x20), sload(offset))
                                                                          mstore(add(tmpKey, 0x40), sload(add(offset, 1)))
                                                                      }
                                                                      offset += 2;
                                                                      key = BytesLib.slice(tmpKey, 0, PUBKEY_LENGTH);
                                                                      // signature
                                                                      signature = new bytes(SIGNATURE_LENGTH);
                                                                      for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) {
                                                                          assembly {
                                                                              mstore(add(signature, add(0x20, i)), sload(offset))
                                                                          }
                                                                          offset++;
                                                                      }
                                                                      return (key, signature);
                                                                  }
                                                                  function _loadOperatorCache() internal view returns (DepositLookupCacheEntry[] memory cache) {
                                                                      cache = new DepositLookupCacheEntry[](getActiveNodeOperatorsCount());
                                                                      if (0 == cache.length)
                                                                          return cache;
                                                                      uint256 totalOperators = getNodeOperatorsCount();
                                                                      uint256 idx = 0;
                                                                      for (uint256 operatorId = 0; operatorId < totalOperators; ++operatorId) {
                                                                          NodeOperator storage operator = operators[operatorId];
                                                                          if (!operator.active)
                                                                              continue;
                                                                          DepositLookupCacheEntry memory entry = cache[idx++];
                                                                          entry.id = operatorId;
                                                                          entry.stakingLimit = operator.stakingLimit;
                                                                          entry.stoppedValidators = operator.stoppedValidators;
                                                                          entry.totalSigningKeys = operator.totalSigningKeys;
                                                                          entry.usedSigningKeys = operator.usedSigningKeys;
                                                                          entry.initialUsedSigningKeys = entry.usedSigningKeys;
                                                                      }
                                                                      require(idx == cache.length, "INCOSISTENT_ACTIVE_COUNT");
                                                                      return cache;
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./AppStorage.sol";
                                                              import "../acl/ACLSyntaxSugar.sol";
                                                              import "../common/Autopetrified.sol";
                                                              import "../common/ConversionHelpers.sol";
                                                              import "../common/ReentrancyGuard.sol";
                                                              import "../common/VaultRecoverable.sol";
                                                              import "../evmscript/EVMScriptRunner.sol";
                                                              // Contracts inheriting from AragonApp are, by default, immediately petrified upon deployment so
                                                              // that they can never be initialized.
                                                              // Unless overriden, this behaviour enforces those contracts to be usable only behind an AppProxy.
                                                              // ReentrancyGuard, EVMScriptRunner, and ACLSyntaxSugar are not directly used by this contract, but
                                                              // are included so that they are automatically usable by subclassing contracts
                                                              contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGuard, EVMScriptRunner, ACLSyntaxSugar {
                                                                  string private constant ERROR_AUTH_FAILED = "APP_AUTH_FAILED";
                                                                  modifier auth(bytes32 _role) {
                                                                      require(canPerform(msg.sender, _role, new uint256[](0)), ERROR_AUTH_FAILED);
                                                                      _;
                                                                  }
                                                                  modifier authP(bytes32 _role, uint256[] _params) {
                                                                      require(canPerform(msg.sender, _role, _params), ERROR_AUTH_FAILED);
                                                                      _;
                                                                  }
                                                                  /**
                                                                  * @dev Check whether an action can be performed by a sender for a particular role on this app
                                                                  * @param _sender Sender of the call
                                                                  * @param _role Role on this app
                                                                  * @param _params Permission params for the role
                                                                  * @return Boolean indicating whether the sender has the permissions to perform the action.
                                                                  *         Always returns false if the app hasn't been initialized yet.
                                                                  */
                                                                  function canPerform(address _sender, bytes32 _role, uint256[] _params) public view returns (bool) {
                                                                      if (!hasInitialized()) {
                                                                          return false;
                                                                      }
                                                                      IKernel linkedKernel = kernel();
                                                                      if (address(linkedKernel) == address(0)) {
                                                                          return false;
                                                                      }
                                                                      return linkedKernel.hasPermission(
                                                                          _sender,
                                                                          address(this),
                                                                          _role,
                                                                          ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)
                                                                      );
                                                                  }
                                                                  /**
                                                                  * @dev Get the recovery vault for the app
                                                                  * @return Recovery vault address for the app
                                                                  */
                                                                  function getRecoveryVault() public view returns (address) {
                                                                      // Funds recovery via a vault is only available when used with a kernel
                                                                      return kernel().getRecoveryVault(); // if kernel is not set, it will revert
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              contract IsContract {
                                                                  /*
                                                                  * NOTE: this should NEVER be used for authentication
                                                                  * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
                                                                  *
                                                                  * This is only intended to be used as a sanity check that an address is actually a contract,
                                                                  * RATHER THAN an address not being a contract.
                                                                  */
                                                                  function isContract(address _target) internal view returns (bool) {
                                                                      if (_target == address(0)) {
                                                                          return false;
                                                                      }
                                                                      uint256 size;
                                                                      assembly { size := extcodesize(_target) }
                                                                      return size > 0;
                                                                  }
                                                              }
                                                              // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol
                                                              // Adapted to use pragma ^0.4.24 and satisfy our linter rules
                                                              pragma solidity ^0.4.24;
                                                              /**
                                                               * @title SafeMath
                                                               * @dev Math operations with safety checks that revert on error
                                                               */
                                                              library SafeMath {
                                                                  string private constant ERROR_ADD_OVERFLOW = "MATH_ADD_OVERFLOW";
                                                                  string private constant ERROR_SUB_UNDERFLOW = "MATH_SUB_UNDERFLOW";
                                                                  string private constant ERROR_MUL_OVERFLOW = "MATH_MUL_OVERFLOW";
                                                                  string private constant ERROR_DIV_ZERO = "MATH_DIV_ZERO";
                                                                  /**
                                                                  * @dev Multiplies two numbers, reverts on overflow.
                                                                  */
                                                                  function mul(uint256 _a, uint256 _b) internal pure returns (uint256) {
                                                                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                                                                      // benefit is lost if 'b' is also tested.
                                                                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                                                                      if (_a == 0) {
                                                                          return 0;
                                                                      }
                                                                      uint256 c = _a * _b;
                                                                      require(c / _a == _b, ERROR_MUL_OVERFLOW);
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
                                                                  */
                                                                  function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
                                                                      require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
                                                                      uint256 c = _a / _b;
                                                                      // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                                                                  */
                                                                  function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
                                                                      require(_b <= _a, ERROR_SUB_UNDERFLOW);
                                                                      uint256 c = _a - _b;
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Adds two numbers, reverts on overflow.
                                                                  */
                                                                  function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
                                                                      uint256 c = _a + _b;
                                                                      require(c >= _a, ERROR_ADD_OVERFLOW);
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
                                                                  * reverts when dividing by zero.
                                                                  */
                                                                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                      require(b != 0, ERROR_DIV_ZERO);
                                                                      return a % b;
                                                                  }
                                                              }
                                                              // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol
                                                              // Adapted for uint64, pragma ^0.4.24, and satisfying our linter rules
                                                              // Also optimized the mul() implementation, see https://github.com/aragon/aragonOS/pull/417
                                                              pragma solidity ^0.4.24;
                                                              /**
                                                               * @title SafeMath64
                                                               * @dev Math operations for uint64 with safety checks that revert on error
                                                               */
                                                              library SafeMath64 {
                                                                  string private constant ERROR_ADD_OVERFLOW = "MATH64_ADD_OVERFLOW";
                                                                  string private constant ERROR_SUB_UNDERFLOW = "MATH64_SUB_UNDERFLOW";
                                                                  string private constant ERROR_MUL_OVERFLOW = "MATH64_MUL_OVERFLOW";
                                                                  string private constant ERROR_DIV_ZERO = "MATH64_DIV_ZERO";
                                                                  /**
                                                                  * @dev Multiplies two numbers, reverts on overflow.
                                                                  */
                                                                  function mul(uint64 _a, uint64 _b) internal pure returns (uint64) {
                                                                      uint256 c = uint256(_a) * uint256(_b);
                                                                      require(c < 0x010000000000000000, ERROR_MUL_OVERFLOW); // 2**64 (less gas this way)
                                                                      return uint64(c);
                                                                  }
                                                                  /**
                                                                  * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
                                                                  */
                                                                  function div(uint64 _a, uint64 _b) internal pure returns (uint64) {
                                                                      require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
                                                                      uint64 c = _a / _b;
                                                                      // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                                                                  */
                                                                  function sub(uint64 _a, uint64 _b) internal pure returns (uint64) {
                                                                      require(_b <= _a, ERROR_SUB_UNDERFLOW);
                                                                      uint64 c = _a - _b;
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Adds two numbers, reverts on overflow.
                                                                  */
                                                                  function add(uint64 _a, uint64 _b) internal pure returns (uint64) {
                                                                      uint64 c = _a + _b;
                                                                      require(c >= _a, ERROR_ADD_OVERFLOW);
                                                                      return c;
                                                                  }
                                                                  /**
                                                                  * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
                                                                  * reverts when dividing by zero.
                                                                  */
                                                                  function mod(uint64 a, uint64 b) internal pure returns (uint64) {
                                                                      require(b != 0, ERROR_DIV_ZERO);
                                                                      return a % b;
                                                                  }
                                                              }
                                                              /*
                                                               * @title Solidity Bytes Arrays Utils
                                                               * @author Gonçalo Sá <[email protected]>
                                                               *
                                                               * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
                                                               *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
                                                               */
                                                              pragma solidity ^0.4.19;
                                                              library BytesLib {
                                                                  function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes) {
                                                                      bytes memory tempBytes;
                                                                      assembly {
                                                                          // Get a location of some free memory and store it in tempBytes as
                                                                          // Solidity does for memory variables.
                                                                          tempBytes := mload(0x40)
                                                                          // Store the length of the first bytes array at the beginning of
                                                                          // the memory for tempBytes.
                                                                          let length := mload(_preBytes)
                                                                          mstore(tempBytes, length)
                                                                          // Maintain a memory counter for the current write location in the
                                                                          // temp bytes array by adding the 32 bytes for the array length to
                                                                          // the starting location.
                                                                          let mc := add(tempBytes, 0x20)
                                                                          // Stop copying when the memory counter reaches the length of the
                                                                          // first bytes array.
                                                                          let end := add(mc, length)
                                                                          for {
                                                                              // Initialize a copy counter to the start of the _preBytes data,
                                                                              // 32 bytes into its memory.
                                                                              let cc := add(_preBytes, 0x20)
                                                                          } lt(mc, end) {
                                                                              // Increase both counters by 32 bytes each iteration.
                                                                              mc := add(mc, 0x20)
                                                                              cc := add(cc, 0x20)
                                                                          } {
                                                                              // Write the _preBytes data into the tempBytes memory 32 bytes
                                                                              // at a time.
                                                                              mstore(mc, mload(cc))
                                                                          }
                                                                          // Add the length of _postBytes to the current length of tempBytes
                                                                          // and store it as the new length in the first 32 bytes of the
                                                                          // tempBytes memory.
                                                                          length := mload(_postBytes)
                                                                          mstore(tempBytes, add(length, mload(tempBytes)))
                                                                          // Move the memory counter back from a multiple of 0x20 to the
                                                                          // actual end of the _preBytes data.
                                                                          mc := end
                                                                          // Stop copying when the memory counter reaches the new combined
                                                                          // length of the arrays.
                                                                          end := add(mc, length)
                                                                          for {
                                                                              let cc := add(_postBytes, 0x20)
                                                                          } lt(mc, end) {
                                                                              mc := add(mc, 0x20)
                                                                              cc := add(cc, 0x20)
                                                                          } {
                                                                              mstore(mc, mload(cc))
                                                                          }
                                                                          // Update the free-memory pointer by padding our last write location
                                                                          // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
                                                                          // next 32 byte block, then round down to the nearest multiple of
                                                                          // 32. If the sum of the length of the two arrays is zero then add 
                                                                          // one before rounding down to leave a blank 32 bytes (the length block with 0).
                                                                          mstore(0x40, and(
                                                                            add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                                                                            not(31) // Round down to the nearest 32 bytes.
                                                                          ))
                                                                      }
                                                                      return tempBytes;
                                                                  }
                                                                  function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
                                                                      assembly {
                                                                          // Read the first 32 bytes of _preBytes storage, which is the length
                                                                          // of the array. (We don't need to use the offset into the slot
                                                                          // because arrays use the entire slot.)
                                                                          let fslot := sload(_preBytes_slot)
                                                                          // Arrays of 31 bytes or less have an even value in their slot,
                                                                          // while longer arrays have an odd value. The actual length is
                                                                          // the slot divided by two for odd values, and the lowest order
                                                                          // byte divided by two for even values.
                                                                          // If the slot is even, bitwise and the slot with 255 and divide by
                                                                          // two to get the length. If the slot is odd, bitwise and the slot
                                                                          // with -1 and divide by two.
                                                                          let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                                                                          let mlength := mload(_postBytes)
                                                                          let newlength := add(slength, mlength)
                                                                          // slength can contain both the length and contents of the array
                                                                          // if length < 32 bytes so let's prepare for that
                                                                          // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                                                                          switch add(lt(slength, 32), lt(newlength, 32))
                                                                          case 2 {
                                                                              // Since the new array still fits in the slot, we just need to
                                                                              // update the contents of the slot.
                                                                              // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                                                                              sstore(
                                                                                  _preBytes_slot,
                                                                                  // all the modifications to the slot are inside this
                                                                                  // next block
                                                                                  add(
                                                                                      // we can just add to the slot contents because the
                                                                                      // bytes we want to change are the LSBs
                                                                                      fslot,
                                                                                      add(
                                                                                          mul(
                                                                                              div(
                                                                                                  // load the bytes from memory
                                                                                                  mload(add(_postBytes, 0x20)),
                                                                                                  // zero all bytes to the right
                                                                                                  exp(0x100, sub(32, mlength))
                                                                                              ),
                                                                                              // and now shift left the number of bytes to
                                                                                              // leave space for the length in the slot
                                                                                              exp(0x100, sub(32, newlength))
                                                                                          ),
                                                                                          // increase length by the double of the memory
                                                                                          // bytes length
                                                                                          mul(mlength, 2)
                                                                                      )
                                                                                  )
                                                                              )
                                                                          }
                                                                          case 1 {
                                                                              // The stored value fits in the slot, but the combined value
                                                                              // will exceed it.
                                                                              // get the keccak hash to get the contents of the array
                                                                              mstore(0x0, _preBytes_slot)
                                                                              let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                                                                              // save new length
                                                                              sstore(_preBytes_slot, add(mul(newlength, 2), 1))
                                                                              // The contents of the _postBytes array start 32 bytes into
                                                                              // the structure. Our first read should obtain the `submod`
                                                                              // bytes that can fit into the unused space in the last word
                                                                              // of the stored array. To get this, we read 32 bytes starting
                                                                              // from `submod`, so the data we read overlaps with the array
                                                                              // contents by `submod` bytes. Masking the lowest-order
                                                                              // `submod` bytes allows us to add that value directly to the
                                                                              // stored value.
                                                                              let submod := sub(32, slength)
                                                                              let mc := add(_postBytes, submod)
                                                                              let end := add(_postBytes, mlength)
                                                                              let mask := sub(exp(0x100, submod), 1)
                                                                              sstore(
                                                                                  sc,
                                                                                  add(
                                                                                      and(
                                                                                          fslot,
                                                                                          0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                                                                                      ),
                                                                                      and(mload(mc), mask)
                                                                                  )
                                                                              )
                                                                              for {
                                                                                  mc := add(mc, 0x20)
                                                                                  sc := add(sc, 1)
                                                                              } lt(mc, end) {
                                                                                  sc := add(sc, 1)
                                                                                  mc := add(mc, 0x20)
                                                                              } {
                                                                                  sstore(sc, mload(mc))
                                                                              }
                                                                              mask := exp(0x100, sub(mc, end))
                                                                              sstore(sc, mul(div(mload(mc), mask), mask))
                                                                          }
                                                                          default {
                                                                              // get the keccak hash to get the contents of the array
                                                                              mstore(0x0, _preBytes_slot)
                                                                              // Start copying to the last used word of the stored array.
                                                                              let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                                                                              // save new length
                                                                              sstore(_preBytes_slot, add(mul(newlength, 2), 1))
                                                                              // Copy over the first `submod` bytes of the new data as in
                                                                              // case 1 above.
                                                                              let slengthmod := mod(slength, 32)
                                                                              let mlengthmod := mod(mlength, 32)
                                                                              let submod := sub(32, slengthmod)
                                                                              let mc := add(_postBytes, submod)
                                                                              let end := add(_postBytes, mlength)
                                                                              let mask := sub(exp(0x100, submod), 1)
                                                                              sstore(sc, add(sload(sc), and(mload(mc), mask)))
                                                                              
                                                                              for { 
                                                                                  sc := add(sc, 1)
                                                                                  mc := add(mc, 0x20)
                                                                              } lt(mc, end) {
                                                                                  sc := add(sc, 1)
                                                                                  mc := add(mc, 0x20)
                                                                              } {
                                                                                  sstore(sc, mload(mc))
                                                                              }
                                                                              mask := exp(0x100, sub(mc, end))
                                                                              sstore(sc, mul(div(mload(mc), mask), mask))
                                                                          }
                                                                      }
                                                                  }
                                                                  function slice(bytes _bytes, uint _start, uint _length) internal  pure returns (bytes) {
                                                                      require(_bytes.length >= (_start + _length));
                                                                      bytes memory tempBytes;
                                                                      assembly {
                                                                          switch iszero(_length)
                                                                          case 0 {
                                                                              // Get a location of some free memory and store it in tempBytes as
                                                                              // Solidity does for memory variables.
                                                                              tempBytes := mload(0x40)
                                                                              // The first word of the slice result is potentially a partial
                                                                              // word read from the original array. To read it, we calculate
                                                                              // the length of that partial word and start copying that many
                                                                              // bytes into the array. The first word we copy will start with
                                                                              // data we don't care about, but the last `lengthmod` bytes will
                                                                              // land at the beginning of the contents of the new array. When
                                                                              // we're done copying, we overwrite the full first word with
                                                                              // the actual length of the slice.
                                                                              let lengthmod := and(_length, 31)
                                                                              // The multiplication in the next line is necessary
                                                                              // because when slicing multiples of 32 bytes (lengthmod == 0)
                                                                              // the following copy loop was copying the origin's length
                                                                              // and then ending prematurely not copying everything it should.
                                                                              let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                                                                              let end := add(mc, _length)
                                                                              for {
                                                                                  // The multiplication in the next line has the same exact purpose
                                                                                  // as the one above.
                                                                                  let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                                                                              } lt(mc, end) {
                                                                                  mc := add(mc, 0x20)
                                                                                  cc := add(cc, 0x20)
                                                                              } {
                                                                                  mstore(mc, mload(cc))
                                                                              }
                                                                              mstore(tempBytes, _length)
                                                                              //update free-memory pointer
                                                                              //allocating the array padded to 32 bytes like the compiler does now
                                                                              mstore(0x40, and(add(mc, 31), not(31)))
                                                                          }
                                                                          //if we want a zero-length slice let's just return a zero-length array
                                                                          default {
                                                                              tempBytes := mload(0x40)
                                                                              mstore(0x40, add(tempBytes, 0x20))
                                                                          }
                                                                      }
                                                                      return tempBytes;
                                                                  }
                                                                  function toAddress(bytes _bytes, uint _start) internal  pure returns (address) {
                                                                      require(_bytes.length >= (_start + 20));
                                                                      address tempAddress;
                                                                      assembly {
                                                                          tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
                                                                      }
                                                                      return tempAddress;
                                                                  }
                                                                  function toUint8(bytes _bytes, uint _start) internal  pure returns (uint8) {
                                                                      require(_bytes.length >= (_start + 1));
                                                                      uint8 tempUint;
                                                                      assembly {
                                                                          tempUint := mload(add(add(_bytes, 0x1), _start))
                                                                      }
                                                                      return tempUint;
                                                                  }
                                                                  function toUint16(bytes _bytes, uint _start) internal  pure returns (uint16) {
                                                                      require(_bytes.length >= (_start + 2));
                                                                      uint16 tempUint;
                                                                      assembly {
                                                                          tempUint := mload(add(add(_bytes, 0x2), _start))
                                                                      }
                                                                      return tempUint;
                                                                  }
                                                                  function toUint32(bytes _bytes, uint _start) internal  pure returns (uint32) {
                                                                      require(_bytes.length >= (_start + 4));
                                                                      uint32 tempUint;
                                                                      assembly {
                                                                          tempUint := mload(add(add(_bytes, 0x4), _start))
                                                                      }
                                                                      return tempUint;
                                                                  }
                                                                  function toUint(bytes _bytes, uint _start) internal  pure returns (uint256) {
                                                                      require(_bytes.length >= (_start + 32));
                                                                      uint256 tempUint;
                                                                      assembly {
                                                                          tempUint := mload(add(add(_bytes, 0x20), _start))
                                                                      }
                                                                      return tempUint;
                                                                  }
                                                                  function toBytes32(bytes _bytes, uint _start) internal  pure returns (bytes32) {
                                                                      require(_bytes.length >= (_start + 32));
                                                                      bytes32 tempBytes32;
                                                                      assembly {
                                                                          tempBytes32 := mload(add(add(_bytes, 0x20), _start))
                                                                      }
                                                                      return tempBytes32;
                                                                  }
                                                                  function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
                                                                      bool success = true;
                                                                      assembly {
                                                                          let length := mload(_preBytes)
                                                                          // if lengths don't match the arrays are not equal
                                                                          switch eq(length, mload(_postBytes))
                                                                          case 1 {
                                                                              // cb is a circuit breaker in the for loop since there's
                                                                              //  no said feature for inline assembly loops
                                                                              // cb = 1 - don't breaker
                                                                              // cb = 0 - break
                                                                              let cb := 1
                                                                              let mc := add(_preBytes, 0x20)
                                                                              let end := add(mc, length)
                                                                              for {
                                                                                  let cc := add(_postBytes, 0x20)
                                                                              // the next line is the loop condition:
                                                                              // while(uint(mc < end) + cb == 2)
                                                                              } eq(add(lt(mc, end), cb), 2) {
                                                                                  mc := add(mc, 0x20)
                                                                                  cc := add(cc, 0x20)
                                                                              } {
                                                                                  // if any of these checks fails then arrays are not equal
                                                                                  if iszero(eq(mload(mc), mload(cc))) {
                                                                                      // unsuccess:
                                                                                      success := 0
                                                                                      cb := 0
                                                                                  }
                                                                              }
                                                                          }
                                                                          default {
                                                                              // unsuccess:
                                                                              success := 0
                                                                          }
                                                                      }
                                                                      return success;
                                                                  }
                                                                  function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
                                                                      bool success = true;
                                                                      assembly {
                                                                          // we know _preBytes_offset is 0
                                                                          let fslot := sload(_preBytes_slot)
                                                                          // Decode the length of the stored array like in concatStorage().
                                                                          let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                                                                          let mlength := mload(_postBytes)
                                                                          // if lengths don't match the arrays are not equal
                                                                          switch eq(slength, mlength)
                                                                          case 1 {
                                                                              // slength can contain both the length and contents of the array
                                                                              // if length < 32 bytes so let's prepare for that
                                                                              // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                                                                              if iszero(iszero(slength)) {
                                                                                  switch lt(slength, 32)
                                                                                  case 1 {
                                                                                      // blank the last byte which is the length
                                                                                      fslot := mul(div(fslot, 0x100), 0x100)
                                                                                      if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                                                                                          // unsuccess:
                                                                                          success := 0
                                                                                      }
                                                                                  }
                                                                                  default {
                                                                                      // cb is a circuit breaker in the for loop since there's
                                                                                      //  no said feature for inline assembly loops
                                                                                      // cb = 1 - don't breaker
                                                                                      // cb = 0 - break
                                                                                      let cb := 1
                                                                                      // get the keccak hash to get the contents of the array
                                                                                      mstore(0x0, _preBytes_slot)
                                                                                      let sc := keccak256(0x0, 0x20)
                                                                                      let mc := add(_postBytes, 0x20)
                                                                                      let end := add(mc, mlength)
                                                                                      // the next line is the loop condition:
                                                                                      // while(uint(mc < end) + cb == 2)
                                                                                      for {} eq(add(lt(mc, end), cb), 2) {
                                                                                          sc := add(sc, 1)
                                                                                          mc := add(mc, 0x20)
                                                                                      } {
                                                                                          if iszero(eq(sload(sc), mload(mc))) {
                                                                                              // unsuccess:
                                                                                              success := 0
                                                                                              cb := 0
                                                                                          }
                                                                                      }
                                                                                  }
                                                                              }
                                                                          }
                                                                          default {
                                                                              // unsuccess:
                                                                              success := 0
                                                                          }
                                                                      }
                                                                      return success;
                                                                  }
                                                              }
                                                              // SPDX-FileCopyrightText: 2020 Lido <[email protected]>
                                                              // SPDX-License-Identifier: GPL-3.0
                                                              /* See contracts/COMPILERS.md */
                                                              pragma solidity 0.4.24;
                                                              library MemUtils {
                                                                  /**
                                                                   * @dev Allocates a memory byte array of `_len` bytes without zeroing it out.
                                                                   */
                                                                  function unsafeAllocateBytes(uint256 _len) internal pure returns (bytes memory result) {
                                                                      assembly {
                                                                          result := mload(0x40)
                                                                          mstore(result, _len)
                                                                          mstore(0x40, add(add(result, _len), 32))
                                                                      }
                                                                  }
                                                                  /**
                                                                   * Performs a memory copy of `_len` bytes from position `_src` to position `_dst`.
                                                                   */
                                                                  function memcpy(uint256 _src, uint256 _dst, uint256 _len) internal pure {
                                                                      assembly {
                                                                          // while al least 32 bytes left, copy in 32-byte chunks
                                                                          for { } gt(_len, 31) { } {
                                                                              mstore(_dst, mload(_src))
                                                                              _src := add(_src, 32)
                                                                              _dst := add(_dst, 32)
                                                                              _len := sub(_len, 32)
                                                                          }
                                                                          if gt(_len, 0) {
                                                                              // read the next 32-byte chunk from _dst, replace the first N bytes
                                                                              // with those left in the _src, and write the transformed chunk back
                                                                              let mask := sub(shl(1, mul(8, sub(32, _len))), 1) // 2 ** (8 * (32 - _len)) - 1
                                                                              let srcMasked := and(mload(_src), not(mask))
                                                                              let dstMasked := and(mload(_dst), mask)
                                                                              mstore(_dst, or(dstMasked, srcMasked))
                                                                          }
                                                                      }
                                                                  }
                                                                  /**
                                                                   * Copies bytes from `_src` to `_dst`, starting at position `_dstStart` into `_dst`.
                                                                   */
                                                                  function copyBytes(bytes memory _src, bytes memory _dst, uint256 _dstStart) internal pure {
                                                                      require(_dstStart + _src.length <= _dst.length, "BYTES_ARRAY_OUT_OF_BOUNDS");
                                                                      uint256 srcStartPos;
                                                                      uint256 dstStartPos;
                                                                      assembly {
                                                                          srcStartPos := add(_src, 32)
                                                                          dstStartPos := add(add(_dst, 32), _dstStart)
                                                                      }
                                                                      memcpy(srcStartPos, dstStartPos, _src.length);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "../common/UnstructuredStorage.sol";
                                                              import "../kernel/IKernel.sol";
                                                              contract AppStorage {
                                                                  using UnstructuredStorage for bytes32;
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
                                                                  bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
                                                                  */
                                                                  bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
                                                                  bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
                                                                  function kernel() public view returns (IKernel) {
                                                                      return IKernel(KERNEL_POSITION.getStorageAddress());
                                                                  }
                                                                  function appId() public view returns (bytes32) {
                                                                      return APP_ID_POSITION.getStorageBytes32();
                                                                  }
                                                                  function setKernel(IKernel _kernel) internal {
                                                                      KERNEL_POSITION.setStorageAddress(address(_kernel));
                                                                  }
                                                                  function setAppId(bytes32 _appId) internal {
                                                                      APP_ID_POSITION.setStorageBytes32(_appId);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              contract ACLSyntaxSugar {
                                                                  function arr() internal pure returns (uint256[]) {
                                                                      return new uint256[](0);
                                                                  }
                                                                  function arr(bytes32 _a) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a));
                                                                  }
                                                                  function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                                  function arr(address _a) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a));
                                                                  }
                                                                  function arr(address _a, address _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                                  function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), _b, _c);
                                                                  }
                                                                  function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), _b, _c, _d);
                                                                  }
                                                                  function arr(address _a, uint256 _b) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b));
                                                                  }
                                                                  function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), _c, _d, _e);
                                                                  }
                                                                  function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), uint256(_c));
                                                                  }
                                                                  function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      return arr(uint256(_a), uint256(_b), uint256(_c));
                                                                  }
                                                                  function arr(uint256 _a) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](1);
                                                                      r[0] = _a;
                                                                  }
                                                                  function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](2);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                  }
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](3);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                  }
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](4);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                      r[3] = _d;
                                                                  }
                                                                  function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
                                                                      r = new uint256[](5);
                                                                      r[0] = _a;
                                                                      r[1] = _b;
                                                                      r[2] = _c;
                                                                      r[3] = _d;
                                                                      r[4] = _e;
                                                                  }
                                                              }
                                                              contract ACLHelpers {
                                                                  function decodeParamOp(uint256 _x) internal pure returns (uint8 b) {
                                                                      return uint8(_x >> (8 * 30));
                                                                  }
                                                                  function decodeParamId(uint256 _x) internal pure returns (uint8 b) {
                                                                      return uint8(_x >> (8 * 31));
                                                                  }
                                                                  function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) {
                                                                      a = uint32(_x);
                                                                      b = uint32(_x >> (8 * 4));
                                                                      c = uint32(_x >> (8 * 8));
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./Petrifiable.sol";
                                                              contract Autopetrified is Petrifiable {
                                                                  constructor() public {
                                                                      // Immediately petrify base (non-proxy) instances of inherited contracts on deploy.
                                                                      // This renders them uninitializable (and unusable without a proxy).
                                                                      petrify();
                                                                  }
                                                              }
                                                              pragma solidity ^0.4.24;
                                                              library ConversionHelpers {
                                                                  string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH";
                                                                  function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) {
                                                                      // Force cast the uint256[] into a bytes array, by overwriting its length
                                                                      // Note that the bytes array doesn't need to be initialized as we immediately overwrite it
                                                                      // with the input and a new length. The input becomes invalid from this point forward.
                                                                      uint256 byteLength = _input.length * 32;
                                                                      assembly {
                                                                          output := _input
                                                                          mstore(output, byteLength)
                                                                      }
                                                                  }
                                                                  function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) {
                                                                      // Force cast the bytes array into a uint256[], by overwriting its length
                                                                      // Note that the uint256[] doesn't need to be initialized as we immediately overwrite it
                                                                      // with the input and a new length. The input becomes invalid from this point forward.
                                                                      uint256 intsLength = _input.length / 32;
                                                                      require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH);
                                                                      assembly {
                                                                          output := _input
                                                                          mstore(output, intsLength)
                                                                      }
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "../common/UnstructuredStorage.sol";
                                                              contract ReentrancyGuard {
                                                                  using UnstructuredStorage for bytes32;
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant REENTRANCY_MUTEX_POSITION = keccak256("aragonOS.reentrancyGuard.mutex");
                                                                  */
                                                                  bytes32 private constant REENTRANCY_MUTEX_POSITION = 0xe855346402235fdd185c890e68d2c4ecad599b88587635ee285bce2fda58dacb;
                                                                  string private constant ERROR_REENTRANT = "REENTRANCY_REENTRANT_CALL";
                                                                  modifier nonReentrant() {
                                                                      // Ensure mutex is unlocked
                                                                      require(!REENTRANCY_MUTEX_POSITION.getStorageBool(), ERROR_REENTRANT);
                                                                      // Lock mutex before function call
                                                                      REENTRANCY_MUTEX_POSITION.setStorageBool(true);
                                                                      // Perform function call
                                                                      _;
                                                                      // Unlock mutex after function call
                                                                      REENTRANCY_MUTEX_POSITION.setStorageBool(false);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "../lib/token/ERC20.sol";
                                                              import "./EtherTokenConstant.sol";
                                                              import "./IsContract.sol";
                                                              import "./IVaultRecoverable.sol";
                                                              import "./SafeERC20.sol";
                                                              contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract {
                                                                  using SafeERC20 for ERC20;
                                                                  string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED";
                                                                  string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT";
                                                                  string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED";
                                                                  /**
                                                                   * @notice Send funds to recovery Vault. This contract should never receive funds,
                                                                   *         but in case it does, this function allows one to recover them.
                                                                   * @param _token Token balance to be sent to recovery vault.
                                                                   */
                                                                  function transferToVault(address _token) external {
                                                                      require(allowRecoverability(_token), ERROR_DISALLOWED);
                                                                      address vault = getRecoveryVault();
                                                                      require(isContract(vault), ERROR_VAULT_NOT_CONTRACT);
                                                                      uint256 balance;
                                                                      if (_token == ETH) {
                                                                          balance = address(this).balance;
                                                                          vault.transfer(balance);
                                                                      } else {
                                                                          ERC20 token = ERC20(_token);
                                                                          balance = token.staticBalanceOf(this);
                                                                          require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED);
                                                                      }
                                                                      emit RecoverToVault(vault, _token, balance);
                                                                  }
                                                                  /**
                                                                  * @dev By default deriving from AragonApp makes it recoverable
                                                                  * @param token Token address that would be recovered
                                                                  * @return bool whether the app allows the recovery
                                                                  */
                                                                  function allowRecoverability(address token) public view returns (bool) {
                                                                      return true;
                                                                  }
                                                                  // Cast non-implemented interface to be public so we can use it internally
                                                                  function getRecoveryVault() public view returns (address);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./IEVMScriptExecutor.sol";
                                                              import "./IEVMScriptRegistry.sol";
                                                              import "../apps/AppStorage.sol";
                                                              import "../kernel/KernelConstants.sol";
                                                              import "../common/Initializable.sol";
                                                              contract EVMScriptRunner is AppStorage, Initializable, EVMScriptRegistryConstants, KernelNamespaceConstants {
                                                                  string private constant ERROR_EXECUTOR_UNAVAILABLE = "EVMRUN_EXECUTOR_UNAVAILABLE";
                                                                  string private constant ERROR_PROTECTED_STATE_MODIFIED = "EVMRUN_PROTECTED_STATE_MODIFIED";
                                                                  /* This is manually crafted in assembly
                                                                  string private constant ERROR_EXECUTOR_INVALID_RETURN = "EVMRUN_EXECUTOR_INVALID_RETURN";
                                                                  */
                                                                  event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData);
                                                                  function getEVMScriptExecutor(bytes _script) public view returns (IEVMScriptExecutor) {
                                                                      return IEVMScriptExecutor(getEVMScriptRegistry().getScriptExecutor(_script));
                                                                  }
                                                                  function getEVMScriptRegistry() public view returns (IEVMScriptRegistry) {
                                                                      address registryAddr = kernel().getApp(KERNEL_APP_ADDR_NAMESPACE, EVMSCRIPT_REGISTRY_APP_ID);
                                                                      return IEVMScriptRegistry(registryAddr);
                                                                  }
                                                                  function runScript(bytes _script, bytes _input, address[] _blacklist)
                                                                      internal
                                                                      isInitialized
                                                                      protectState
                                                                      returns (bytes)
                                                                  {
                                                                      IEVMScriptExecutor executor = getEVMScriptExecutor(_script);
                                                                      require(address(executor) != address(0), ERROR_EXECUTOR_UNAVAILABLE);
                                                                      bytes4 sig = executor.execScript.selector;
                                                                      bytes memory data = abi.encodeWithSelector(sig, _script, _input, _blacklist);
                                                                      bytes memory output;
                                                                      assembly {
                                                                          let success := delegatecall(
                                                                              gas,                // forward all gas
                                                                              executor,           // address
                                                                              add(data, 0x20),    // calldata start
                                                                              mload(data),        // calldata length
                                                                              0,                  // don't write output (we'll handle this ourselves)
                                                                              0                   // don't write output
                                                                          )
                                                                          output := mload(0x40) // free mem ptr get
                                                                          switch success
                                                                          case 0 {
                                                                              // If the call errored, forward its full error data
                                                                              returndatacopy(output, 0, returndatasize)
                                                                              revert(output, returndatasize)
                                                                          }
                                                                          default {
                                                                              switch gt(returndatasize, 0x3f)
                                                                              case 0 {
                                                                                  // Need at least 0x40 bytes returned for properly ABI-encoded bytes values,
                                                                                  // revert with "EVMRUN_EXECUTOR_INVALID_RETURN"
                                                                                  // See remix: doing a `revert("EVMRUN_EXECUTOR_INVALID_RETURN")` always results in
                                                                                  // this memory layout
                                                                                  mstore(output, 0x08c379a000000000000000000000000000000000000000000000000000000000)         // error identifier
                                                                                  mstore(add(output, 0x04), 0x0000000000000000000000000000000000000000000000000000000000000020) // starting offset
                                                                                  mstore(add(output, 0x24), 0x000000000000000000000000000000000000000000000000000000000000001e) // reason length
                                                                                  mstore(add(output, 0x44), 0x45564d52554e5f4558454355544f525f494e56414c49445f52455455524e0000) // reason
                                                                                  revert(output, 100) // 100 = 4 + 3 * 32 (error identifier + 3 words for the ABI encoded error)
                                                                              }
                                                                              default {
                                                                                  // Copy result
                                                                                  //
                                                                                  // Needs to perform an ABI decode for the expected `bytes` return type of
                                                                                  // `executor.execScript()` as solidity will automatically ABI encode the returned bytes as:
                                                                                  //    [ position of the first dynamic length return value = 0x20 (32 bytes) ]
                                                                                  //    [ output length (32 bytes) ]
                                                                                  //    [ output content (N bytes) ]
                                                                                  //
                                                                                  // Perform the ABI decode by ignoring the first 32 bytes of the return data
                                                                                  let copysize := sub(returndatasize, 0x20)
                                                                                  returndatacopy(output, 0x20, copysize)
                                                                                  mstore(0x40, add(output, copysize)) // free mem ptr set
                                                                              }
                                                                          }
                                                                      }
                                                                      emit ScriptResult(address(executor), _script, _input, output);
                                                                      return output;
                                                                  }
                                                                  modifier protectState {
                                                                      address preKernel = address(kernel());
                                                                      bytes32 preAppId = appId();
                                                                      _; // exec
                                                                      require(address(kernel()) == preKernel, ERROR_PROTECTED_STATE_MODIFIED);
                                                                      require(appId() == preAppId, ERROR_PROTECTED_STATE_MODIFIED);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              library UnstructuredStorage {
                                                                  function getStorageBool(bytes32 position) internal view returns (bool data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                                  function getStorageAddress(bytes32 position) internal view returns (address data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                                  function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                                  function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
                                                                      assembly { data := sload(position) }
                                                                  }
                                                                  function setStorageBool(bytes32 position, bool data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                                  function setStorageAddress(bytes32 position, address data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                                  function setStorageBytes32(bytes32 position, bytes32 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                                  function setStorageUint256(bytes32 position, uint256 data) internal {
                                                                      assembly { sstore(position, data) }
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "../acl/IACL.sol";
                                                              import "../common/IVaultRecoverable.sol";
                                                              interface IKernelEvents {
                                                                  event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
                                                              }
                                                              // This should be an interface, but interfaces can't inherit yet :(
                                                              contract IKernel is IKernelEvents, IVaultRecoverable {
                                                                  function acl() public view returns (IACL);
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                                  function setApp(bytes32 namespace, bytes32 appId, address app) public;
                                                                  function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              interface IACL {
                                                                  function initialize(address permissionsCreator) external;
                                                                  // TODO: this should be external
                                                                  // See https://github.com/ethereum/solidity/issues/4832
                                                                  function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              interface IVaultRecoverable {
                                                                  event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
                                                                  function transferToVault(address token) external;
                                                                  function allowRecoverability(address token) external view returns (bool);
                                                                  function getRecoveryVault() external view returns (address);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./Initializable.sol";
                                                              contract Petrifiable is Initializable {
                                                                  // Use block UINT256_MAX (which should be never) as the initializable date
                                                                  uint256 internal constant PETRIFIED_BLOCK = uint256(-1);
                                                                  function isPetrified() public view returns (bool) {
                                                                      return getInitializationBlock() == PETRIFIED_BLOCK;
                                                                  }
                                                                  /**
                                                                  * @dev Function to be called by top level contract to prevent being initialized.
                                                                  *      Useful for freezing base contracts when they're used behind proxies.
                                                                  */
                                                                  function petrify() internal onlyInit {
                                                                      initializedAt(PETRIFIED_BLOCK);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./TimeHelpers.sol";
                                                              import "./UnstructuredStorage.sol";
                                                              contract Initializable is TimeHelpers {
                                                                  using UnstructuredStorage for bytes32;
                                                                  // keccak256("aragonOS.initializable.initializationBlock")
                                                                  bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e;
                                                                  string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED";
                                                                  string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED";
                                                                  modifier onlyInit {
                                                                      require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED);
                                                                      _;
                                                                  }
                                                                  modifier isInitialized {
                                                                      require(hasInitialized(), ERROR_NOT_INITIALIZED);
                                                                      _;
                                                                  }
                                                                  /**
                                                                  * @return Block number in which the contract was initialized
                                                                  */
                                                                  function getInitializationBlock() public view returns (uint256) {
                                                                      return INITIALIZATION_BLOCK_POSITION.getStorageUint256();
                                                                  }
                                                                  /**
                                                                  * @return Whether the contract has been initialized by the time of the current block
                                                                  */
                                                                  function hasInitialized() public view returns (bool) {
                                                                      uint256 initializationBlock = getInitializationBlock();
                                                                      return initializationBlock != 0 && getBlockNumber() >= initializationBlock;
                                                                  }
                                                                  /**
                                                                  * @dev Function to be called by top level contract after initialization has finished.
                                                                  */
                                                                  function initialized() internal onlyInit {
                                                                      INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber());
                                                                  }
                                                                  /**
                                                                  * @dev Function to be called by top level contract after initialization to enable the contract
                                                                  *      at a future block number rather than immediately.
                                                                  */
                                                                  function initializedAt(uint256 _blockNumber) internal onlyInit {
                                                                      INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber);
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./Uint256Helpers.sol";
                                                              contract TimeHelpers {
                                                                  using Uint256Helpers for uint256;
                                                                  /**
                                                                  * @dev Returns the current block number.
                                                                  *      Using a function rather than `block.number` allows us to easily mock the block number in
                                                                  *      tests.
                                                                  */
                                                                  function getBlockNumber() internal view returns (uint256) {
                                                                      return block.number;
                                                                  }
                                                                  /**
                                                                  * @dev Returns the current block number, converted to uint64.
                                                                  *      Using a function rather than `block.number` allows us to easily mock the block number in
                                                                  *      tests.
                                                                  */
                                                                  function getBlockNumber64() internal view returns (uint64) {
                                                                      return getBlockNumber().toUint64();
                                                                  }
                                                                  /**
                                                                  * @dev Returns the current timestamp.
                                                                  *      Using a function rather than `block.timestamp` allows us to easily mock it in
                                                                  *      tests.
                                                                  */
                                                                  function getTimestamp() internal view returns (uint256) {
                                                                      return block.timestamp; // solium-disable-line security/no-block-members
                                                                  }
                                                                  /**
                                                                  * @dev Returns the current timestamp, converted to uint64.
                                                                  *      Using a function rather than `block.timestamp` allows us to easily mock it in
                                                                  *      tests.
                                                                  */
                                                                  function getTimestamp64() internal view returns (uint64) {
                                                                      return getTimestamp().toUint64();
                                                                  }
                                                              }
                                                              pragma solidity ^0.4.24;
                                                              library Uint256Helpers {
                                                                  uint256 private constant MAX_UINT64 = uint64(-1);
                                                                  string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG";
                                                                  function toUint64(uint256 a) internal pure returns (uint64) {
                                                                      require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG);
                                                                      return uint64(a);
                                                                  }
                                                              }
                                                              // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol
                                                              pragma solidity ^0.4.24;
                                                              /**
                                                               * @title ERC20 interface
                                                               * @dev see https://github.com/ethereum/EIPs/issues/20
                                                               */
                                                              contract ERC20 {
                                                                  function totalSupply() public view returns (uint256);
                                                                  function balanceOf(address _who) public view returns (uint256);
                                                                  function allowance(address _owner, address _spender)
                                                                      public view returns (uint256);
                                                                  function transfer(address _to, uint256 _value) public returns (bool);
                                                                  function approve(address _spender, uint256 _value)
                                                                      public returns (bool);
                                                                  function transferFrom(address _from, address _to, uint256 _value)
                                                                      public returns (bool);
                                                                  event Transfer(
                                                                      address indexed from,
                                                                      address indexed to,
                                                                      uint256 value
                                                                  );
                                                                  event Approval(
                                                                      address indexed owner,
                                                                      address indexed spender,
                                                                      uint256 value
                                                                  );
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              // aragonOS and aragon-apps rely on address(0) to denote native ETH, in
                                                              // contracts where both tokens and ETH are accepted
                                                              contract EtherTokenConstant {
                                                                  address internal constant ETH = address(0);
                                                              }
                                                              // Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol)
                                                              // and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143)
                                                              pragma solidity ^0.4.24;
                                                              import "../lib/token/ERC20.sol";
                                                              library SafeERC20 {
                                                                  // Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`:
                                                                  // https://github.com/ethereum/solidity/issues/3544
                                                                  bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb;
                                                                  string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED";
                                                                  string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED";
                                                                  function invokeAndCheckSuccess(address _addr, bytes memory _calldata)
                                                                      private
                                                                      returns (bool)
                                                                  {
                                                                      bool ret;
                                                                      assembly {
                                                                          let ptr := mload(0x40)    // free memory pointer
                                                                          let success := call(
                                                                              gas,                  // forward all gas
                                                                              _addr,                // address
                                                                              0,                    // no value
                                                                              add(_calldata, 0x20), // calldata start
                                                                              mload(_calldata),     // calldata length
                                                                              ptr,                  // write output over free memory
                                                                              0x20                  // uint256 return
                                                                          )
                                                                          if gt(success, 0) {
                                                                              // Check number of bytes returned from last function call
                                                                              switch returndatasize
                                                                              // No bytes returned: assume success
                                                                              case 0 {
                                                                                  ret := 1
                                                                              }
                                                                              // 32 bytes returned: check if non-zero
                                                                              case 0x20 {
                                                                                  // Only return success if returned data was true
                                                                                  // Already have output in ptr
                                                                                  ret := eq(mload(ptr), 1)
                                                                              }
                                                                              // Not sure what was returned: don't mark as success
                                                                              default { }
                                                                          }
                                                                      }
                                                                      return ret;
                                                                  }
                                                                  function staticInvoke(address _addr, bytes memory _calldata)
                                                                      private
                                                                      view
                                                                      returns (bool, uint256)
                                                                  {
                                                                      bool success;
                                                                      uint256 ret;
                                                                      assembly {
                                                                          let ptr := mload(0x40)    // free memory pointer
                                                                          success := staticcall(
                                                                              gas,                  // forward all gas
                                                                              _addr,                // address
                                                                              add(_calldata, 0x20), // calldata start
                                                                              mload(_calldata),     // calldata length
                                                                              ptr,                  // write output over free memory
                                                                              0x20                  // uint256 return
                                                                          )
                                                                          if gt(success, 0) {
                                                                              ret := mload(ptr)
                                                                          }
                                                                      }
                                                                      return (success, ret);
                                                                  }
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) {
                                                                      bytes memory transferCallData = abi.encodeWithSelector(
                                                                          TRANSFER_SELECTOR,
                                                                          _to,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, transferCallData);
                                                                  }
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
                                                                      bytes memory transferFromCallData = abi.encodeWithSelector(
                                                                          _token.transferFrom.selector,
                                                                          _from,
                                                                          _to,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, transferFromCallData);
                                                                  }
                                                                  /**
                                                                  * @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false).
                                                                  *      Note that this makes an external call to the token.
                                                                  */
                                                                  function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) {
                                                                      bytes memory approveCallData = abi.encodeWithSelector(
                                                                          _token.approve.selector,
                                                                          _spender,
                                                                          _amount
                                                                      );
                                                                      return invokeAndCheckSuccess(_token, approveCallData);
                                                                  }
                                                                  /**
                                                                  * @dev Static call into ERC20.balanceOf().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) {
                                                                      bytes memory balanceOfCallData = abi.encodeWithSelector(
                                                                          _token.balanceOf.selector,
                                                                          _owner
                                                                      );
                                                                      (bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData);
                                                                      require(success, ERROR_TOKEN_BALANCE_REVERTED);
                                                                      return tokenBalance;
                                                                  }
                                                                  /**
                                                                  * @dev Static call into ERC20.allowance().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) {
                                                                      bytes memory allowanceCallData = abi.encodeWithSelector(
                                                                          _token.allowance.selector,
                                                                          _owner,
                                                                          _spender
                                                                      );
                                                                      (bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData);
                                                                      require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                                                                      return allowance;
                                                                  }
                                                                  /**
                                                                  * @dev Static call into ERC20.totalSupply().
                                                                  * Reverts if the call fails for some reason (should never fail).
                                                                  */
                                                                  function staticTotalSupply(ERC20 _token) internal view returns (uint256) {
                                                                      bytes memory totalSupplyCallData = abi.encodeWithSelector(_token.totalSupply.selector);
                                                                      (bool success, uint256 totalSupply) = staticInvoke(_token, totalSupplyCallData);
                                                                      require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
                                                                      return totalSupply;
                                                                  }
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              interface IEVMScriptExecutor {
                                                                  function execScript(bytes script, bytes input, address[] blacklist) external returns (bytes);
                                                                  function executorType() external pure returns (bytes32);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              import "./IEVMScriptExecutor.sol";
                                                              contract EVMScriptRegistryConstants {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = apmNamehash("evmreg");
                                                                  */
                                                                  bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = 0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61;
                                                              }
                                                              interface IEVMScriptRegistry {
                                                                  function addScriptExecutor(IEVMScriptExecutor executor) external returns (uint id);
                                                                  function disableScriptExecutor(uint256 executorId) external;
                                                                  // TODO: this should be external
                                                                  // See https://github.com/ethereum/solidity/issues/4832
                                                                  function getScriptExecutor(bytes script) public view returns (IEVMScriptExecutor);
                                                              }
                                                              /*
                                                               * SPDX-License-Identifier:    MIT
                                                               */
                                                              pragma solidity ^0.4.24;
                                                              contract KernelAppIds {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
                                                                  bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
                                                                  bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
                                                              }
                                                              contract KernelNamespaceConstants {
                                                                  /* Hardcoded constants to save gas
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
                                                                  */
                                                                  bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
                                                                  bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
                                                                  bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
                                                              }
                                                              

                                                              File 10 of 14: Keep3rV2Helper
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.8.2;
                                                              
                                                              library Math {
                                                                  function max(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                      return a >= b ? a : b;
                                                                  }
                                                                  function min(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                      return a < b ? a : b;
                                                                  }
                                                              }
                                                              
                                                              interface IChainLinkFeed {
                                                                  function latestAnswer() external view returns (int256);
                                                              }
                                                              
                                                              interface IKeep3rV1 {
                                                                  function totalBonded() external view returns (uint);
                                                                  function bonds(address keeper, address credit) external view returns (uint);
                                                                  function votes(address keeper) external view returns (uint);
                                                              }
                                                              
                                                              interface IKeep3rV2Oracle {
                                                                  function quote(address tokenIn, uint amountIn, address tokenOut, uint points) external view returns (uint amountOut, uint lastUpdatedAgo);
                                                              }
                                                              
                                                              contract Keep3rV2Helper {
                                                              
                                                                  IChainLinkFeed public constant FASTGAS = IChainLinkFeed(0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C);
                                                                  IKeep3rV1 public constant KP3R = IKeep3rV1(0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44);
                                                                  IKeep3rV2Oracle public constant KV2O = IKeep3rV2Oracle(0xe20B3f175F9f4e1EDDf333f96b72Bba138c9e83a);
                                                                  address public constant WETH = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
                                                              
                                                                  uint constant public MIN = 11;
                                                                  uint constant public MAX = 12;
                                                                  uint constant public BASE = 10;
                                                                  uint constant public SWAP = 300000;
                                                                  uint constant public TARGETBOND = 200e18;
                                                                  
                                                                  function quote(uint eth) public view returns (uint amountOut) {
                                                                      (amountOut,) = KV2O.quote(address(WETH), eth, address(KP3R), 1);
                                                                  }
                                                              
                                                                  function getFastGas() external view returns (uint) {
                                                                      return uint(FASTGAS.latestAnswer());
                                                                  }
                                                              
                                                                  function bonds(address keeper) public view returns (uint) {
                                                                      return KP3R.bonds(keeper, address(KP3R)) + (KP3R.votes(keeper));
                                                                  }
                                                              
                                                                  function getQuoteLimitFor(address origin, uint gasUsed) public view returns (uint) {
                                                                      uint _quote = quote((gasUsed+SWAP)*(uint(FASTGAS.latestAnswer())));
                                                                      uint _min = _quote * MIN / BASE;
                                                                      uint _boost = _quote * MAX / BASE;
                                                                      uint _bond = Math.min(bonds(origin), TARGETBOND);
                                                                      return Math.max(_min, _boost * _bond / TARGETBOND);
                                                                  }
                                                              
                                                                  function getQuoteLimit(uint gasUsed) external view returns (uint) {
                                                                      return getQuoteLimitFor(tx.origin, gasUsed);
                                                                  }
                                                              }

                                                              File 11 of 14: EACAggregatorProxy
                                                              pragma solidity 0.6.6;
                                                              
                                                              
                                                              /**
                                                               * @title The Owned contract
                                                               * @notice A contract with helpers for basic contract ownership.
                                                               */
                                                              contract Owned {
                                                              
                                                                address payable public owner;
                                                                address private pendingOwner;
                                                              
                                                                event OwnershipTransferRequested(
                                                                  address indexed from,
                                                                  address indexed to
                                                                );
                                                                event OwnershipTransferred(
                                                                  address indexed from,
                                                                  address indexed to
                                                                );
                                                              
                                                                constructor() public {
                                                                  owner = msg.sender;
                                                                }
                                                              
                                                                /**
                                                                 * @dev Allows an owner to begin transferring ownership to a new address,
                                                                 * pending.
                                                                 */
                                                                function transferOwnership(address _to)
                                                                  external
                                                                  onlyOwner()
                                                                {
                                                                  pendingOwner = _to;
                                                              
                                                                  emit OwnershipTransferRequested(owner, _to);
                                                                }
                                                              
                                                                /**
                                                                 * @dev Allows an ownership transfer to be completed by the recipient.
                                                                 */
                                                                function acceptOwnership()
                                                                  external
                                                                {
                                                                  require(msg.sender == pendingOwner, "Must be proposed owner");
                                                              
                                                                  address oldOwner = owner;
                                                                  owner = msg.sender;
                                                                  pendingOwner = address(0);
                                                              
                                                                  emit OwnershipTransferred(oldOwner, msg.sender);
                                                                }
                                                              
                                                                /**
                                                                 * @dev Reverts if called by anyone other than the contract owner.
                                                                 */
                                                                modifier onlyOwner() {
                                                                  require(msg.sender == owner, "Only callable by owner");
                                                                  _;
                                                                }
                                                              
                                                              }
                                                              
                                                              interface AggregatorInterface {
                                                                function latestAnswer() external view returns (int256);
                                                                function latestTimestamp() external view returns (uint256);
                                                                function latestRound() external view returns (uint256);
                                                                function getAnswer(uint256 roundId) external view returns (int256);
                                                                function getTimestamp(uint256 roundId) external view returns (uint256);
                                                              
                                                                event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
                                                                event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
                                                              }
                                                              
                                                              interface AggregatorV3Interface {
                                                              
                                                                function decimals() external view returns (uint8);
                                                                function description() external view returns (string memory);
                                                                function version() external view returns (uint256);
                                                              
                                                                // getRoundData and latestRoundData should both raise "No data present"
                                                                // if they do not have data to report, instead of returning unset values
                                                                // which could be misinterpreted as actual reported values.
                                                                function getRoundData(uint80 _roundId)
                                                                  external
                                                                  view
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  );
                                                                function latestRoundData()
                                                                  external
                                                                  view
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  );
                                                              
                                                              }
                                                              
                                                              interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
                                                              {
                                                              }
                                                              
                                                              /**
                                                               * @title A trusted proxy for updating where current answers are read from
                                                               * @notice This contract provides a consistent address for the
                                                               * CurrentAnwerInterface but delegates where it reads from to the owner, who is
                                                               * trusted to update it.
                                                               */
                                                              contract AggregatorProxy is AggregatorV2V3Interface, Owned {
                                                              
                                                                struct Phase {
                                                                  uint16 id;
                                                                  AggregatorV2V3Interface aggregator;
                                                                }
                                                                Phase private currentPhase;
                                                                AggregatorV2V3Interface public proposedAggregator;
                                                                mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators;
                                                              
                                                                uint256 constant private PHASE_OFFSET = 64;
                                                                uint256 constant private PHASE_SIZE = 16;
                                                                uint256 constant private MAX_ID = 2**(PHASE_OFFSET+PHASE_SIZE) - 1;
                                                              
                                                                constructor(address _aggregator) public Owned() {
                                                                  setAggregator(_aggregator);
                                                                }
                                                              
                                                                /**
                                                                 * @notice Reads the current answer from aggregator delegated to.
                                                                 *
                                                                 * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended latestRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function latestAnswer()
                                                                  public
                                                                  view
                                                                  virtual
                                                                  override
                                                                  returns (int256 answer)
                                                                {
                                                                  return currentPhase.aggregator.latestAnswer();
                                                                }
                                                              
                                                                /**
                                                                 * @notice Reads the last updated height from aggregator delegated to.
                                                                 *
                                                                 * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended latestRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function latestTimestamp()
                                                                  public
                                                                  view
                                                                  virtual
                                                                  override
                                                                  returns (uint256 updatedAt)
                                                                {
                                                                  return currentPhase.aggregator.latestTimestamp();
                                                                }
                                                              
                                                                /**
                                                                 * @notice get past rounds answers
                                                                 * @param _roundId the answer number to retrieve the answer for
                                                                 *
                                                                 * @dev #[deprecated] Use getRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended getRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function getAnswer(uint256 _roundId)
                                                                  public
                                                                  view
                                                                  virtual
                                                                  override
                                                                  returns (int256 answer)
                                                                {
                                                                  if (_roundId > MAX_ID) return 0;
                                                              
                                                                  (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                                                                  AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
                                                                  if (address(aggregator) == address(0)) return 0;
                                                              
                                                                  return aggregator.getAnswer(aggregatorRoundId);
                                                                }
                                                              
                                                                /**
                                                                 * @notice get block timestamp when an answer was last updated
                                                                 * @param _roundId the answer number to retrieve the updated timestamp for
                                                                 *
                                                                 * @dev #[deprecated] Use getRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended getRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function getTimestamp(uint256 _roundId)
                                                                  public
                                                                  view
                                                                  virtual
                                                                  override
                                                                  returns (uint256 updatedAt)
                                                                {
                                                                  if (_roundId > MAX_ID) return 0;
                                                              
                                                                  (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                                                                  AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
                                                                  if (address(aggregator) == address(0)) return 0;
                                                              
                                                                  return aggregator.getTimestamp(aggregatorRoundId);
                                                                }
                                                              
                                                                /**
                                                                 * @notice get the latest completed round where the answer was updated. This
                                                                 * ID includes the proxy's phase, to make sure round IDs increase even when
                                                                 * switching to a newly deployed aggregator.
                                                                 *
                                                                 * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended latestRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function latestRound()
                                                                  public
                                                                  view
                                                                  virtual
                                                                  override
                                                                  returns (uint256 roundId)
                                                                {
                                                                  Phase memory phase = currentPhase; // cache storage reads
                                                                  return addPhase(phase.id, uint64(phase.aggregator.latestRound()));
                                                                }
                                                              
                                                                /**
                                                                 * @notice get data about a round. Consumers are encouraged to check
                                                                 * that they're receiving fresh data by inspecting the updatedAt and
                                                                 * answeredInRound return values.
                                                                 * Note that different underlying implementations of AggregatorV3Interface
                                                                 * have slightly different semantics for some of the return values. Consumers
                                                                 * should determine what implementations they expect to receive
                                                                 * data from and validate that they can properly handle return data from all
                                                                 * of them.
                                                                 * @param _roundId the requested round ID as presented through the proxy, this
                                                                 * is made up of the aggregator's round ID with the phase ID encoded in the
                                                                 * two highest order bytes
                                                                 * @return roundId is the round ID from the aggregator for which the data was
                                                                 * retrieved combined with an phase to ensure that round IDs get larger as
                                                                 * time moves forward.
                                                                 * @return answer is the answer for the given round
                                                                 * @return startedAt is the timestamp when the round was started.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @return updatedAt is the timestamp when the round last was updated (i.e.
                                                                 * answer was last computed)
                                                                 * @return answeredInRound is the round ID of the round in which the answer
                                                                 * was computed.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @dev Note that answer and updatedAt may change between queries.
                                                                 */
                                                                function getRoundData(uint80 _roundId)
                                                                  public
                                                                  view
                                                                  virtual
                                                                  override
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
                                                              
                                                                  (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 ansIn
                                                                  ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);
                                                              
                                                                  return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);
                                                                }
                                                              
                                                                /**
                                                                 * @notice get data about the latest round. Consumers are encouraged to check
                                                                 * that they're receiving fresh data by inspecting the updatedAt and
                                                                 * answeredInRound return values.
                                                                 * Note that different underlying implementations of AggregatorV3Interface
                                                                 * have slightly different semantics for some of the return values. Consumers
                                                                 * should determine what implementations they expect to receive
                                                                 * data from and validate that they can properly handle return data from all
                                                                 * of them.
                                                                 * @return roundId is the round ID from the aggregator for which the data was
                                                                 * retrieved combined with an phase to ensure that round IDs get larger as
                                                                 * time moves forward.
                                                                 * @return answer is the answer for the given round
                                                                 * @return startedAt is the timestamp when the round was started.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @return updatedAt is the timestamp when the round last was updated (i.e.
                                                                 * answer was last computed)
                                                                 * @return answeredInRound is the round ID of the round in which the answer
                                                                 * was computed.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @dev Note that answer and updatedAt may change between queries.
                                                                 */
                                                                function latestRoundData()
                                                                  public
                                                                  view
                                                                  virtual
                                                                  override
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  Phase memory current = currentPhase; // cache storage reads
                                                              
                                                                  (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 ansIn
                                                                  ) = current.aggregator.latestRoundData();
                                                              
                                                                  return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, current.id);
                                                                }
                                                              
                                                                /**
                                                                 * @notice Used if an aggregator contract has been proposed.
                                                                 * @param _roundId the round ID to retrieve the round data for
                                                                 * @return roundId is the round ID for which data was retrieved
                                                                 * @return answer is the answer for the given round
                                                                 * @return startedAt is the timestamp when the round was started.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @return updatedAt is the timestamp when the round last was updated (i.e.
                                                                 * answer was last computed)
                                                                 * @return answeredInRound is the round ID of the round in which the answer
                                                                 * was computed.
                                                                */
                                                                function proposedGetRoundData(uint80 _roundId)
                                                                  public
                                                                  view
                                                                  virtual
                                                                  hasProposal()
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  return proposedAggregator.getRoundData(_roundId);
                                                                }
                                                              
                                                                /**
                                                                 * @notice Used if an aggregator contract has been proposed.
                                                                 * @return roundId is the round ID for which data was retrieved
                                                                 * @return answer is the answer for the given round
                                                                 * @return startedAt is the timestamp when the round was started.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @return updatedAt is the timestamp when the round last was updated (i.e.
                                                                 * answer was last computed)
                                                                 * @return answeredInRound is the round ID of the round in which the answer
                                                                 * was computed.
                                                                */
                                                                function proposedLatestRoundData()
                                                                  public
                                                                  view
                                                                  virtual
                                                                  hasProposal()
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  return proposedAggregator.latestRoundData();
                                                                }
                                                              
                                                                /**
                                                                 * @notice returns the current phase's aggregator address.
                                                                 */
                                                                function aggregator()
                                                                  external
                                                                  view
                                                                  returns (address)
                                                                {
                                                                  return address(currentPhase.aggregator);
                                                                }
                                                              
                                                                /**
                                                                 * @notice returns the current phase's ID.
                                                                 */
                                                                function phaseId()
                                                                  external
                                                                  view
                                                                  returns (uint16)
                                                                {
                                                                  return currentPhase.id;
                                                                }
                                                              
                                                                /**
                                                                 * @notice represents the number of decimals the aggregator responses represent.
                                                                 */
                                                                function decimals()
                                                                  external
                                                                  view
                                                                  override
                                                                  returns (uint8)
                                                                {
                                                                  return currentPhase.aggregator.decimals();
                                                                }
                                                              
                                                                /**
                                                                 * @notice the version number representing the type of aggregator the proxy
                                                                 * points to.
                                                                 */
                                                                function version()
                                                                  external
                                                                  view
                                                                  override
                                                                  returns (uint256)
                                                                {
                                                                  return currentPhase.aggregator.version();
                                                                }
                                                              
                                                                /**
                                                                 * @notice returns the description of the aggregator the proxy points to.
                                                                 */
                                                                function description()
                                                                  external
                                                                  view
                                                                  override
                                                                  returns (string memory)
                                                                {
                                                                  return currentPhase.aggregator.description();
                                                                }
                                                              
                                                                /**
                                                                 * @notice Allows the owner to propose a new address for the aggregator
                                                                 * @param _aggregator The new address for the aggregator contract
                                                                 */
                                                                function proposeAggregator(address _aggregator)
                                                                  external
                                                                  onlyOwner()
                                                                {
                                                                  proposedAggregator = AggregatorV2V3Interface(_aggregator);
                                                                }
                                                              
                                                                /**
                                                                 * @notice Allows the owner to confirm and change the address
                                                                 * to the proposed aggregator
                                                                 * @dev Reverts if the given address doesn't match what was previously
                                                                 * proposed
                                                                 * @param _aggregator The new address for the aggregator contract
                                                                 */
                                                                function confirmAggregator(address _aggregator)
                                                                  external
                                                                  onlyOwner()
                                                                {
                                                                  require(_aggregator == address(proposedAggregator), "Invalid proposed aggregator");
                                                                  delete proposedAggregator;
                                                                  setAggregator(_aggregator);
                                                                }
                                                              
                                                              
                                                                /*
                                                                 * Internal
                                                                 */
                                                              
                                                                function setAggregator(address _aggregator)
                                                                  internal
                                                                {
                                                                  uint16 id = currentPhase.id + 1;
                                                                  currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator));
                                                                  phaseAggregators[id] = AggregatorV2V3Interface(_aggregator);
                                                                }
                                                              
                                                                function addPhase(
                                                                  uint16 _phase,
                                                                  uint64 _originalId
                                                                )
                                                                  internal
                                                                  view
                                                                  returns (uint80)
                                                                {
                                                                  return uint80(uint256(_phase) << PHASE_OFFSET | _originalId);
                                                                }
                                                              
                                                                function parseIds(
                                                                  uint256 _roundId
                                                                )
                                                                  internal
                                                                  view
                                                                  returns (uint16, uint64)
                                                                {
                                                                  uint16 phaseId = uint16(_roundId >> PHASE_OFFSET);
                                                                  uint64 aggregatorRoundId = uint64(_roundId);
                                                              
                                                                  return (phaseId, aggregatorRoundId);
                                                                }
                                                              
                                                                function addPhaseIds(
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound,
                                                                    uint16 phaseId
                                                                )
                                                                  internal
                                                                  view
                                                                  returns (uint80, int256, uint256, uint256, uint80)
                                                                {
                                                                  return (
                                                                    addPhase(phaseId, uint64(roundId)),
                                                                    answer,
                                                                    startedAt,
                                                                    updatedAt,
                                                                    addPhase(phaseId, uint64(answeredInRound))
                                                                  );
                                                                }
                                                              
                                                                /*
                                                                 * Modifiers
                                                                 */
                                                              
                                                                modifier hasProposal() {
                                                                  require(address(proposedAggregator) != address(0), "No proposed aggregator present");
                                                                  _;
                                                                }
                                                              
                                                              }
                                                              
                                                              interface AccessControllerInterface {
                                                                function hasAccess(address user, bytes calldata data) external view returns (bool);
                                                              }
                                                              
                                                              /**
                                                               * @title External Access Controlled Aggregator Proxy
                                                               * @notice A trusted proxy for updating where current answers are read from
                                                               * @notice This contract provides a consistent address for the
                                                               * Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is
                                                               * trusted to update it.
                                                               * @notice Only access enabled addresses are allowed to access getters for
                                                               * aggregated answers and round information.
                                                               */
                                                              contract EACAggregatorProxy is AggregatorProxy {
                                                              
                                                                AccessControllerInterface public accessController;
                                                              
                                                                constructor(
                                                                  address _aggregator,
                                                                  address _accessController
                                                                )
                                                                  public
                                                                  AggregatorProxy(_aggregator)
                                                                {
                                                                  setController(_accessController);
                                                                }
                                                              
                                                                /**
                                                                 * @notice Allows the owner to update the accessController contract address.
                                                                 * @param _accessController The new address for the accessController contract
                                                                 */
                                                                function setController(address _accessController)
                                                                  public
                                                                  onlyOwner()
                                                                {
                                                                  accessController = AccessControllerInterface(_accessController);
                                                                }
                                                              
                                                                /**
                                                                 * @notice Reads the current answer from aggregator delegated to.
                                                                 * @dev overridden function to add the checkAccess() modifier
                                                                 *
                                                                 * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended latestRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function latestAnswer()
                                                                  public
                                                                  view
                                                                  override
                                                                  checkAccess()
                                                                  returns (int256)
                                                                {
                                                                  return super.latestAnswer();
                                                                }
                                                              
                                                                /**
                                                                 * @notice get the latest completed round where the answer was updated. This
                                                                 * ID includes the proxy's phase, to make sure round IDs increase even when
                                                                 * switching to a newly deployed aggregator.
                                                                 *
                                                                 * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended latestRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function latestTimestamp()
                                                                  public
                                                                  view
                                                                  override
                                                                  checkAccess()
                                                                  returns (uint256)
                                                                {
                                                                  return super.latestTimestamp();
                                                                }
                                                              
                                                                /**
                                                                 * @notice get past rounds answers
                                                                 * @param _roundId the answer number to retrieve the answer for
                                                                 * @dev overridden function to add the checkAccess() modifier
                                                                 *
                                                                 * @dev #[deprecated] Use getRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended getRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function getAnswer(uint256 _roundId)
                                                                  public
                                                                  view
                                                                  override
                                                                  checkAccess()
                                                                  returns (int256)
                                                                {
                                                                  return super.getAnswer(_roundId);
                                                                }
                                                              
                                                                /**
                                                                 * @notice get block timestamp when an answer was last updated
                                                                 * @param _roundId the answer number to retrieve the updated timestamp for
                                                                 * @dev overridden function to add the checkAccess() modifier
                                                                 *
                                                                 * @dev #[deprecated] Use getRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended getRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function getTimestamp(uint256 _roundId)
                                                                  public
                                                                  view
                                                                  override
                                                                  checkAccess()
                                                                  returns (uint256)
                                                                {
                                                                  return super.getTimestamp(_roundId);
                                                                }
                                                              
                                                                /**
                                                                 * @notice get the latest completed round where the answer was updated
                                                                 * @dev overridden function to add the checkAccess() modifier
                                                                 *
                                                                 * @dev #[deprecated] Use latestRoundData instead. This does not error if no
                                                                 * answer has been reached, it will simply return 0. Either wait to point to
                                                                 * an already answered Aggregator or use the recommended latestRoundData
                                                                 * instead which includes better verification information.
                                                                 */
                                                                function latestRound()
                                                                  public
                                                                  view
                                                                  override
                                                                  checkAccess()
                                                                  returns (uint256)
                                                                {
                                                                  return super.latestRound();
                                                                }
                                                              
                                                                /**
                                                                 * @notice get data about a round. Consumers are encouraged to check
                                                                 * that they're receiving fresh data by inspecting the updatedAt and
                                                                 * answeredInRound return values.
                                                                 * Note that different underlying implementations of AggregatorV3Interface
                                                                 * have slightly different semantics for some of the return values. Consumers
                                                                 * should determine what implementations they expect to receive
                                                                 * data from and validate that they can properly handle return data from all
                                                                 * of them.
                                                                 * @param _roundId the round ID to retrieve the round data for
                                                                 * @return roundId is the round ID from the aggregator for which the data was
                                                                 * retrieved combined with a phase to ensure that round IDs get larger as
                                                                 * time moves forward.
                                                                 * @return answer is the answer for the given round
                                                                 * @return startedAt is the timestamp when the round was started.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @return updatedAt is the timestamp when the round last was updated (i.e.
                                                                 * answer was last computed)
                                                                 * @return answeredInRound is the round ID of the round in which the answer
                                                                 * was computed.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @dev Note that answer and updatedAt may change between queries.
                                                                 */
                                                                function getRoundData(uint80 _roundId)
                                                                  public
                                                                  view
                                                                  checkAccess()
                                                                  override
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  return super.getRoundData(_roundId);
                                                                }
                                                              
                                                                /**
                                                                 * @notice get data about the latest round. Consumers are encouraged to check
                                                                 * that they're receiving fresh data by inspecting the updatedAt and
                                                                 * answeredInRound return values.
                                                                 * Note that different underlying implementations of AggregatorV3Interface
                                                                 * have slightly different semantics for some of the return values. Consumers
                                                                 * should determine what implementations they expect to receive
                                                                 * data from and validate that they can properly handle return data from all
                                                                 * of them.
                                                                 * @return roundId is the round ID from the aggregator for which the data was
                                                                 * retrieved combined with a phase to ensure that round IDs get larger as
                                                                 * time moves forward.
                                                                 * @return answer is the answer for the given round
                                                                 * @return startedAt is the timestamp when the round was started.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @return updatedAt is the timestamp when the round last was updated (i.e.
                                                                 * answer was last computed)
                                                                 * @return answeredInRound is the round ID of the round in which the answer
                                                                 * was computed.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @dev Note that answer and updatedAt may change between queries.
                                                                 */
                                                                function latestRoundData()
                                                                  public
                                                                  view
                                                                  checkAccess()
                                                                  override
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  return super.latestRoundData();
                                                                }
                                                              
                                                                /**
                                                                 * @notice Used if an aggregator contract has been proposed.
                                                                 * @param _roundId the round ID to retrieve the round data for
                                                                 * @return roundId is the round ID for which data was retrieved
                                                                 * @return answer is the answer for the given round
                                                                 * @return startedAt is the timestamp when the round was started.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @return updatedAt is the timestamp when the round last was updated (i.e.
                                                                 * answer was last computed)
                                                                 * @return answeredInRound is the round ID of the round in which the answer
                                                                 * was computed.
                                                                */
                                                                function proposedGetRoundData(uint80 _roundId)
                                                                  public
                                                                  view
                                                                  checkAccess()
                                                                  hasProposal()
                                                                  override
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  return super.proposedGetRoundData(_roundId);
                                                                }
                                                              
                                                                /**
                                                                 * @notice Used if an aggregator contract has been proposed.
                                                                 * @return roundId is the round ID for which data was retrieved
                                                                 * @return answer is the answer for the given round
                                                                 * @return startedAt is the timestamp when the round was started.
                                                                 * (Only some AggregatorV3Interface implementations return meaningful values)
                                                                 * @return updatedAt is the timestamp when the round last was updated (i.e.
                                                                 * answer was last computed)
                                                                 * @return answeredInRound is the round ID of the round in which the answer
                                                                 * was computed.
                                                                */
                                                                function proposedLatestRoundData()
                                                                  public
                                                                  view
                                                                  checkAccess()
                                                                  hasProposal()
                                                                  override
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  return super.proposedLatestRoundData();
                                                                }
                                                              
                                                                /**
                                                                 * @dev reverts if the caller does not have access by the accessController
                                                                 * contract or is the contract itself.
                                                                 */
                                                                modifier checkAccess() {
                                                                  AccessControllerInterface ac = accessController;
                                                                  require(address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), "No access");
                                                                  _;
                                                                }
                                                              }

                                                              File 12 of 14: AccessControlledOffchainAggregator
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.1;
                                                              import "./OffchainAggregator.sol";
                                                              import "./SimpleReadAccessController.sol";
                                                              /**
                                                               * @notice Wrapper of OffchainAggregator which checks read access on Aggregator-interface methods
                                                               */
                                                              contract AccessControlledOffchainAggregator is OffchainAggregator, SimpleReadAccessController {
                                                                constructor(
                                                                  uint32 _maximumGasPrice,
                                                                  uint32 _reasonableGasPrice,
                                                                  uint32 _microLinkPerEth,
                                                                  uint32 _linkGweiPerObservation,
                                                                  uint32 _linkGweiPerTransmission,
                                                                  address _link,
                                                                  address _validator,
                                                                  int192 _minAnswer,
                                                                  int192 _maxAnswer,
                                                                  AccessControllerInterface _billingAccessController,
                                                                  AccessControllerInterface _requesterAccessController,
                                                                  uint8 _decimals,
                                                                  string memory description
                                                                )
                                                                  OffchainAggregator(
                                                                    _maximumGasPrice,
                                                                    _reasonableGasPrice,
                                                                    _microLinkPerEth,
                                                                    _linkGweiPerObservation,
                                                                    _linkGweiPerTransmission,
                                                                    _link,
                                                                    _validator,
                                                                    _minAnswer,
                                                                    _maxAnswer,
                                                                    _billingAccessController,
                                                                    _requesterAccessController,
                                                                    _decimals,
                                                                    description
                                                                  ) {
                                                                  }
                                                                /*
                                                                 * v2 Aggregator interface
                                                                 */
                                                                /// @inheritdoc OffchainAggregator
                                                                function latestAnswer()
                                                                  public
                                                                  override
                                                                  view
                                                                  checkAccess()
                                                                  returns (int256)
                                                                {
                                                                  return super.latestAnswer();
                                                                }
                                                                /// @inheritdoc OffchainAggregator
                                                                function latestTimestamp()
                                                                  public
                                                                  override
                                                                  view
                                                                  checkAccess()
                                                                  returns (uint256)
                                                                {
                                                                  return super.latestTimestamp();
                                                                }
                                                                /// @inheritdoc OffchainAggregator
                                                                function latestRound()
                                                                  public
                                                                  override
                                                                  view
                                                                  checkAccess()
                                                                  returns (uint256)
                                                                {
                                                                  return super.latestRound();
                                                                }
                                                                /// @inheritdoc OffchainAggregator
                                                                function getAnswer(uint256 _roundId)
                                                                  public
                                                                  override
                                                                  view
                                                                  checkAccess()
                                                                  returns (int256)
                                                                {
                                                                  return super.getAnswer(_roundId);
                                                                }
                                                                /// @inheritdoc OffchainAggregator
                                                                function getTimestamp(uint256 _roundId)
                                                                  public
                                                                  override
                                                                  view
                                                                  checkAccess()
                                                                  returns (uint256)
                                                                {
                                                                  return super.getTimestamp(_roundId);
                                                                }
                                                                /*
                                                                 * v3 Aggregator interface
                                                                 */
                                                                /// @inheritdoc OffchainAggregator
                                                                function description()
                                                                  public
                                                                  override
                                                                  view
                                                                  checkAccess()
                                                                  returns (string memory)
                                                                {
                                                                  return super.description();
                                                                }
                                                                /// @inheritdoc OffchainAggregator
                                                                function getRoundData(uint80 _roundId)
                                                                  public
                                                                  override
                                                                  view
                                                                  checkAccess()
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  return super.getRoundData(_roundId);
                                                                }
                                                                /// @inheritdoc OffchainAggregator
                                                                function latestRoundData()
                                                                  public
                                                                  override
                                                                  view
                                                                  checkAccess()
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  return super.latestRoundData();
                                                                }
                                                              }
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.0;
                                                              import "./AccessControllerInterface.sol";
                                                              import "./AggregatorV2V3Interface.sol";
                                                              import "./AggregatorValidatorInterface.sol";
                                                              import "./LinkTokenInterface.sol";
                                                              import "./Owned.sol";
                                                              import "./OffchainAggregatorBilling.sol";
                                                              /**
                                                                * @notice Onchain verification of reports from the offchain reporting protocol
                                                                * @dev For details on its operation, see the offchain reporting protocol design
                                                                * @dev doc, which refers to this contract as simply the "contract".
                                                              */
                                                              contract OffchainAggregator is Owned, OffchainAggregatorBilling, AggregatorV2V3Interface {
                                                                uint256 constant private maxUint32 = (1 << 32) - 1;
                                                                // Storing these fields used on the hot path in a HotVars variable reduces the
                                                                // retrieval of all of them to a single SLOAD. If any further fields are
                                                                // added, make sure that storage of the struct still takes at most 32 bytes.
                                                                struct HotVars {
                                                                  // Provides 128 bits of security against 2nd pre-image attacks, but only
                                                                  // 64 bits against collisions. This is acceptable, since a malicious owner has
                                                                  // easier way of messing up the protocol than to find hash collisions.
                                                                  bytes16 latestConfigDigest;
                                                                  uint40 latestEpochAndRound; // 32 most sig bits for epoch, 8 least sig bits for round
                                                                  // Current bound assumed on number of faulty/dishonest oracles participating
                                                                  // in the protocol, this value is referred to as f in the design
                                                                  uint8 threshold;
                                                                  // Chainlink Aggregators expose a roundId to consumers. The offchain reporting
                                                                  // protocol does not use this id anywhere. We increment it whenever a new
                                                                  // transmission is made to provide callers with contiguous ids for successive
                                                                  // reports.
                                                                  uint32 latestAggregatorRoundId;
                                                                }
                                                                HotVars internal s_hotVars;
                                                                // Transmission records the median answer from the transmit transaction at
                                                                // time timestamp
                                                                struct Transmission {
                                                                  int192 answer; // 192 bits ought to be enough for anyone
                                                                  uint64 timestamp;
                                                                }
                                                                mapping(uint32 /* aggregator round ID */ => Transmission) internal s_transmissions;
                                                                // incremented each time a new config is posted. This count is incorporated
                                                                // into the config digest, to prevent replay attacks.
                                                                uint32 internal s_configCount;
                                                                uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems
                                                                                                           // to extract config from logs.
                                                                // Lowest answer the system is allowed to report in response to transmissions
                                                                int192 immutable public minAnswer;
                                                                // Highest answer the system is allowed to report in response to transmissions
                                                                int192 immutable public maxAnswer;
                                                                /*
                                                                 * @param _maximumGasPrice highest gas price for which transmitter will be compensated
                                                                 * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
                                                                 * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
                                                                 * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
                                                                 * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
                                                                 * @param _link address of the LINK contract
                                                                 * @param _validator address of validator contract (must satisfy AggregatorValidatorInterface)
                                                                 * @param _minAnswer lowest answer the median of a report is allowed to be
                                                                 * @param _maxAnswer highest answer the median of a report is allowed to be
                                                                 * @param _billingAccessController access controller for billing admin functions
                                                                 * @param _requesterAccessController access controller for requesting new rounds
                                                                 * @param _decimals answers are stored in fixed-point format, with this many digits of precision
                                                                 * @param _description short human-readable description of observable this contract's answers pertain to
                                                                 */
                                                                constructor(
                                                                  uint32 _maximumGasPrice,
                                                                  uint32 _reasonableGasPrice,
                                                                  uint32 _microLinkPerEth,
                                                                  uint32 _linkGweiPerObservation,
                                                                  uint32 _linkGweiPerTransmission,
                                                                  address _link,
                                                                  address _validator,
                                                                  int192 _minAnswer,
                                                                  int192 _maxAnswer,
                                                                  AccessControllerInterface _billingAccessController,
                                                                  AccessControllerInterface _requesterAccessController,
                                                                  uint8 _decimals,
                                                                  string memory _description
                                                                )
                                                                  OffchainAggregatorBilling(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                                                                    _linkGweiPerObservation, _linkGweiPerTransmission, _link,
                                                                    _billingAccessController
                                                                  )
                                                                {
                                                                  decimals = _decimals;
                                                                  s_description = _description;
                                                                  setRequesterAccessController(_requesterAccessController);
                                                                  setValidator(_validator);
                                                                  minAnswer = _minAnswer;
                                                                  maxAnswer = _maxAnswer;
                                                                }
                                                                /*
                                                                 * Config logic
                                                                 */
                                                                /**
                                                                 * @notice triggers a new run of the offchain reporting protocol
                                                                 * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis
                                                                 * @param configCount ordinal number of this config setting among all config settings over the life of this contract
                                                                 * @param signers ith element is address ith oracle uses to sign a report
                                                                 * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method
                                                                 * @param threshold maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly
                                                                 * @param encodedConfigVersion version of the serialization format used for "encoded" parameter
                                                                 * @param encoded serialized data used by oracles to configure their offchain operation
                                                                 */
                                                                event ConfigSet(
                                                                  uint32 previousConfigBlockNumber,
                                                                  uint64 configCount,
                                                                  address[] signers,
                                                                  address[] transmitters,
                                                                  uint8 threshold,
                                                                  uint64 encodedConfigVersion,
                                                                  bytes encoded
                                                                );
                                                                // Reverts transaction if config args are invalid
                                                                modifier checkConfigValid (
                                                                  uint256 _numSigners, uint256 _numTransmitters, uint256 _threshold
                                                                ) {
                                                                  require(_numSigners <= maxNumOracles, "too many signers");
                                                                  require(_threshold > 0, "threshold must be positive");
                                                                  require(
                                                                    _numSigners == _numTransmitters,
                                                                    "oracle addresses out of registration"
                                                                  );
                                                                  require(_numSigners > 3*_threshold, "faulty-oracle threshold too high");
                                                                  _;
                                                                }
                                                                /**
                                                                 * @notice sets offchain reporting protocol configuration incl. participating oracles
                                                                 * @param _signers addresses with which oracles sign the reports
                                                                 * @param _transmitters addresses oracles use to transmit the reports
                                                                 * @param _threshold number of faulty oracles the system can tolerate
                                                                 * @param _encodedConfigVersion version number for offchainEncoding schema
                                                                 * @param _encoded encoded off-chain oracle configuration
                                                                 */
                                                                function setConfig(
                                                                  address[] calldata _signers,
                                                                  address[] calldata _transmitters,
                                                                  uint8 _threshold,
                                                                  uint64 _encodedConfigVersion,
                                                                  bytes calldata _encoded
                                                                )
                                                                  external
                                                                  checkConfigValid(_signers.length, _transmitters.length, _threshold)
                                                                  onlyOwner()
                                                                {
                                                                  while (s_signers.length != 0) { // remove any old signer/transmitter addresses
                                                                    uint lastIdx = s_signers.length - 1;
                                                                    address signer = s_signers[lastIdx];
                                                                    address transmitter = s_transmitters[lastIdx];
                                                                    payOracle(transmitter);
                                                                    delete s_oracles[signer];
                                                                    delete s_oracles[transmitter];
                                                                    s_signers.pop();
                                                                    s_transmitters.pop();
                                                                  }
                                                                  for (uint i = 0; i < _signers.length; i++) { // add new signer/transmitter addresses
                                                                    require(
                                                                      s_oracles[_signers[i]].role == Role.Unset,
                                                                      "repeated signer address"
                                                                    );
                                                                    s_oracles[_signers[i]] = Oracle(uint8(i), Role.Signer);
                                                                    require(s_payees[_transmitters[i]] != address(0), "payee must be set");
                                                                    require(
                                                                      s_oracles[_transmitters[i]].role == Role.Unset,
                                                                      "repeated transmitter address"
                                                                    );
                                                                    s_oracles[_transmitters[i]] = Oracle(uint8(i), Role.Transmitter);
                                                                    s_signers.push(_signers[i]);
                                                                    s_transmitters.push(_transmitters[i]);
                                                                  }
                                                                  s_hotVars.threshold = _threshold;
                                                                  uint32 previousConfigBlockNumber = s_latestConfigBlockNumber;
                                                                  s_latestConfigBlockNumber = uint32(block.number);
                                                                  s_configCount += 1;
                                                                  uint64 configCount = s_configCount;
                                                                  {
                                                                    s_hotVars.latestConfigDigest = configDigestFromConfigData(
                                                                      address(this),
                                                                      configCount,
                                                                      _signers,
                                                                      _transmitters,
                                                                      _threshold,
                                                                      _encodedConfigVersion,
                                                                      _encoded
                                                                    );
                                                                    s_hotVars.latestEpochAndRound = 0;
                                                                  }
                                                                  emit ConfigSet(
                                                                    previousConfigBlockNumber,
                                                                    configCount,
                                                                    _signers,
                                                                    _transmitters,
                                                                    _threshold,
                                                                    _encodedConfigVersion,
                                                                    _encoded
                                                                  );
                                                                }
                                                                function configDigestFromConfigData(
                                                                  address _contractAddress,
                                                                  uint64 _configCount,
                                                                  address[] calldata _signers,
                                                                  address[] calldata _transmitters,
                                                                  uint8 _threshold,
                                                                  uint64 _encodedConfigVersion,
                                                                  bytes calldata _encodedConfig
                                                                ) internal pure returns (bytes16) {
                                                                  return bytes16(keccak256(abi.encode(_contractAddress, _configCount,
                                                                    _signers, _transmitters, _threshold, _encodedConfigVersion, _encodedConfig
                                                                  )));
                                                                }
                                                                /**
                                                                 * @notice information about current offchain reporting protocol configuration
                                                                 * @return configCount ordinal number of current config, out of all configs applied to this contract so far
                                                                 * @return blockNumber block at which this config was set
                                                                 * @return configDigest domain-separation tag for current config (see configDigestFromConfigData)
                                                                 */
                                                                function latestConfigDetails()
                                                                  external
                                                                  view
                                                                  returns (
                                                                    uint32 configCount,
                                                                    uint32 blockNumber,
                                                                    bytes16 configDigest
                                                                  )
                                                                {
                                                                  return (s_configCount, s_latestConfigBlockNumber, s_hotVars.latestConfigDigest);
                                                                }
                                                                /**
                                                                 * @return list of addresses permitted to transmit reports to this contract
                                                                 * @dev The list will match the order used to specify the transmitter during setConfig
                                                                 */
                                                                function transmitters()
                                                                  external
                                                                  view
                                                                  returns(address[] memory)
                                                                {
                                                                    return s_transmitters;
                                                                }
                                                                /*
                                                                 * On-chain validation logc
                                                                 */
                                                                // Maximum gas the validation logic can use
                                                                uint256 private constant VALIDATOR_GAS_LIMIT = 100000;
                                                                // Contract containing the validation logic
                                                                AggregatorValidatorInterface private s_validator;
                                                                /**
                                                                 * @notice indicates that the address of the validator contract has been set
                                                                 * @param previous setting of the address prior to this event
                                                                 * @param current the new value for the address
                                                                 */
                                                                event ValidatorUpdated(
                                                                  address indexed previous,
                                                                  address indexed current
                                                                );
                                                                /**
                                                                 * @notice address of the contract which does external data validation
                                                                 * @return validator address
                                                                 */
                                                                function validator()
                                                                  external
                                                                  view
                                                                  returns (AggregatorValidatorInterface)
                                                                {
                                                                  return s_validator;
                                                                }
                                                                /**
                                                                 * @notice sets the address which does external data validation
                                                                 * @param _newValidator designates the address of the new validation contract
                                                                 */
                                                                function setValidator(address _newValidator)
                                                                  public
                                                                  onlyOwner()
                                                                {
                                                                  address previous = address(s_validator);
                                                                  if (previous != _newValidator) {
                                                                    s_validator = AggregatorValidatorInterface(_newValidator);
                                                                    emit ValidatorUpdated(previous, _newValidator);
                                                                  }
                                                                }
                                                                function validateAnswer(
                                                                  uint32 _aggregatorRoundId,
                                                                  int256 _answer
                                                                )
                                                                  private
                                                                {
                                                                  AggregatorValidatorInterface av = s_validator; // cache storage reads
                                                                  if (address(av) == address(0)) return;
                                                                  uint32 prevAggregatorRoundId = _aggregatorRoundId - 1;
                                                                  int256 prevAggregatorRoundAnswer = s_transmissions[prevAggregatorRoundId].answer;
                                                                  // We do not want the validator to ever prevent reporting, so we limit its
                                                                  // gas usage and catch any errors that may arise.
                                                                  try av.validate{gas: VALIDATOR_GAS_LIMIT}(
                                                                    prevAggregatorRoundId,
                                                                    prevAggregatorRoundAnswer,
                                                                    _aggregatorRoundId,
                                                                    _answer
                                                                  ) {} catch {}
                                                                }
                                                                /*
                                                                 * requestNewRound logic
                                                                 */
                                                                AccessControllerInterface internal s_requesterAccessController;
                                                                /**
                                                                 * @notice emitted when a new requester access controller contract is set
                                                                 * @param old the address prior to the current setting
                                                                 * @param current the address of the new access controller contract
                                                                 */
                                                                event RequesterAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
                                                                /**
                                                                 * @notice emitted to immediately request a new round
                                                                 * @param requester the address of the requester
                                                                 * @param configDigest the latest transmission's configDigest
                                                                 * @param epoch the latest transmission's epoch
                                                                 * @param round the latest transmission's round
                                                                 */
                                                                event RoundRequested(address indexed requester, bytes16 configDigest, uint32 epoch, uint8 round);
                                                                /**
                                                                 * @notice address of the requester access controller contract
                                                                 * @return requester access controller address
                                                                 */
                                                                function requesterAccessController()
                                                                  external
                                                                  view
                                                                  returns (AccessControllerInterface)
                                                                {
                                                                  return s_requesterAccessController;
                                                                }
                                                                /**
                                                                 * @notice sets the requester access controller
                                                                 * @param _requesterAccessController designates the address of the new requester access controller
                                                                 */
                                                                function setRequesterAccessController(AccessControllerInterface _requesterAccessController)
                                                                  public
                                                                  onlyOwner()
                                                                {
                                                                  AccessControllerInterface oldController = s_requesterAccessController;
                                                                  if (_requesterAccessController != oldController) {
                                                                    s_requesterAccessController = AccessControllerInterface(_requesterAccessController);
                                                                    emit RequesterAccessControllerSet(oldController, _requesterAccessController);
                                                                  }
                                                                }
                                                                /**
                                                                 * @notice immediately requests a new round
                                                                 * @return the aggregatorRoundId of the next round. Note: The report for this round may have been
                                                                 * transmitted (but not yet mined) *before* requestNewRound() was even called. There is *no*
                                                                 * guarantee of causality between the request and the report at aggregatorRoundId.
                                                                 */
                                                                function requestNewRound() external returns (uint80) {
                                                                  require(msg.sender == owner || s_requesterAccessController.hasAccess(msg.sender, msg.data),
                                                                    "Only owner&requester can call");
                                                                  HotVars memory hotVars = s_hotVars;
                                                                  emit RoundRequested(
                                                                    msg.sender,
                                                                    hotVars.latestConfigDigest,
                                                                    uint32(s_hotVars.latestEpochAndRound >> 8),
                                                                    uint8(s_hotVars.latestEpochAndRound)
                                                                  );
                                                                  return hotVars.latestAggregatorRoundId + 1;
                                                                }
                                                                /*
                                                                 * Transmission logic
                                                                 */
                                                                /**
                                                                 * @notice indicates that a new report was transmitted
                                                                 * @param aggregatorRoundId the round to which this report was assigned
                                                                 * @param answer median of the observations attached this report
                                                                 * @param transmitter address from which the report was transmitted
                                                                 * @param observations observations transmitted with this report
                                                                 * @param rawReportContext signature-replay-prevention domain-separation tag
                                                                 */
                                                                event NewTransmission(
                                                                  uint32 indexed aggregatorRoundId,
                                                                  int192 answer,
                                                                  address transmitter,
                                                                  int192[] observations,
                                                                  bytes observers,
                                                                  bytes32 rawReportContext
                                                                );
                                                                // decodeReport is used to check that the solidity and go code are using the
                                                                // same format. See TestOffchainAggregator.testDecodeReport and TestReportParsing
                                                                function decodeReport(bytes memory _report)
                                                                  internal
                                                                  pure
                                                                  returns (
                                                                    bytes32 rawReportContext,
                                                                    bytes32 rawObservers,
                                                                    int192[] memory observations
                                                                  )
                                                                {
                                                                  (rawReportContext, rawObservers, observations) = abi.decode(_report,
                                                                    (bytes32, bytes32, int192[]));
                                                                }
                                                                // Used to relieve stack pressure in transmit
                                                                struct ReportData {
                                                                  HotVars hotVars; // Only read from storage once
                                                                  bytes observers; // ith element is the index of the ith observer
                                                                  int192[] observations; // ith element is the ith observation
                                                                  bytes vs; // jth element is the v component of the jth signature
                                                                  bytes32 rawReportContext;
                                                                }
                                                                /*
                                                                 * @notice details about the most recent report
                                                                 * @return configDigest domain separation tag for the latest report
                                                                 * @return epoch epoch in which the latest report was generated
                                                                 * @return round OCR round in which the latest report was generated
                                                                 * @return latestAnswer median value from latest report
                                                                 * @return latestTimestamp when the latest report was transmitted
                                                                 */
                                                                function latestTransmissionDetails()
                                                                  external
                                                                  view
                                                                  returns (
                                                                    bytes16 configDigest,
                                                                    uint32 epoch,
                                                                    uint8 round,
                                                                    int192 latestAnswer,
                                                                    uint64 latestTimestamp
                                                                  )
                                                                {
                                                                  require(msg.sender == tx.origin, "Only callable by EOA");
                                                                  return (
                                                                    s_hotVars.latestConfigDigest,
                                                                    uint32(s_hotVars.latestEpochAndRound >> 8),
                                                                    uint8(s_hotVars.latestEpochAndRound),
                                                                    s_transmissions[s_hotVars.latestAggregatorRoundId].answer,
                                                                    s_transmissions[s_hotVars.latestAggregatorRoundId].timestamp
                                                                  );
                                                                }
                                                                // The constant-length components of the msg.data sent to transmit.
                                                                // See the "If we wanted to call sam" example on for example reasoning
                                                                // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html
                                                                uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT =
                                                                  4 + // function selector
                                                                  32 + // word containing start location of abiencoded _report value
                                                                  32 + // word containing location start of abiencoded  _rs value
                                                                  32 + // word containing start location of abiencoded _ss value
                                                                  32 + // _rawVs value
                                                                  32 + // word containing length of _report
                                                                  32 + // word containing length _rs
                                                                  32 + // word containing length of _ss
                                                                  0; // placeholder
                                                                function expectedMsgDataLength(
                                                                  bytes calldata _report, bytes32[] calldata _rs, bytes32[] calldata _ss
                                                                ) private pure returns (uint256 length)
                                                                {
                                                                  // calldata will never be big enough to make this overflow
                                                                  return uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) +
                                                                    _report.length + // one byte pure entry in _report
                                                                    _rs.length * 32 + // 32 bytes per entry in _rs
                                                                    _ss.length * 32 + // 32 bytes per entry in _ss
                                                                    0; // placeholder
                                                                }
                                                                /**
                                                                 * @notice transmit is called to post a new report to the contract
                                                                 * @param _report serialized report, which the signatures are signing. See parsing code below for format. The ith element of the observers component must be the index in s_signers of the address for the ith signature
                                                                 * @param _rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries
                                                                 * @param _ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries
                                                                 * @param _rawVs ith element is the the V component of the ith signature
                                                                 */
                                                                function transmit(
                                                                  // NOTE: If these parameters are changed, expectedMsgDataLength and/or
                                                                  // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly
                                                                  bytes calldata _report,
                                                                  bytes32[] calldata _rs, bytes32[] calldata _ss, bytes32 _rawVs // signatures
                                                                )
                                                                  external
                                                                {
                                                                  uint256 initialGas = gasleft(); // This line must come first
                                                                  // Make sure the transmit message-length matches the inputs. Otherwise, the
                                                                  // transmitter could append an arbitrarily long (up to gas-block limit)
                                                                  // string of 0 bytes, which we would reimburse at a rate of 16 gas/byte, but
                                                                  // which would only cost the transmitter 4 gas/byte. (Appendix G of the
                                                                  // yellow paper, p. 25, for G_txdatazero and EIP 2028 for G_txdatanonzero.)
                                                                  // This could amount to reimbursement profit of 36 million gas, given a 3MB
                                                                  // zero tail.
                                                                  require(msg.data.length == expectedMsgDataLength(_report, _rs, _ss),
                                                                    "transmit message too long");
                                                                  ReportData memory r; // Relieves stack pressure
                                                                  {
                                                                    r.hotVars = s_hotVars; // cache read from storage
                                                                    bytes32 rawObservers;
                                                                    (r.rawReportContext, rawObservers, r.observations) = abi.decode(
                                                                      _report, (bytes32, bytes32, int192[])
                                                                    );
                                                                    // rawReportContext consists of:
                                                                    // 11-byte zero padding
                                                                    // 16-byte configDigest
                                                                    // 4-byte epoch
                                                                    // 1-byte round
                                                                    bytes16 configDigest = bytes16(r.rawReportContext << 88);
                                                                    require(
                                                                      r.hotVars.latestConfigDigest == configDigest,
                                                                      "configDigest mismatch"
                                                                    );
                                                                    uint40 epochAndRound = uint40(uint256(r.rawReportContext));
                                                                    // direct numerical comparison works here, because
                                                                    //
                                                                    //   ((e,r) <= (e',r')) implies (epochAndRound <= epochAndRound')
                                                                    //
                                                                    // because alphabetic ordering implies e <= e', and if e = e', then r<=r',
                                                                    // so e*256+r <= e'*256+r', because r, r' < 256
                                                                    require(r.hotVars.latestEpochAndRound < epochAndRound, "stale report");
                                                                    require(_rs.length > r.hotVars.threshold, "not enough signatures");
                                                                    require(_rs.length <= maxNumOracles, "too many signatures");
                                                                    require(_ss.length == _rs.length, "signatures out of registration");
                                                                    require(r.observations.length <= maxNumOracles,
                                                                            "num observations out of bounds");
                                                                    require(r.observations.length > 2 * r.hotVars.threshold,
                                                                            "too few values to trust median");
                                                                    // Copy signature parities in bytes32 _rawVs to bytes r.v
                                                                    r.vs = new bytes(_rs.length);
                                                                    for (uint8 i = 0; i < _rs.length; i++) {
                                                                      r.vs[i] = _rawVs[i];
                                                                    }
                                                                    // Copy observer identities in bytes32 rawObservers to bytes r.observers
                                                                    r.observers = new bytes(r.observations.length);
                                                                    bool[maxNumOracles] memory seen;
                                                                    for (uint8 i = 0; i < r.observations.length; i++) {
                                                                      uint8 observerIdx = uint8(rawObservers[i]);
                                                                      require(!seen[observerIdx], "observer index repeated");
                                                                      seen[observerIdx] = true;
                                                                      r.observers[i] = rawObservers[i];
                                                                    }
                                                                    Oracle memory transmitter = s_oracles[msg.sender];
                                                                    require( // Check that sender is authorized to report
                                                                      transmitter.role == Role.Transmitter &&
                                                                      msg.sender == s_transmitters[transmitter.index],
                                                                      "unauthorized transmitter"
                                                                    );
                                                                    // record epochAndRound here, so that we don't have to carry the local
                                                                    // variable in transmit. The change is reverted if something fails later.
                                                                    r.hotVars.latestEpochAndRound = epochAndRound;
                                                                  }
                                                                  { // Verify signatures attached to report
                                                                    bytes32 h = keccak256(_report);
                                                                    bool[maxNumOracles] memory signed;
                                                                    Oracle memory o;
                                                                    for (uint i = 0; i < _rs.length; i++) {
                                                                      address signer = ecrecover(h, uint8(r.vs[i])+27, _rs[i], _ss[i]);
                                                                      o = s_oracles[signer];
                                                                      require(o.role == Role.Signer, "address not authorized to sign");
                                                                      require(!signed[o.index], "non-unique signature");
                                                                      signed[o.index] = true;
                                                                    }
                                                                  }
                                                                  { // Check the report contents, and record the result
                                                                    for (uint i = 0; i < r.observations.length - 1; i++) {
                                                                      bool inOrder = r.observations[i] <= r.observations[i+1];
                                                                      require(inOrder, "observations not sorted");
                                                                    }
                                                                    int192 median = r.observations[r.observations.length/2];
                                                                    require(minAnswer <= median && median <= maxAnswer, "median is out of min-max range");
                                                                    r.hotVars.latestAggregatorRoundId++;
                                                                    s_transmissions[r.hotVars.latestAggregatorRoundId] =
                                                                      Transmission(median, uint64(block.timestamp));
                                                                    emit NewTransmission(
                                                                      r.hotVars.latestAggregatorRoundId,
                                                                      median,
                                                                      msg.sender,
                                                                      r.observations,
                                                                      r.observers,
                                                                      r.rawReportContext
                                                                    );
                                                                    // Emit these for backwards compatability with offchain consumers
                                                                    // that only support legacy events
                                                                    emit NewRound(
                                                                      r.hotVars.latestAggregatorRoundId,
                                                                      address(0x0), // use zero address since we don't have anybody "starting" the round here
                                                                      block.timestamp
                                                                    );
                                                                    emit AnswerUpdated(
                                                                      median,
                                                                      r.hotVars.latestAggregatorRoundId,
                                                                      block.timestamp
                                                                    );
                                                                    validateAnswer(r.hotVars.latestAggregatorRoundId, median);
                                                                  }
                                                                  s_hotVars = r.hotVars;
                                                                  assert(initialGas < maxUint32);
                                                                  reimburseAndRewardOracles(uint32(initialGas), r.observers);
                                                                }
                                                                /*
                                                                 * v2 Aggregator interface
                                                                 */
                                                                /**
                                                                 * @notice median from the most recent report
                                                                 */
                                                                function latestAnswer()
                                                                  public
                                                                  override
                                                                  view
                                                                  virtual
                                                                  returns (int256)
                                                                {
                                                                  return s_transmissions[s_hotVars.latestAggregatorRoundId].answer;
                                                                }
                                                                /**
                                                                 * @notice timestamp of block in which last report was transmitted
                                                                 */
                                                                function latestTimestamp()
                                                                  public
                                                                  override
                                                                  view
                                                                  virtual
                                                                  returns (uint256)
                                                                {
                                                                  return s_transmissions[s_hotVars.latestAggregatorRoundId].timestamp;
                                                                }
                                                                /**
                                                                 * @notice Aggregator round (NOT OCR round) in which last report was transmitted
                                                                 */
                                                                function latestRound()
                                                                  public
                                                                  override
                                                                  view
                                                                  virtual
                                                                  returns (uint256)
                                                                {
                                                                  return s_hotVars.latestAggregatorRoundId;
                                                                }
                                                                /**
                                                                 * @notice median of report from given aggregator round (NOT OCR round)
                                                                 * @param _roundId the aggregator round of the target report
                                                                 */
                                                                function getAnswer(uint256 _roundId)
                                                                  public
                                                                  override
                                                                  view
                                                                  virtual
                                                                  returns (int256)
                                                                {
                                                                  if (_roundId > 0xFFFFFFFF) { return 0; }
                                                                  return s_transmissions[uint32(_roundId)].answer;
                                                                }
                                                                /**
                                                                 * @notice timestamp of block in which report from given aggregator round was transmitted
                                                                 * @param _roundId aggregator round (NOT OCR round) of target report
                                                                 */
                                                                function getTimestamp(uint256 _roundId)
                                                                  public
                                                                  override
                                                                  view
                                                                  virtual
                                                                  returns (uint256)
                                                                {
                                                                  if (_roundId > 0xFFFFFFFF) { return 0; }
                                                                  return s_transmissions[uint32(_roundId)].timestamp;
                                                                }
                                                                /*
                                                                 * v3 Aggregator interface
                                                                 */
                                                                string constant private V3_NO_DATA_ERROR = "No data present";
                                                                /**
                                                                 * @return answers are stored in fixed-point format, with this many digits of precision
                                                                 */
                                                                uint8 immutable public override decimals;
                                                                /**
                                                                 * @notice aggregator contract version
                                                                 */
                                                                uint256 constant public override version = 4;
                                                                string internal s_description;
                                                                /**
                                                                 * @notice human-readable description of observable this contract is reporting on
                                                                 */
                                                                function description()
                                                                  public
                                                                  override
                                                                  view
                                                                  virtual
                                                                  returns (string memory)
                                                                {
                                                                  return s_description;
                                                                }
                                                                /**
                                                                 * @notice details for the given aggregator round
                                                                 * @param _roundId target aggregator round (NOT OCR round). Must fit in uint32
                                                                 * @return roundId _roundId
                                                                 * @return answer median of report from given _roundId
                                                                 * @return startedAt timestamp of block in which report from given _roundId was transmitted
                                                                 * @return updatedAt timestamp of block in which report from given _roundId was transmitted
                                                                 * @return answeredInRound _roundId
                                                                 */
                                                                function getRoundData(uint80 _roundId)
                                                                  public
                                                                  override
                                                                  view
                                                                  virtual
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  require(_roundId <= 0xFFFFFFFF, V3_NO_DATA_ERROR);
                                                                  Transmission memory transmission = s_transmissions[uint32(_roundId)];
                                                                  return (
                                                                    _roundId,
                                                                    transmission.answer,
                                                                    transmission.timestamp,
                                                                    transmission.timestamp,
                                                                    _roundId
                                                                  );
                                                                }
                                                                /**
                                                                 * @notice aggregator details for the most recently transmitted report
                                                                 * @return roundId aggregator round of latest report (NOT OCR round)
                                                                 * @return answer median of latest report
                                                                 * @return startedAt timestamp of block containing latest report
                                                                 * @return updatedAt timestamp of block containing latest report
                                                                 * @return answeredInRound aggregator round of latest report
                                                                 */
                                                                function latestRoundData()
                                                                  public
                                                                  override
                                                                  view
                                                                  virtual
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  )
                                                                {
                                                                  roundId = s_hotVars.latestAggregatorRoundId;
                                                                  // Skipped for compatability with existing FluxAggregator in which latestRoundData never reverts.
                                                                  // require(roundId != 0, V3_NO_DATA_ERROR);
                                                                  Transmission memory transmission = s_transmissions[uint32(roundId)];
                                                                  return (
                                                                    roundId,
                                                                    transmission.answer,
                                                                    transmission.timestamp,
                                                                    transmission.timestamp,
                                                                    roundId
                                                                  );
                                                                }
                                                              }
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.0;
                                                              interface AccessControllerInterface {
                                                                function hasAccess(address user, bytes calldata data) external view returns (bool);
                                                              }
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.0;
                                                              import "./AggregatorInterface.sol";
                                                              import "./AggregatorV3Interface.sol";
                                                              interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
                                                              {
                                                              }// SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.0;
                                                              interface AggregatorInterface {
                                                                function latestAnswer() external view returns (int256);
                                                                function latestTimestamp() external view returns (uint256);
                                                                function latestRound() external view returns (uint256);
                                                                function getAnswer(uint256 roundId) external view returns (int256);
                                                                function getTimestamp(uint256 roundId) external view returns (uint256);
                                                                event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
                                                                event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
                                                              }
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.0;
                                                              interface AggregatorV3Interface {
                                                                function decimals() external view returns (uint8);
                                                                function description() external view returns (string memory);
                                                                function version() external view returns (uint256);
                                                                // getRoundData and latestRoundData should both raise "No data present"
                                                                // if they do not have data to report, instead of returning unset values
                                                                // which could be misinterpreted as actual reported values.
                                                                function getRoundData(uint80 _roundId)
                                                                  external
                                                                  view
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  );
                                                                function latestRoundData()
                                                                  external
                                                                  view
                                                                  returns (
                                                                    uint80 roundId,
                                                                    int256 answer,
                                                                    uint256 startedAt,
                                                                    uint256 updatedAt,
                                                                    uint80 answeredInRound
                                                                  );
                                                              }
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.0;
                                                              interface AggregatorValidatorInterface {
                                                                function validate(
                                                                  uint256 previousRoundId,
                                                                  int256 previousAnswer,
                                                                  uint256 currentRoundId,
                                                                  int256 currentAnswer
                                                                ) external returns (bool);
                                                              }// SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.1;
                                                              interface LinkTokenInterface {
                                                                function allowance(address owner, address spender) external view returns (uint256 remaining);
                                                                function approve(address spender, uint256 value) external returns (bool success);
                                                                function balanceOf(address owner) external view returns (uint256 balance);
                                                                function decimals() external view returns (uint8 decimalPlaces);
                                                                function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
                                                                function increaseApproval(address spender, uint256 subtractedValue) external;
                                                                function name() external view returns (string memory tokenName);
                                                                function symbol() external view returns (string memory tokenSymbol);
                                                                function totalSupply() external view returns (uint256 totalTokensIssued);
                                                                function transfer(address to, uint256 value) external returns (bool success);
                                                                function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success);
                                                                function transferFrom(address from, address to, uint256 value) external returns (bool success);
                                                              }
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.0;
                                                              /**
                                                               * @title The Owned contract
                                                               * @notice A contract with helpers for basic contract ownership.
                                                               */
                                                              contract Owned {
                                                                address payable public owner;
                                                                address private pendingOwner;
                                                                event OwnershipTransferRequested(
                                                                  address indexed from,
                                                                  address indexed to
                                                                );
                                                                event OwnershipTransferred(
                                                                  address indexed from,
                                                                  address indexed to
                                                                );
                                                                constructor() {
                                                                  owner = msg.sender;
                                                                }
                                                                /**
                                                                 * @dev Allows an owner to begin transferring ownership to a new address,
                                                                 * pending.
                                                                 */
                                                                function transferOwnership(address _to)
                                                                  external
                                                                  onlyOwner()
                                                                {
                                                                  pendingOwner = _to;
                                                                  emit OwnershipTransferRequested(owner, _to);
                                                                }
                                                                /**
                                                                 * @dev Allows an ownership transfer to be completed by the recipient.
                                                                 */
                                                                function acceptOwnership()
                                                                  external
                                                                {
                                                                  require(msg.sender == pendingOwner, "Must be proposed owner");
                                                                  address oldOwner = owner;
                                                                  owner = msg.sender;
                                                                  pendingOwner = address(0);
                                                                  emit OwnershipTransferred(oldOwner, msg.sender);
                                                                }
                                                                /**
                                                                 * @dev Reverts if called by anyone other than the contract owner.
                                                                 */
                                                                modifier onlyOwner() {
                                                                  require(msg.sender == owner, "Only callable by owner");
                                                                  _;
                                                                }
                                                              }
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.0;
                                                              import "./AccessControllerInterface.sol";
                                                              import "./LinkTokenInterface.sol";
                                                              import "./Owned.sol";
                                                              /**
                                                               * @notice tracks administration of oracle-reward and gas-reimbursement parameters.
                                                               * @dev
                                                               * If you read or change this, be sure to read or adjust the comments. They
                                                               * track the units of the values under consideration, and are crucial to
                                                               * the readability of the operations it specifies.
                                                               * @notice
                                                               * Trust Model:
                                                               * Nothing in this contract prevents a billing admin from setting insane
                                                               * values for the billing parameters in setBilling. Oracles
                                                               * participating in this contract should regularly check that the
                                                               * parameters make sense. Similarly, the outstanding obligations of this
                                                               * contract to the oracles can exceed the funds held by the contract.
                                                               * Oracles participating in this contract should regularly check that it
                                                               * holds sufficient funds and stop interacting with it if funding runs
                                                               * out.
                                                               * This still leaves oracles with some risk due to TOCTOU issues.
                                                               * However, since the sums involved are pretty small (Ethereum
                                                               * transactions aren't that expensive in the end) and an oracle would
                                                               * likely stop participating in a contract it repeatedly lost money on,
                                                               * this risk is deemed acceptable. Oracles should also regularly
                                                               * withdraw any funds in the contract to prevent issues where the
                                                               * contract becomes underfunded at a later time, and different oracles
                                                               * are competing for the left-over funds.
                                                               * Finally, note that any change to the set of oracles or to the billing
                                                               * parameters will trigger payout of all oracles first (using the old
                                                               * parameters), a billing admin cannot take away funds that are already
                                                               * marked for payment.
                                                              */
                                                              contract OffchainAggregatorBilling is Owned {
                                                                // Maximum number of oracles the offchain reporting protocol is designed for
                                                                uint256 constant internal maxNumOracles = 31;
                                                                // Parameters for oracle payments
                                                                struct Billing {
                                                                  // Highest compensated gas price, in ETH-gwei uints
                                                                  uint32 maximumGasPrice;
                                                                  // If gas price is less (in ETH-gwei units), transmitter gets half the savings
                                                                  uint32 reasonableGasPrice;
                                                                  // Pay transmitter back this much LINK per unit eth spent on gas
                                                                  // (1e-6LINK/ETH units)
                                                                  uint32 microLinkPerEth;
                                                                  // Fixed LINK reward for each observer, in LINK-gwei units
                                                                  uint32 linkGweiPerObservation;
                                                                  // Fixed reward for transmitter, in linkGweiPerObservation units
                                                                  uint32 linkGweiPerTransmission;
                                                                }
                                                                Billing internal s_billing;
                                                                /**
                                                                * @return LINK token contract used for billing
                                                                */
                                                                LinkTokenInterface immutable public LINK;
                                                                AccessControllerInterface internal s_billingAccessController;
                                                                // ith element is number of observation rewards due to ith process, plus one.
                                                                // This is expected to saturate after an oracle has submitted 65,535
                                                                // observations, or about 65535/(3*24*20) = 45 days, given a transmission
                                                                // every 3 minutes.
                                                                //
                                                                // This is always one greater than the actual value, so that when the value is
                                                                // reset to zero, we don't end up with a zero value in storage (which would
                                                                // result in a higher gas cost, the next time the value is incremented.)
                                                                // Calculations using this variable need to take that offset into account.
                                                                uint16[maxNumOracles] internal s_oracleObservationsCounts;
                                                                // Addresses at which oracles want to receive payments, by transmitter address
                                                                mapping (address /* transmitter */ => address /* payment address */)
                                                                  internal
                                                                  s_payees;
                                                                // Payee addresses which must be approved by the owner
                                                                mapping (address /* transmitter */ => address /* payment address */)
                                                                  internal
                                                                  s_proposedPayees;
                                                                // LINK-wei-denominated reimbursements for gas used by transmitters.
                                                                //
                                                                // This is always one greater than the actual value, so that when the value is
                                                                // reset to zero, we don't end up with a zero value in storage (which would
                                                                // result in a higher gas cost, the next time the value is incremented.)
                                                                // Calculations using this variable need to take that offset into account.
                                                                //
                                                                // Argument for overflow safety:
                                                                // We have the following maximum intermediate values:
                                                                // - 2**40 additions to this variable (epochAndRound is a uint40)
                                                                // - 2**32 gas price in ethgwei/gas
                                                                // - 1e9 ethwei/ethgwei
                                                                // - 2**32 gas since the block gas limit is at ~20 million
                                                                // - 2**32 (microlink/eth)
                                                                // And we have 2**40 * 2**32 * 1e9 * 2**32 * 2**32 < 2**166
                                                                // (we also divide in some places, but that only makes the value smaller)
                                                                // We can thus safely use uint256 intermediate values for the computation
                                                                // updating this variable.
                                                                uint256[maxNumOracles] internal s_gasReimbursementsLinkWei;
                                                                // Used for s_oracles[a].role, where a is an address, to track the purpose
                                                                // of the address, or to indicate that the address is unset.
                                                                enum Role {
                                                                  // No oracle role has been set for address a
                                                                  Unset,
                                                                  // Signing address for the s_oracles[a].index'th oracle. I.e., report
                                                                  // signatures from this oracle should ecrecover back to address a.
                                                                  Signer,
                                                                  // Transmission address for the s_oracles[a].index'th oracle. I.e., if a
                                                                  // report is received by OffchainAggregator.transmit in which msg.sender is
                                                                  // a, it is attributed to the s_oracles[a].index'th oracle.
                                                                  Transmitter
                                                                }
                                                                struct Oracle {
                                                                  uint8 index; // Index of oracle in s_signers/s_transmitters
                                                                  Role role;   // Role of the address which mapped to this struct
                                                                }
                                                                mapping (address /* signer OR transmitter address */ => Oracle)
                                                                  internal s_oracles;
                                                                // s_signers contains the signing address of each oracle
                                                                address[] internal s_signers;
                                                                // s_transmitters contains the transmission address of each oracle,
                                                                // i.e. the address the oracle actually sends transactions to the contract from
                                                                address[] internal s_transmitters;
                                                                uint256 constant private  maxUint16 = (1 << 16) - 1;
                                                                uint256 constant internal maxUint128 = (1 << 128) - 1;
                                                                constructor(
                                                                  uint32 _maximumGasPrice,
                                                                  uint32 _reasonableGasPrice,
                                                                  uint32 _microLinkPerEth,
                                                                  uint32 _linkGweiPerObservation,
                                                                  uint32 _linkGweiPerTransmission,
                                                                  address _link,
                                                                  AccessControllerInterface _billingAccessController
                                                                )
                                                                {
                                                                  setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                                                                    _linkGweiPerObservation, _linkGweiPerTransmission);
                                                                  setBillingAccessControllerInternal(_billingAccessController);
                                                                  LINK = LinkTokenInterface(_link);
                                                                  uint16[maxNumOracles] memory counts; // See s_oracleObservationsCounts docstring
                                                                  uint256[maxNumOracles] memory gas; // see s_gasReimbursementsLinkWei docstring
                                                                  for (uint8 i = 0; i < maxNumOracles; i++) {
                                                                    counts[i] = 1;
                                                                    gas[i] = 1;
                                                                  }
                                                                  s_oracleObservationsCounts = counts;
                                                                  s_gasReimbursementsLinkWei = gas;
                                                                }
                                                                /**
                                                                 * @notice emitted when billing parameters are set
                                                                 * @param maximumGasPrice highest gas price for which transmitter will be compensated
                                                                 * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
                                                                 * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
                                                                 * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
                                                                 * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
                                                                 */
                                                                event BillingSet(
                                                                  uint32 maximumGasPrice,
                                                                  uint32 reasonableGasPrice,
                                                                  uint32 microLinkPerEth,
                                                                  uint32 linkGweiPerObservation,
                                                                  uint32 linkGweiPerTransmission
                                                                );
                                                                function setBillingInternal(
                                                                  uint32 _maximumGasPrice,
                                                                  uint32 _reasonableGasPrice,
                                                                  uint32 _microLinkPerEth,
                                                                  uint32 _linkGweiPerObservation,
                                                                  uint32 _linkGweiPerTransmission
                                                                )
                                                                  internal
                                                                {
                                                                  s_billing = Billing(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                                                                    _linkGweiPerObservation, _linkGweiPerTransmission);
                                                                  emit BillingSet(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                                                                    _linkGweiPerObservation, _linkGweiPerTransmission);
                                                                }
                                                                /**
                                                                 * @notice sets billing parameters
                                                                 * @param _maximumGasPrice highest gas price for which transmitter will be compensated
                                                                 * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
                                                                 * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
                                                                 * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
                                                                 * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
                                                                 * @dev access control provided by billingAccessController
                                                                 */
                                                                function setBilling(
                                                                  uint32 _maximumGasPrice,
                                                                  uint32 _reasonableGasPrice,
                                                                  uint32 _microLinkPerEth,
                                                                  uint32 _linkGweiPerObservation,
                                                                  uint32 _linkGweiPerTransmission
                                                                )
                                                                  external
                                                                {
                                                                  AccessControllerInterface access = s_billingAccessController;
                                                                  require(msg.sender == owner || access.hasAccess(msg.sender, msg.data),
                                                                    "Only owner&billingAdmin can call");
                                                                  payOracles();
                                                                  setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                                                                    _linkGweiPerObservation, _linkGweiPerTransmission);
                                                                }
                                                                /**
                                                                 * @notice gets billing parameters
                                                                 * @param maximumGasPrice highest gas price for which transmitter will be compensated
                                                                 * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
                                                                 * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
                                                                 * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
                                                                 * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
                                                                 */
                                                                function getBilling()
                                                                  external
                                                                  view
                                                                  returns (
                                                                    uint32 maximumGasPrice,
                                                                    uint32 reasonableGasPrice,
                                                                    uint32 microLinkPerEth,
                                                                    uint32 linkGweiPerObservation,
                                                                    uint32 linkGweiPerTransmission
                                                                  )
                                                                {
                                                                  Billing memory billing = s_billing;
                                                                  return (
                                                                    billing.maximumGasPrice,
                                                                    billing.reasonableGasPrice,
                                                                    billing.microLinkPerEth,
                                                                    billing.linkGweiPerObservation,
                                                                    billing.linkGweiPerTransmission
                                                                  );
                                                                }
                                                                /**
                                                                 * @notice emitted when a new access-control contract is set
                                                                 * @param old the address prior to the current setting
                                                                 * @param current the address of the new access-control contract
                                                                 */
                                                                event BillingAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
                                                                function setBillingAccessControllerInternal(AccessControllerInterface _billingAccessController)
                                                                  internal
                                                                {
                                                                  AccessControllerInterface oldController = s_billingAccessController;
                                                                  if (_billingAccessController != oldController) {
                                                                    s_billingAccessController = _billingAccessController;
                                                                    emit BillingAccessControllerSet(
                                                                      oldController,
                                                                      _billingAccessController
                                                                    );
                                                                  }
                                                                }
                                                                /**
                                                                 * @notice sets billingAccessController
                                                                 * @param _billingAccessController new billingAccessController contract address
                                                                 * @dev only owner can call this
                                                                 */
                                                                function setBillingAccessController(AccessControllerInterface _billingAccessController)
                                                                  external
                                                                  onlyOwner
                                                                {
                                                                  setBillingAccessControllerInternal(_billingAccessController);
                                                                }
                                                                /**
                                                                 * @notice gets billingAccessController
                                                                 * @return address of billingAccessController contract
                                                                 */
                                                                function billingAccessController()
                                                                  external
                                                                  view
                                                                  returns (AccessControllerInterface)
                                                                {
                                                                  return s_billingAccessController;
                                                                }
                                                                /**
                                                                 * @notice withdraws an oracle's payment from the contract
                                                                 * @param _transmitter the transmitter address of the oracle
                                                                 * @dev must be called by oracle's payee address
                                                                 */
                                                                function withdrawPayment(address _transmitter)
                                                                  external
                                                                {
                                                                  require(msg.sender == s_payees[_transmitter], "Only payee can withdraw");
                                                                  payOracle(_transmitter);
                                                                }
                                                                /**
                                                                 * @notice query an oracle's payment amount
                                                                 * @param _transmitter the transmitter address of the oracle
                                                                 */
                                                                function owedPayment(address _transmitter)
                                                                  public
                                                                  view
                                                                  returns (uint256)
                                                                {
                                                                  Oracle memory oracle = s_oracles[_transmitter];
                                                                  if (oracle.role == Role.Unset) { return 0; }
                                                                  Billing memory billing = s_billing;
                                                                  uint256 linkWeiAmount =
                                                                    uint256(s_oracleObservationsCounts[oracle.index] - 1) *
                                                                    uint256(billing.linkGweiPerObservation) *
                                                                    (1 gwei);
                                                                  linkWeiAmount += s_gasReimbursementsLinkWei[oracle.index] - 1;
                                                                  return linkWeiAmount;
                                                                }
                                                                /**
                                                                 * @notice emitted when an oracle has been paid LINK
                                                                 * @param transmitter address from which the oracle sends reports to the transmit method
                                                                 * @param payee address to which the payment is sent
                                                                 * @param amount amount of LINK sent
                                                                 */
                                                                event OraclePaid(address transmitter, address payee, uint256 amount);
                                                                // payOracle pays out _transmitter's balance to the corresponding payee, and zeros it out
                                                                function payOracle(address _transmitter)
                                                                  internal
                                                                {
                                                                  Oracle memory oracle = s_oracles[_transmitter];
                                                                  uint256 linkWeiAmount = owedPayment(_transmitter);
                                                                  if (linkWeiAmount > 0) {
                                                                    address payee = s_payees[_transmitter];
                                                                    // Poses no re-entrancy issues, because LINK.transfer does not yield
                                                                    // control flow.
                                                                    require(LINK.transfer(payee, linkWeiAmount), "insufficient funds");
                                                                    s_oracleObservationsCounts[oracle.index] = 1; // "zero" the counts. see var's docstring
                                                                    s_gasReimbursementsLinkWei[oracle.index] = 1; // "zero" the counts. see var's docstring
                                                                    emit OraclePaid(_transmitter, payee, linkWeiAmount);
                                                                  }
                                                                }
                                                                // payOracles pays out all transmitters, and zeros out their balances.
                                                                //
                                                                // It's much more gas-efficient to do this as a single operation, to avoid
                                                                // hitting storage too much.
                                                                function payOracles()
                                                                  internal
                                                                {
                                                                  Billing memory billing = s_billing;
                                                                  uint16[maxNumOracles] memory observationsCounts = s_oracleObservationsCounts;
                                                                  uint256[maxNumOracles] memory gasReimbursementsLinkWei =
                                                                    s_gasReimbursementsLinkWei;
                                                                  address[] memory transmitters = s_transmitters;
                                                                  for (uint transmitteridx = 0; transmitteridx < transmitters.length; transmitteridx++) {
                                                                    uint256 reimbursementAmountLinkWei = gasReimbursementsLinkWei[transmitteridx] - 1;
                                                                    uint256 obsCount = observationsCounts[transmitteridx] - 1;
                                                                    uint256 linkWeiAmount =
                                                                      obsCount * uint256(billing.linkGweiPerObservation) * (1 gwei) + reimbursementAmountLinkWei;
                                                                    if (linkWeiAmount > 0) {
                                                                        address payee = s_payees[transmitters[transmitteridx]];
                                                                        // Poses no re-entrancy issues, because LINK.transfer does not yield
                                                                        // control flow.
                                                                        require(LINK.transfer(payee, linkWeiAmount), "insufficient funds");
                                                                        observationsCounts[transmitteridx] = 1;       // "zero" the counts.
                                                                        gasReimbursementsLinkWei[transmitteridx] = 1; // "zero" the counts.
                                                                        emit OraclePaid(transmitters[transmitteridx], payee, linkWeiAmount);
                                                                      }
                                                                  }
                                                                  // "Zero" the accounting storage variables
                                                                  s_oracleObservationsCounts = observationsCounts;
                                                                  s_gasReimbursementsLinkWei = gasReimbursementsLinkWei;
                                                                }
                                                                function oracleRewards(
                                                                  bytes memory observers,
                                                                  uint16[maxNumOracles] memory observations
                                                                )
                                                                  internal
                                                                  pure
                                                                  returns (uint16[maxNumOracles] memory)
                                                                {
                                                                  // reward each observer-participant with the observer reward
                                                                  for (uint obsIdx = 0; obsIdx < observers.length; obsIdx++) {
                                                                    uint8 observer = uint8(observers[obsIdx]);
                                                                    observations[observer] = saturatingAddUint16(observations[observer], 1);
                                                                  }
                                                                  return observations;
                                                                }
                                                                // This value needs to change if maxNumOracles is increased, or the accounting
                                                                // calculations at the bottom of reimburseAndRewardOracles change.
                                                                //
                                                                // To recalculate it, run the profiler as described in
                                                                // ../../profile/README.md, and add up the gas-usage values reported for the
                                                                // lines in reimburseAndRewardOracles following the "gasLeft = gasleft()"
                                                                // line. E.g., you will see output like this:
                                                                //
                                                                //      7        uint256 gasLeft = gasleft();
                                                                //     29        uint256 gasCostEthWei = transmitterGasCostEthWei(
                                                                //      9          uint256(initialGas),
                                                                //      3          gasPrice,
                                                                //      3          callDataGasCost,
                                                                //      3          gasLeft
                                                                //      .
                                                                //      .
                                                                //      .
                                                                //     59        uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
                                                                //      .
                                                                //      .
                                                                //      .
                                                                //   5047        s_gasReimbursementsLinkWei[txOracle.index] =
                                                                //    856          s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
                                                                //     26          uint256(billing.linkGweiPerTransmission) * (1 gwei);
                                                                //
                                                                // If those were the only lines to be accounted for, you would add up
                                                                // 29+9+3+3+3+59+5047+856+26=6035.
                                                                uint256 internal constant accountingGasCost = 6035;
                                                                // Uncomment the following declaration to compute the remaining gas cost after
                                                                // above gasleft(). (This must exist in a base class to OffchainAggregator, so
                                                                // it can't go in TestOffchainAggregator.)
                                                                //
                                                                // uint256 public gasUsedInAccounting;
                                                                // Gas price at which the transmitter should be reimbursed, in ETH-gwei/gas
                                                                function impliedGasPrice(
                                                                  uint256 txGasPrice,         // ETH-gwei/gas units
                                                                  uint256 reasonableGasPrice, // ETH-gwei/gas units
                                                                  uint256 maximumGasPrice     // ETH-gwei/gas units
                                                                )
                                                                  internal
                                                                  pure
                                                                  returns (uint256)
                                                                {
                                                                  // Reward the transmitter for choosing an efficient gas price: if they manage
                                                                  // to come in lower than considered reasonable, give them half the savings.
                                                                  //
                                                                  // The following calculations are all in units of gwei/gas, i.e. 1e-9ETH/gas
                                                                  uint256 gasPrice = txGasPrice;
                                                                  if (txGasPrice < reasonableGasPrice) {
                                                                    // Give transmitter half the savings for coming in under the reasonable gas price
                                                                    gasPrice += (reasonableGasPrice - txGasPrice) / 2;
                                                                  }
                                                                  // Don't reimburse a gas price higher than maximumGasPrice
                                                                  return min(gasPrice, maximumGasPrice);
                                                                }
                                                                // gas reimbursement due the transmitter, in ETH-wei
                                                                //
                                                                // If this function is changed, accountingGasCost needs to change, too. See
                                                                // its docstring
                                                                function transmitterGasCostEthWei(
                                                                  uint256 initialGas,
                                                                  uint256 gasPrice, // ETH-gwei/gas units
                                                                  uint256 callDataCost, // gas units
                                                                  uint256 gasLeft
                                                                )
                                                                  internal
                                                                  pure
                                                                  returns (uint128 gasCostEthWei)
                                                                {
                                                                  require(initialGas >= gasLeft, "gasLeft cannot exceed initialGas");
                                                                  uint256 gasUsed = // gas units
                                                                    initialGas - gasLeft + // observed gas usage
                                                                    callDataCost + accountingGasCost; // estimated gas usage
                                                                  // gasUsed is in gas units, gasPrice is in ETH-gwei/gas units; convert to ETH-wei
                                                                  uint256 fullGasCostEthWei = gasUsed * gasPrice * (1 gwei);
                                                                  assert(fullGasCostEthWei < maxUint128); // the entire ETH supply fits in a uint128...
                                                                  return uint128(fullGasCostEthWei);
                                                                }
                                                                /**
                                                                 * @notice withdraw any available funds left in the contract, up to _amount, after accounting for the funds due to participants in past reports
                                                                 * @param _recipient address to send funds to
                                                                 * @param _amount maximum amount to withdraw, denominated in LINK-wei.
                                                                 * @dev access control provided by billingAccessController
                                                                 */
                                                                function withdrawFunds(address _recipient, uint256 _amount)
                                                                  external
                                                                {
                                                                  require(msg.sender == owner || s_billingAccessController.hasAccess(msg.sender, msg.data),
                                                                    "Only owner&billingAdmin can call");
                                                                  uint256 linkDue = totalLINKDue();
                                                                  uint256 linkBalance = LINK.balanceOf(address(this));
                                                                  require(linkBalance >= linkDue, "insufficient balance");
                                                                  require(LINK.transfer(_recipient, min(linkBalance - linkDue, _amount)), "insufficient funds");
                                                                }
                                                                // Total LINK due to participants in past reports.
                                                                function totalLINKDue()
                                                                  internal
                                                                  view
                                                                  returns (uint256 linkDue)
                                                                {
                                                                  // Argument for overflow safety: We do all computations in
                                                                  // uint256s. The inputs to linkDue are:
                                                                  // - the <= 31 observation rewards each of which has less than
                                                                  //   64 bits (32 bits for billing.linkGweiPerObservation, 32 bits
                                                                  //   for wei/gwei conversion). Hence 69 bits are sufficient for this part.
                                                                  // - the <= 31 gas reimbursements, each of which consists of at most 166
                                                                  //   bits (see s_gasReimbursementsLinkWei docstring). Hence 171 bits are
                                                                  //   sufficient for this part
                                                                  // In total, 172 bits are enough.
                                                                  uint16[maxNumOracles] memory observationCounts = s_oracleObservationsCounts;
                                                                  for (uint i = 0; i < maxNumOracles; i++) {
                                                                    linkDue += observationCounts[i] - 1; // Stored value is one greater than actual value
                                                                  }
                                                                  Billing memory billing = s_billing;
                                                                  // Convert linkGweiPerObservation to uint256, or this overflows!
                                                                  linkDue *= uint256(billing.linkGweiPerObservation) * (1 gwei);
                                                                  address[] memory transmitters = s_transmitters;
                                                                  uint256[maxNumOracles] memory gasReimbursementsLinkWei =
                                                                    s_gasReimbursementsLinkWei;
                                                                  for (uint i = 0; i < transmitters.length; i++) {
                                                                    linkDue += uint256(gasReimbursementsLinkWei[i]-1); // Stored value is one greater than actual value
                                                                  }
                                                                }
                                                                /**
                                                                 * @notice allows oracles to check that sufficient LINK balance is available
                                                                 * @return availableBalance LINK available on this contract, after accounting for outstanding obligations. can become negative
                                                                 */
                                                                function linkAvailableForPayment()
                                                                  external
                                                                  view
                                                                  returns (int256 availableBalance)
                                                                {
                                                                  // there are at most one billion LINK, so this cast is safe
                                                                  int256 balance = int256(LINK.balanceOf(address(this)));
                                                                  // according to the argument in the definition of totalLINKDue,
                                                                  // totalLINKDue is never greater than 2**172, so this cast is safe
                                                                  int256 due = int256(totalLINKDue());
                                                                  // safe from overflow according to above sizes
                                                                  return int256(balance) - int256(due);
                                                                }
                                                                /**
                                                                 * @notice number of observations oracle is due to be reimbursed for
                                                                 * @param _signerOrTransmitter address used by oracle for signing or transmitting reports
                                                                 */
                                                                function oracleObservationCount(address _signerOrTransmitter)
                                                                  external
                                                                  view
                                                                  returns (uint16)
                                                                {
                                                                  Oracle memory oracle = s_oracles[_signerOrTransmitter];
                                                                  if (oracle.role == Role.Unset) { return 0; }
                                                                  return s_oracleObservationsCounts[oracle.index] - 1;
                                                                }
                                                                function reimburseAndRewardOracles(
                                                                  uint32 initialGas,
                                                                  bytes memory observers
                                                                )
                                                                  internal
                                                                {
                                                                  Oracle memory txOracle = s_oracles[msg.sender];
                                                                  Billing memory billing = s_billing;
                                                                  // Reward oracles for providing observations. Oracles are not rewarded
                                                                  // for providing signatures, because signing is essentially free.
                                                                  s_oracleObservationsCounts =
                                                                    oracleRewards(observers, s_oracleObservationsCounts);
                                                                  // Reimburse transmitter of the report for gas usage
                                                                  require(txOracle.role == Role.Transmitter,
                                                                    "sent by undesignated transmitter"
                                                                  );
                                                                  uint256 gasPrice = impliedGasPrice(
                                                                    tx.gasprice / (1 gwei), // convert to ETH-gwei units
                                                                    billing.reasonableGasPrice,
                                                                    billing.maximumGasPrice
                                                                  );
                                                                  // The following is only an upper bound, as it ignores the cheaper cost for
                                                                  // 0 bytes. Safe from overflow, because calldata just isn't that long.
                                                                  uint256 callDataGasCost = 16 * msg.data.length;
                                                                  // If any changes are made to subsequent calculations, accountingGasCost
                                                                  // needs to change, too.
                                                                  uint256 gasLeft = gasleft();
                                                                  uint256 gasCostEthWei = transmitterGasCostEthWei(
                                                                    uint256(initialGas),
                                                                    gasPrice,
                                                                    callDataGasCost,
                                                                    gasLeft
                                                                  );
                                                                  // microLinkPerEth is 1e-6LINK/ETH units, gasCostEthWei is 1e-18ETH units
                                                                  // (ETH-wei), product is 1e-24LINK-wei units, dividing by 1e6 gives
                                                                  // 1e-18LINK units, i.e. LINK-wei units
                                                                  // Safe from over/underflow, since all components are non-negative,
                                                                  // gasCostEthWei will always fit into uint128 and microLinkPerEth is a
                                                                  // uint32 (128+32 < 256!).
                                                                  uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
                                                                  // Safe from overflow, because gasCostLinkWei < 2**160 and
                                                                  // billing.linkGweiPerTransmission * (1 gwei) < 2**64 and we increment
                                                                  // s_gasReimbursementsLinkWei[txOracle.index] at most 2**40 times.
                                                                  s_gasReimbursementsLinkWei[txOracle.index] =
                                                                    s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
                                                                    uint256(billing.linkGweiPerTransmission) * (1 gwei); // convert from linkGwei to linkWei
                                                                  // Uncomment next line to compute the remaining gas cost after above gasleft().
                                                                  // See OffchainAggregatorBilling.accountingGasCost docstring for more information.
                                                                  //
                                                                  // gasUsedInAccounting = gasLeft - gasleft();
                                                                }
                                                                /*
                                                                 * Payee management
                                                                 */
                                                                /**
                                                                 * @notice emitted when a transfer of an oracle's payee address has been initiated
                                                                 * @param transmitter address from which the oracle sends reports to the transmit method
                                                                 * @param current the payeee address for the oracle, prior to this setting
                                                                 * @param proposed the proposed new payee address for the oracle
                                                                 */
                                                                event PayeeshipTransferRequested(
                                                                  address indexed transmitter,
                                                                  address indexed current,
                                                                  address indexed proposed
                                                                );
                                                                /**
                                                                 * @notice emitted when a transfer of an oracle's payee address has been completed
                                                                 * @param transmitter address from which the oracle sends reports to the transmit method
                                                                 * @param current the payeee address for the oracle, prior to this setting
                                                                 */
                                                                event PayeeshipTransferred(
                                                                  address indexed transmitter,
                                                                  address indexed previous,
                                                                  address indexed current
                                                                );
                                                                /**
                                                                 * @notice sets the payees for transmitting addresses
                                                                 * @param _transmitters addresses oracles use to transmit the reports
                                                                 * @param _payees addresses of payees corresponding to list of transmitters
                                                                 * @dev must be called by owner
                                                                 * @dev cannot be used to change payee addresses, only to initially populate them
                                                                 */
                                                                function setPayees(
                                                                  address[] calldata _transmitters,
                                                                  address[] calldata _payees
                                                                )
                                                                  external
                                                                  onlyOwner()
                                                                {
                                                                  require(_transmitters.length == _payees.length, "transmitters.size != payees.size");
                                                                  for (uint i = 0; i < _transmitters.length; i++) {
                                                                    address transmitter = _transmitters[i];
                                                                    address payee = _payees[i];
                                                                    address currentPayee = s_payees[transmitter];
                                                                    bool zeroedOut = currentPayee == address(0);
                                                                    require(zeroedOut || currentPayee == payee, "payee already set");
                                                                    s_payees[transmitter] = payee;
                                                                    if (currentPayee != payee) {
                                                                      emit PayeeshipTransferred(transmitter, currentPayee, payee);
                                                                    }
                                                                  }
                                                                }
                                                                /**
                                                                 * @notice first step of payeeship transfer (safe transfer pattern)
                                                                 * @param _transmitter transmitter address of oracle whose payee is changing
                                                                 * @param _proposed new payee address
                                                                 * @dev can only be called by payee address
                                                                 */
                                                                function transferPayeeship(
                                                                  address _transmitter,
                                                                  address _proposed
                                                                )
                                                                  external
                                                                {
                                                                    require(msg.sender == s_payees[_transmitter], "only current payee can update");
                                                                    require(msg.sender != _proposed, "cannot transfer to self");
                                                                    address previousProposed = s_proposedPayees[_transmitter];
                                                                    s_proposedPayees[_transmitter] = _proposed;
                                                                    if (previousProposed != _proposed) {
                                                                      emit PayeeshipTransferRequested(_transmitter, msg.sender, _proposed);
                                                                    }
                                                                }
                                                                /**
                                                                 * @notice second step of payeeship transfer (safe transfer pattern)
                                                                 * @param _transmitter transmitter address of oracle whose payee is changing
                                                                 * @dev can only be called by proposed new payee address
                                                                 */
                                                                function acceptPayeeship(
                                                                  address _transmitter
                                                                )
                                                                  external
                                                                {
                                                                  require(msg.sender == s_proposedPayees[_transmitter], "only proposed payees can accept");
                                                                  address currentPayee = s_payees[_transmitter];
                                                                  s_payees[_transmitter] = msg.sender;
                                                                  s_proposedPayees[_transmitter] = address(0);
                                                                  emit PayeeshipTransferred(_transmitter, currentPayee, msg.sender);
                                                                }
                                                                /*
                                                                 * Helper functions
                                                                 */
                                                                function saturatingAddUint16(uint16 _x, uint16 _y)
                                                                  internal
                                                                  pure
                                                                  returns (uint16)
                                                                {
                                                                  return uint16(min(uint256(_x)+uint256(_y), maxUint16));
                                                                }
                                                                function min(uint256 a, uint256 b)
                                                                  internal
                                                                  pure
                                                                  returns (uint256)
                                                                {
                                                                  if (a < b) { return a; }
                                                                  return b;
                                                                }
                                                              }
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.1;
                                                              import "./SimpleWriteAccessController.sol";
                                                              /**
                                                               * @title SimpleReadAccessController
                                                               * @notice Gives access to:
                                                               * - any externally owned account (note that offchain actors can always read
                                                               * any contract storage regardless of onchain access control measures, so this
                                                               * does not weaken the access control while improving usability)
                                                               * - accounts explicitly added to an access list
                                                               * @dev SimpleReadAccessController is not suitable for access controlling writes
                                                               * since it grants any externally owned account access! See
                                                               * SimpleWriteAccessController for that.
                                                               */
                                                              contract SimpleReadAccessController is SimpleWriteAccessController {
                                                                /**
                                                                 * @notice Returns the access of an address
                                                                 * @param _user The address to query
                                                                 */
                                                                function hasAccess(
                                                                  address _user,
                                                                  bytes memory _calldata
                                                                )
                                                                  public
                                                                  view
                                                                  virtual
                                                                  override
                                                                  returns (bool)
                                                                {
                                                                  return super.hasAccess(_user, _calldata) || _user == tx.origin;
                                                                }
                                                              }
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.7.0;
                                                              import "./Owned.sol";
                                                              import "./AccessControllerInterface.sol";
                                                              /**
                                                               * @title SimpleWriteAccessController
                                                               * @notice Gives access to accounts explicitly added to an access list by the
                                                               * controller's owner.
                                                               * @dev does not make any special permissions for externally, see
                                                               * SimpleReadAccessController for that.
                                                               */
                                                              contract SimpleWriteAccessController is AccessControllerInterface, Owned {
                                                                bool public checkEnabled;
                                                                mapping(address => bool) internal accessList;
                                                                event AddedAccess(address user);
                                                                event RemovedAccess(address user);
                                                                event CheckAccessEnabled();
                                                                event CheckAccessDisabled();
                                                                constructor()
                                                                {
                                                                  checkEnabled = true;
                                                                }
                                                                /**
                                                                 * @notice Returns the access of an address
                                                                 * @param _user The address to query
                                                                 */
                                                                function hasAccess(
                                                                  address _user,
                                                                  bytes memory
                                                                )
                                                                  public
                                                                  view
                                                                  virtual
                                                                  override
                                                                  returns (bool)
                                                                {
                                                                  return accessList[_user] || !checkEnabled;
                                                                }
                                                                /**
                                                                 * @notice Adds an address to the access list
                                                                 * @param _user The address to add
                                                                 */
                                                                function addAccess(address _user) external onlyOwner() {
                                                                  addAccessInternal(_user);
                                                                }
                                                                function addAccessInternal(address _user) internal {
                                                                  if (!accessList[_user]) {
                                                                    accessList[_user] = true;
                                                                    emit AddedAccess(_user);
                                                                  }
                                                                }
                                                                /**
                                                                 * @notice Removes an address from the access list
                                                                 * @param _user The address to remove
                                                                 */
                                                                function removeAccess(address _user)
                                                                  external
                                                                  onlyOwner()
                                                                {
                                                                  if (accessList[_user]) {
                                                                    accessList[_user] = false;
                                                                    emit RemovedAccess(_user);
                                                                  }
                                                                }
                                                                /**
                                                                 * @notice makes the access check enforced
                                                                 */
                                                                function enableAccessCheck()
                                                                  external
                                                                  onlyOwner()
                                                                {
                                                                  if (!checkEnabled) {
                                                                    checkEnabled = true;
                                                                    emit CheckAccessEnabled();
                                                                  }
                                                                }
                                                                /**
                                                                 * @notice makes the access check unenforced
                                                                 */
                                                                function disableAccessCheck()
                                                                  external
                                                                  onlyOwner()
                                                                {
                                                                  if (checkEnabled) {
                                                                    checkEnabled = false;
                                                                    emit CheckAccessDisabled();
                                                                  }
                                                                }
                                                                /**
                                                                 * @dev reverts if the caller does not have access
                                                                 */
                                                                modifier checkAccess() {
                                                                  require(hasAccess(msg.sender, msg.data), "No access");
                                                                  _;
                                                                }
                                                              }
                                                              

                                                              File 13 of 14: Keep3rV2Oracle
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity ^0.8.2;
                                                              
                                                              interface IUniswapV2Pair {
                                                                  function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
                                                                  function price0CumulativeLast() external view returns (uint);
                                                                  function price1CumulativeLast() external view returns (uint);
                                                                  function token0() external view returns (address);
                                                                  function token1() external view returns (address);
                                                              }
                                                              
                                                              interface IKeep3rV1 {
                                                                  function keepers(address keeper) external returns (bool);
                                                                  function KPRH() external view returns (IKeep3rV1Helper);
                                                                  function receipt(address credit, address keeper, uint amount) external;
                                                              }
                                                              
                                                              interface IKeep3rV1Helper {
                                                                  function getQuoteLimit(uint gasUsed) external view returns (uint);
                                                              }
                                                              
                                                              // sliding oracle that uses observations collected to provide moving price averages in the past
                                                              contract Keep3rV2Oracle {
                                                                  
                                                                  constructor(address _pair) {
                                                                      _factory = msg.sender;
                                                                      pair = _pair;
                                                                      (,,uint32 timestamp) = IUniswapV2Pair(_pair).getReserves();
                                                                      uint112 _price0CumulativeLast = uint112(IUniswapV2Pair(_pair).price0CumulativeLast() * e10 / Q112);
                                                                      uint112 _price1CumulativeLast = uint112(IUniswapV2Pair(_pair).price1CumulativeLast() * e10 / Q112);
                                                                      observations[length++] = Observation(timestamp, _price0CumulativeLast, _price1CumulativeLast);
                                                                  }
                                                              
                                                                  struct Observation {
                                                                      uint32 timestamp;
                                                                      uint112 price0Cumulative;
                                                                      uint112 price1Cumulative;
                                                                  }
                                                              
                                                                  modifier factory() {
                                                                      require(msg.sender == _factory, "!F");
                                                                      _;
                                                                  }
                                                                  
                                                                  Observation[65535] public observations;
                                                                  uint16 public length;
                                                              
                                                                  address immutable _factory;
                                                                  address immutable public pair;
                                                                  // this is redundant with granularity and windowSize, but stored for gas savings & informational purposes.
                                                                  uint constant periodSize = 1800;
                                                                  uint Q112 = 2**112;
                                                                  uint e10 = 10**18;
                                                                  
                                                                  // Pre-cache slots for cheaper oracle writes
                                                                  function cache(uint size) external {
                                                                      uint _length = length+size;
                                                                      for (uint i = length; i < _length; i++) observations[i].timestamp = 1;
                                                                  }
                                                              
                                                                  // update the current feed for free
                                                                  function update() external factory returns (bool) {
                                                                      return _update();
                                                                  }
                                                              
                                                                  function updateable() external view returns (bool) {
                                                                      Observation memory _point = observations[length-1];
                                                                      (,, uint timestamp) = IUniswapV2Pair(pair).getReserves();
                                                                      uint timeElapsed = timestamp - _point.timestamp;
                                                                      return timeElapsed > periodSize;
                                                                  }
                                                              
                                                                  function _update() internal returns (bool) {
                                                                      Observation memory _point = observations[length-1];
                                                                      (,, uint32 timestamp) = IUniswapV2Pair(pair).getReserves();
                                                                      uint32 timeElapsed = timestamp - _point.timestamp;
                                                                      if (timeElapsed > periodSize) {
                                                                          uint112 _price0CumulativeLast = uint112(IUniswapV2Pair(pair).price0CumulativeLast() * e10 / Q112);
                                                                          uint112 _price1CumulativeLast = uint112(IUniswapV2Pair(pair).price1CumulativeLast() * e10 / Q112);
                                                                          observations[length++] = Observation(timestamp, _price0CumulativeLast, _price1CumulativeLast);
                                                                          return true;
                                                                      }
                                                                      return false;
                                                                  }
                                                              
                                                                  function _computeAmountOut(uint start, uint end, uint elapsed, uint amountIn) internal view returns (uint amountOut) {
                                                                      amountOut = amountIn * (end - start) / e10 / elapsed;
                                                                  }
                                                              
                                                                  function current(address tokenIn, uint amountIn, address tokenOut) external view returns (uint amountOut, uint lastUpdatedAgo) {
                                                                      (address token0,) = tokenIn < tokenOut ? (tokenIn, tokenOut) : (tokenOut, tokenIn);
                                                              
                                                                      Observation memory _observation = observations[length-1];
                                                                      uint price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast() * e10 / Q112;
                                                                      uint price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast() * e10 / Q112;
                                                                      (,,uint timestamp) = IUniswapV2Pair(pair).getReserves();
                                                                      
                                                                      // Handle edge cases where we have no updates, will revert on first reading set
                                                                      if (timestamp == _observation.timestamp) {
                                                                          _observation = observations[length-2];
                                                                      }
                                                                      
                                                                      uint timeElapsed = timestamp - _observation.timestamp;
                                                                      timeElapsed = timeElapsed == 0 ? 1 : timeElapsed;
                                                                      if (token0 == tokenIn) {
                                                                          amountOut = _computeAmountOut(_observation.price0Cumulative, price0Cumulative, timeElapsed, amountIn);
                                                                      } else {
                                                                          amountOut = _computeAmountOut(_observation.price1Cumulative, price1Cumulative, timeElapsed, amountIn);
                                                                      }
                                                                      lastUpdatedAgo = timeElapsed;
                                                                  }
                                                              
                                                                  function quote(address tokenIn, uint amountIn, address tokenOut, uint points) external view returns (uint amountOut, uint lastUpdatedAgo) {
                                                                      (address token0,) = tokenIn < tokenOut ? (tokenIn, tokenOut) : (tokenOut, tokenIn);
                                                              
                                                                      uint priceAverageCumulative = 0;
                                                                      uint _length = length-1;
                                                                      uint i = _length - points;
                                                                      Observation memory currentObservation;
                                                                      Observation memory nextObservation;
                                                              
                                                                      uint nextIndex = 0;
                                                                      if (token0 == tokenIn) {
                                                                          for (; i < _length; i++) {
                                                                              nextIndex = i+1;
                                                                              currentObservation = observations[i];
                                                                              nextObservation = observations[nextIndex];
                                                                              priceAverageCumulative += _computeAmountOut(
                                                                                  currentObservation.price0Cumulative,
                                                                                  nextObservation.price0Cumulative, 
                                                                                  nextObservation.timestamp - currentObservation.timestamp, amountIn);
                                                                          }
                                                                      } else {
                                                                          for (; i < _length; i++) {
                                                                              nextIndex = i+1;
                                                                              currentObservation = observations[i];
                                                                              nextObservation = observations[nextIndex];
                                                                              priceAverageCumulative += _computeAmountOut(
                                                                                  currentObservation.price1Cumulative,
                                                                                  nextObservation.price1Cumulative, 
                                                                                  nextObservation.timestamp - currentObservation.timestamp, amountIn);
                                                                          }
                                                                      }
                                                                      amountOut = priceAverageCumulative / points;
                                                                      
                                                                      (,,uint timestamp) = IUniswapV2Pair(pair).getReserves();
                                                                      lastUpdatedAgo = timestamp - nextObservation.timestamp;
                                                                  }
                                                                  
                                                                  function sample(address tokenIn, uint amountIn, address tokenOut, uint points, uint window) external view returns (uint[] memory prices, uint lastUpdatedAgo) {
                                                                      (address token0,) = tokenIn < tokenOut ? (tokenIn, tokenOut) : (tokenOut, tokenIn);
                                                                      prices = new uint[](points);
                                                                      
                                                                      if (token0 == tokenIn) {
                                                                          {
                                                                              uint _length = length-1;
                                                                              uint i = _length - (points * window);
                                                                              uint _index = 0;
                                                                              Observation memory nextObservation;
                                                                              for (; i < _length; i+=window) {
                                                                                  Observation memory currentObservation;
                                                                                  currentObservation = observations[i];
                                                                                  nextObservation = observations[i + window];
                                                                                  prices[_index] = _computeAmountOut(
                                                                                      currentObservation.price0Cumulative,
                                                                                      nextObservation.price0Cumulative, 
                                                                                      nextObservation.timestamp - currentObservation.timestamp, amountIn);
                                                                                  _index = _index + 1;
                                                                              }
                                                                              
                                                                              (,,uint timestamp) = IUniswapV2Pair(pair).getReserves();
                                                                              lastUpdatedAgo = timestamp - nextObservation.timestamp;
                                                                          }
                                                                      } else {
                                                                          {
                                                                              uint _length = length-1;
                                                                              uint i = _length - (points * window);
                                                                              uint _index = 0;
                                                                              Observation memory nextObservation;
                                                                              for (; i < _length; i+=window) {
                                                                                  Observation memory currentObservation;
                                                                                  currentObservation = observations[i];
                                                                                  nextObservation = observations[i + window];
                                                                                  prices[_index] = _computeAmountOut(
                                                                                      currentObservation.price1Cumulative,
                                                                                      nextObservation.price1Cumulative, 
                                                                                      nextObservation.timestamp - currentObservation.timestamp, amountIn);
                                                                                  _index = _index + 1;
                                                                              }
                                                                              
                                                                              (,,uint timestamp) = IUniswapV2Pair(pair).getReserves();
                                                                              lastUpdatedAgo = timestamp - nextObservation.timestamp;
                                                                          }
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              contract Keep3rV2OracleFactory {
                                                                  
                                                                  function pairForSushi(address tokenA, address tokenB) internal pure returns (address pair) {
                                                                      (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
                                                                      pair = address(uint160(uint256(keccak256(abi.encodePacked(
                                                                              hex'ff',
                                                                              0xc35DADB65012eC5796536bD9864eD8773aBc74C4,
                                                                              keccak256(abi.encodePacked(token0, token1)),
                                                                              hex'e18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303' // init code hash
                                                                          )))));
                                                                  }
                                                                  
                                                                  function pairForUni(address tokenA, address tokenB) internal pure returns (address pair) {
                                                                      (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
                                                                      pair = address(uint160(uint256(keccak256(abi.encodePacked(
                                                                              hex'ff',
                                                                              0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f,
                                                                              keccak256(abi.encodePacked(token0, token1)),
                                                                              hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash
                                                                          )))));
                                                                  }
                                                                  
                                                                  modifier keeper() {
                                                                      require(KP3R.keepers(msg.sender), "!K");
                                                                      _;
                                                                  }
                                                              
                                                                  modifier upkeep() {
                                                                      uint _gasUsed = gasleft();
                                                                      require(KP3R.keepers(msg.sender), "!K");
                                                                      _;
                                                                      uint _received = KP3R.KPRH().getQuoteLimit(_gasUsed - gasleft());
                                                                      KP3R.receipt(address(KP3R), msg.sender, _received);
                                                                  }
                                                              
                                                                  address public governance;
                                                                  address public pendingGovernance;
                                                              
                                                                  /**
                                                                   * @notice Allows governance to change governance (for future upgradability)
                                                                   * @param _governance new governance address to set
                                                                   */
                                                                  function setGovernance(address _governance) external {
                                                                      require(msg.sender == governance, "!G");
                                                                      pendingGovernance = _governance;
                                                                  }
                                                              
                                                                  /**
                                                                   * @notice Allows pendingGovernance to accept their role as governance (protection pattern)
                                                                   */
                                                                  function acceptGovernance() external {
                                                                      require(msg.sender == pendingGovernance, "!pG");
                                                                      governance = pendingGovernance;
                                                                  }
                                                              
                                                                  IKeep3rV1 public constant KP3R = IKeep3rV1(0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44);
                                                              
                                                                  address[] internal _pairs;
                                                                  mapping(address => Keep3rV2Oracle) public feeds;
                                                              
                                                                  function pairs() external view returns (address[] memory) {
                                                                      return _pairs;
                                                                  }
                                                              
                                                                  constructor() {
                                                                      governance = msg.sender;
                                                                  }
                                                              
                                                                  function update(address pair) external keeper returns (bool) {
                                                                      return feeds[pair].update();
                                                                  }
                                                                  
                                                                  function byteCode(address pair) external pure returns (bytes memory bytecode) {
                                                                      bytecode = abi.encodePacked(type(Keep3rV2Oracle).creationCode, abi.encode(pair));
                                                                  }
                                                              
                                                                  function deploy(address pair) external returns (address feed) {
                                                                      require(msg.sender == governance, "!G");
                                                                      require(address(feeds[pair]) == address(0), 'PE');
                                                                      bytes memory bytecode = abi.encodePacked(type(Keep3rV2Oracle).creationCode, abi.encode(pair));
                                                                      bytes32 salt = keccak256(abi.encodePacked(pair));
                                                                      assembly {
                                                                          feed := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
                                                                          if iszero(extcodesize(feed)) {
                                                                              revert(0, 0)
                                                                          }
                                                                      }
                                                                      feeds[pair] = Keep3rV2Oracle(feed);
                                                                      _pairs.push(pair);
                                                                  }
                                                                  
                                                                  function work() external upkeep {
                                                                      require(workable(), "!W");
                                                                      for (uint i = 0; i < _pairs.length; i++) {
                                                                          feeds[_pairs[i]].update();
                                                                      }
                                                                  }
                                                              
                                                                  function work(address pair) external upkeep {
                                                                      require(feeds[pair].update(), "!W");
                                                                  }
                                                                  
                                                                  function workForFree() external keeper {
                                                                      for (uint i = 0; i < _pairs.length; i++) {
                                                                          feeds[_pairs[i]].update();
                                                                      }
                                                                  }
                                                              
                                                                  function workForFree(address pair) external keeper {
                                                                      feeds[pair].update();
                                                                  }
                                                                  
                                                                  function cache(uint size) external {
                                                                      for (uint i = 0; i < _pairs.length; i++) {
                                                                          feeds[_pairs[i]].cache(size);
                                                                      }
                                                                  }
                                                                  
                                                                  function cache(address pair, uint size) external {
                                                                      feeds[pair].cache(size);
                                                                  }
                                                              
                                                                  function workable() public view returns (bool canWork) {
                                                                      canWork = true;
                                                                      for (uint i = 0; i < _pairs.length; i++) {
                                                                          if (!feeds[_pairs[i]].updateable()) {
                                                                              canWork = false;
                                                                          }
                                                                      }
                                                                  }
                                                              
                                                                  function workable(address pair) public view returns (bool) {
                                                                      return feeds[pair].updateable();
                                                                  }
                                                                  
                                                                  function sample(address tokenIn, uint amountIn, address tokenOut, uint points, uint window, bool sushiswap) external view returns (uint[] memory prices, uint lastUpdatedAgo) {
                                                                      address _pair = sushiswap ? pairForSushi(tokenIn, tokenOut) : pairForUni(tokenIn, tokenOut);
                                                                      return feeds[_pair].sample(tokenIn, amountIn, tokenOut, points, window);
                                                                  }
                                                                  
                                                                  function sample(address pair, address tokenIn, uint amountIn, address tokenOut, uint points, uint window) external view returns (uint[] memory prices, uint lastUpdatedAgo) {
                                                                      return feeds[pair].sample(tokenIn, amountIn, tokenOut, points, window);
                                                                  }
                                                                  
                                                                  function quote(address tokenIn, uint amountIn, address tokenOut, uint points, bool sushiswap) external view returns (uint amountOut, uint lastUpdatedAgo) {
                                                                      address _pair = sushiswap ? pairForSushi(tokenIn, tokenOut) : pairForUni(tokenIn, tokenOut);
                                                                      return feeds[_pair].quote(tokenIn, amountIn, tokenOut, points);
                                                                  }
                                                                  
                                                                  function quote(address pair, address tokenIn, uint amountIn, address tokenOut, uint points) external view returns (uint amountOut, uint lastUpdatedAgo) {
                                                                      return feeds[pair].quote(tokenIn, amountIn, tokenOut, points);
                                                                  }
                                                                  
                                                                  function current(address tokenIn, uint amountIn, address tokenOut, bool sushiswap) external view returns (uint amountOut, uint lastUpdatedAgo) {
                                                                      address _pair = sushiswap ? pairForSushi(tokenIn, tokenOut) : pairForUni(tokenIn, tokenOut);
                                                                      return feeds[_pair].current(tokenIn, amountIn, tokenOut);
                                                                  }
                                                                  
                                                                  function current(address pair, address tokenIn, uint amountIn, address tokenOut) external view returns (uint amountOut, uint lastUpdatedAgo) {
                                                                      return feeds[pair].current(tokenIn, amountIn, tokenOut);
                                                                  }
                                                              }

                                                              File 14 of 14: UniswapV2Pair
                                                              // File: contracts/uniswapv2/interfaces/IUniswapV2Factory.sol
                                                              
                                                              pragma solidity >=0.5.0;
                                                              
                                                              interface IUniswapV2Factory {
                                                                  event PairCreated(address indexed token0, address indexed token1, address pair, uint);
                                                              
                                                                  function feeTo() external view returns (address);
                                                                  function feeToSetter() external view returns (address);
                                                                  function migrator() external view returns (address);
                                                              
                                                                  function getPair(address tokenA, address tokenB) external view returns (address pair);
                                                                  function allPairs(uint) external view returns (address pair);
                                                                  function allPairsLength() external view returns (uint);
                                                              
                                                                  function createPair(address tokenA, address tokenB) external returns (address pair);
                                                              
                                                                  function setFeeTo(address) external;
                                                                  function setFeeToSetter(address) external;
                                                                  function setMigrator(address) external;
                                                              }
                                                              
                                                              // File: contracts/uniswapv2/libraries/SafeMath.sol
                                                              
                                                              pragma solidity =0.6.12;
                                                              
                                                              // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
                                                              
                                                              library SafeMathUniswap {
                                                                  function add(uint x, uint y) internal pure returns (uint z) {
                                                                      require((z = x + y) >= x, 'ds-math-add-overflow');
                                                                  }
                                                              
                                                                  function sub(uint x, uint y) internal pure returns (uint z) {
                                                                      require((z = x - y) <= x, 'ds-math-sub-underflow');
                                                                  }
                                                              
                                                                  function mul(uint x, uint y) internal pure returns (uint z) {
                                                                      require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/uniswapv2/UniswapV2ERC20.sol
                                                              
                                                              pragma solidity =0.6.12;
                                                              
                                                              
                                                              contract UniswapV2ERC20 {
                                                                  using SafeMathUniswap for uint;
                                                              
                                                                  string public constant name = 'SushiSwap LP Token';
                                                                  string public constant symbol = 'SLP';
                                                                  uint8 public constant decimals = 18;
                                                                  uint  public totalSupply;
                                                                  mapping(address => uint) public balanceOf;
                                                                  mapping(address => mapping(address => uint)) public allowance;
                                                              
                                                                  bytes32 public DOMAIN_SEPARATOR;
                                                                  // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
                                                                  bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
                                                                  mapping(address => uint) public nonces;
                                                              
                                                                  event Approval(address indexed owner, address indexed spender, uint value);
                                                                  event Transfer(address indexed from, address indexed to, uint value);
                                                              
                                                                  constructor() public {
                                                                      uint chainId;
                                                                      assembly {
                                                                          chainId := chainid()
                                                                      }
                                                                      DOMAIN_SEPARATOR = keccak256(
                                                                          abi.encode(
                                                                              keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                                                                              keccak256(bytes(name)),
                                                                              keccak256(bytes('1')),
                                                                              chainId,
                                                                              address(this)
                                                                          )
                                                                      );
                                                                  }
                                                              
                                                                  function _mint(address to, uint value) internal {
                                                                      totalSupply = totalSupply.add(value);
                                                                      balanceOf[to] = balanceOf[to].add(value);
                                                                      emit Transfer(address(0), to, value);
                                                                  }
                                                              
                                                                  function _burn(address from, uint value) internal {
                                                                      balanceOf[from] = balanceOf[from].sub(value);
                                                                      totalSupply = totalSupply.sub(value);
                                                                      emit Transfer(from, address(0), value);
                                                                  }
                                                              
                                                                  function _approve(address owner, address spender, uint value) private {
                                                                      allowance[owner][spender] = value;
                                                                      emit Approval(owner, spender, value);
                                                                  }
                                                              
                                                                  function _transfer(address from, address to, uint value) private {
                                                                      balanceOf[from] = balanceOf[from].sub(value);
                                                                      balanceOf[to] = balanceOf[to].add(value);
                                                                      emit Transfer(from, to, value);
                                                                  }
                                                              
                                                                  function approve(address spender, uint value) external returns (bool) {
                                                                      _approve(msg.sender, spender, value);
                                                                      return true;
                                                                  }
                                                              
                                                                  function transfer(address to, uint value) external returns (bool) {
                                                                      _transfer(msg.sender, to, value);
                                                                      return true;
                                                                  }
                                                              
                                                                  function transferFrom(address from, address to, uint value) external returns (bool) {
                                                                      if (allowance[from][msg.sender] != uint(-1)) {
                                                                          allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
                                                                      }
                                                                      _transfer(from, to, value);
                                                                      return true;
                                                                  }
                                                              
                                                                  function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
                                                                      require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
                                                                      bytes32 digest = keccak256(
                                                                          abi.encodePacked(
                                                                              '\x19\x01',
                                                                              DOMAIN_SEPARATOR,
                                                                              keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                                                                          )
                                                                      );
                                                                      address recoveredAddress = ecrecover(digest, v, r, s);
                                                                      require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
                                                                      _approve(owner, spender, value);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/uniswapv2/libraries/Math.sol
                                                              
                                                              pragma solidity =0.6.12;
                                                              
                                                              // a library for performing various math operations
                                                              
                                                              library Math {
                                                                  function min(uint x, uint y) internal pure returns (uint z) {
                                                                      z = x < y ? x : y;
                                                                  }
                                                              
                                                                  // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
                                                                  function sqrt(uint y) internal pure returns (uint z) {
                                                                      if (y > 3) {
                                                                          z = y;
                                                                          uint x = y / 2 + 1;
                                                                          while (x < z) {
                                                                              z = x;
                                                                              x = (y / x + x) / 2;
                                                                          }
                                                                      } else if (y != 0) {
                                                                          z = 1;
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/uniswapv2/libraries/UQ112x112.sol
                                                              
                                                              pragma solidity =0.6.12;
                                                              
                                                              // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
                                                              
                                                              // range: [0, 2**112 - 1]
                                                              // resolution: 1 / 2**112
                                                              
                                                              library UQ112x112 {
                                                                  uint224 constant Q112 = 2**112;
                                                              
                                                                  // encode a uint112 as a UQ112x112
                                                                  function encode(uint112 y) internal pure returns (uint224 z) {
                                                                      z = uint224(y) * Q112; // never overflows
                                                                  }
                                                              
                                                                  // divide a UQ112x112 by a uint112, returning a UQ112x112
                                                                  function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
                                                                      z = x / uint224(y);
                                                                  }
                                                              }
                                                              
                                                              // File: contracts/uniswapv2/interfaces/IERC20.sol
                                                              
                                                              pragma solidity >=0.5.0;
                                                              
                                                              interface IERC20Uniswap {
                                                                  event Approval(address indexed owner, address indexed spender, uint value);
                                                                  event Transfer(address indexed from, address indexed to, uint value);
                                                              
                                                                  function name() external view returns (string memory);
                                                                  function symbol() external view returns (string memory);
                                                                  function decimals() external view returns (uint8);
                                                                  function totalSupply() external view returns (uint);
                                                                  function balanceOf(address owner) external view returns (uint);
                                                                  function allowance(address owner, address spender) external view returns (uint);
                                                              
                                                                  function approve(address spender, uint value) external returns (bool);
                                                                  function transfer(address to, uint value) external returns (bool);
                                                                  function transferFrom(address from, address to, uint value) external returns (bool);
                                                              }
                                                              
                                                              // File: contracts/uniswapv2/interfaces/IUniswapV2Callee.sol
                                                              
                                                              pragma solidity >=0.5.0;
                                                              
                                                              interface IUniswapV2Callee {
                                                                  function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
                                                              }
                                                              
                                                              // File: contracts/uniswapv2/UniswapV2Pair.sol
                                                              
                                                              pragma solidity =0.6.12;
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              
                                                              interface IMigrator {
                                                                  // Return the desired amount of liquidity token that the migrator wants.
                                                                  function desiredLiquidity() external view returns (uint256);
                                                              }
                                                              
                                                              contract UniswapV2Pair is UniswapV2ERC20 {
                                                                  using SafeMathUniswap  for uint;
                                                                  using UQ112x112 for uint224;
                                                              
                                                                  uint public constant MINIMUM_LIQUIDITY = 10**3;
                                                                  bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
                                                              
                                                                  address public factory;
                                                                  address public token0;
                                                                  address public token1;
                                                              
                                                                  uint112 private reserve0;           // uses single storage slot, accessible via getReserves
                                                                  uint112 private reserve1;           // uses single storage slot, accessible via getReserves
                                                                  uint32  private blockTimestampLast; // uses single storage slot, accessible via getReserves
                                                              
                                                                  uint public price0CumulativeLast;
                                                                  uint public price1CumulativeLast;
                                                                  uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
                                                              
                                                                  uint private unlocked = 1;
                                                                  modifier lock() {
                                                                      require(unlocked == 1, 'UniswapV2: LOCKED');
                                                                      unlocked = 0;
                                                                      _;
                                                                      unlocked = 1;
                                                                  }
                                                              
                                                                  function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
                                                                      _reserve0 = reserve0;
                                                                      _reserve1 = reserve1;
                                                                      _blockTimestampLast = blockTimestampLast;
                                                                  }
                                                              
                                                                  function _safeTransfer(address token, address to, uint value) private {
                                                                      (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
                                                                      require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
                                                                  }
                                                              
                                                                  event Mint(address indexed sender, uint amount0, uint amount1);
                                                                  event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
                                                                  event Swap(
                                                                      address indexed sender,
                                                                      uint amount0In,
                                                                      uint amount1In,
                                                                      uint amount0Out,
                                                                      uint amount1Out,
                                                                      address indexed to
                                                                  );
                                                                  event Sync(uint112 reserve0, uint112 reserve1);
                                                              
                                                                  constructor() public {
                                                                      factory = msg.sender;
                                                                  }
                                                              
                                                                  // called once by the factory at time of deployment
                                                                  function initialize(address _token0, address _token1) external {
                                                                      require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
                                                                      token0 = _token0;
                                                                      token1 = _token1;
                                                                  }
                                                              
                                                                  // update reserves and, on the first call per block, price accumulators
                                                                  function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
                                                                      require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
                                                                      uint32 blockTimestamp = uint32(block.timestamp % 2**32);
                                                                      uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
                                                                      if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                                                                          // * never overflows, and + overflow is desired
                                                                          price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
                                                                          price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
                                                                      }
                                                                      reserve0 = uint112(balance0);
                                                                      reserve1 = uint112(balance1);
                                                                      blockTimestampLast = blockTimestamp;
                                                                      emit Sync(reserve0, reserve1);
                                                                  }
                                                              
                                                                  // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
                                                                  function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
                                                                      address feeTo = IUniswapV2Factory(factory).feeTo();
                                                                      feeOn = feeTo != address(0);
                                                                      uint _kLast = kLast; // gas savings
                                                                      if (feeOn) {
                                                                          if (_kLast != 0) {
                                                                              uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
                                                                              uint rootKLast = Math.sqrt(_kLast);
                                                                              if (rootK > rootKLast) {
                                                                                  uint numerator = totalSupply.mul(rootK.sub(rootKLast));
                                                                                  uint denominator = rootK.mul(5).add(rootKLast);
                                                                                  uint liquidity = numerator / denominator;
                                                                                  if (liquidity > 0) _mint(feeTo, liquidity);
                                                                              }
                                                                          }
                                                                      } else if (_kLast != 0) {
                                                                          kLast = 0;
                                                                      }
                                                                  }
                                                              
                                                                  // this low-level function should be called from a contract which performs important safety checks
                                                                  function mint(address to) external lock returns (uint liquidity) {
                                                                      (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                                                                      uint balance0 = IERC20Uniswap(token0).balanceOf(address(this));
                                                                      uint balance1 = IERC20Uniswap(token1).balanceOf(address(this));
                                                                      uint amount0 = balance0.sub(_reserve0);
                                                                      uint amount1 = balance1.sub(_reserve1);
                                                              
                                                                      bool feeOn = _mintFee(_reserve0, _reserve1);
                                                                      uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
                                                                      if (_totalSupply == 0) {
                                                                          address migrator = IUniswapV2Factory(factory).migrator();
                                                                          if (msg.sender == migrator) {
                                                                              liquidity = IMigrator(migrator).desiredLiquidity();
                                                                              require(liquidity > 0 && liquidity != uint256(-1), "Bad desired liquidity");
                                                                          } else {
                                                                              require(migrator == address(0), "Must not have migrator");
                                                                              liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
                                                                              _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
                                                                          }
                                                                      } else {
                                                                          liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
                                                                      }
                                                                      require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
                                                                      _mint(to, liquidity);
                                                              
                                                                      _update(balance0, balance1, _reserve0, _reserve1);
                                                                      if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
                                                                      emit Mint(msg.sender, amount0, amount1);
                                                                  }
                                                              
                                                                  // this low-level function should be called from a contract which performs important safety checks
                                                                  function burn(address to) external lock returns (uint amount0, uint amount1) {
                                                                      (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                                                                      address _token0 = token0;                                // gas savings
                                                                      address _token1 = token1;                                // gas savings
                                                                      uint balance0 = IERC20Uniswap(_token0).balanceOf(address(this));
                                                                      uint balance1 = IERC20Uniswap(_token1).balanceOf(address(this));
                                                                      uint liquidity = balanceOf[address(this)];
                                                              
                                                                      bool feeOn = _mintFee(_reserve0, _reserve1);
                                                                      uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
                                                                      amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
                                                                      amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
                                                                      require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
                                                                      _burn(address(this), liquidity);
                                                                      _safeTransfer(_token0, to, amount0);
                                                                      _safeTransfer(_token1, to, amount1);
                                                                      balance0 = IERC20Uniswap(_token0).balanceOf(address(this));
                                                                      balance1 = IERC20Uniswap(_token1).balanceOf(address(this));
                                                              
                                                                      _update(balance0, balance1, _reserve0, _reserve1);
                                                                      if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
                                                                      emit Burn(msg.sender, amount0, amount1, to);
                                                                  }
                                                              
                                                                  // this low-level function should be called from a contract which performs important safety checks
                                                                  function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
                                                                      require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
                                                                      (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                                                                      require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
                                                              
                                                                      uint balance0;
                                                                      uint balance1;
                                                                      { // scope for _token{0,1}, avoids stack too deep errors
                                                                      address _token0 = token0;
                                                                      address _token1 = token1;
                                                                      require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
                                                                      if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
                                                                      if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
                                                                      if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
                                                                      balance0 = IERC20Uniswap(_token0).balanceOf(address(this));
                                                                      balance1 = IERC20Uniswap(_token1).balanceOf(address(this));
                                                                      }
                                                                      uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
                                                                      uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
                                                                      require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
                                                                      { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
                                                                      uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
                                                                      uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
                                                                      require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
                                                                      }
                                                              
                                                                      _update(balance0, balance1, _reserve0, _reserve1);
                                                                      emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
                                                                  }
                                                              
                                                                  // force balances to match reserves
                                                                  function skim(address to) external lock {
                                                                      address _token0 = token0; // gas savings
                                                                      address _token1 = token1; // gas savings
                                                                      _safeTransfer(_token0, to, IERC20Uniswap(_token0).balanceOf(address(this)).sub(reserve0));
                                                                      _safeTransfer(_token1, to, IERC20Uniswap(_token1).balanceOf(address(this)).sub(reserve1));
                                                                  }
                                                              
                                                                  // force reserves to match balances
                                                                  function sync() external lock {
                                                                      _update(IERC20Uniswap(token0).balanceOf(address(this)), IERC20Uniswap(token1).balanceOf(address(this)), reserve0, reserve1);
                                                                  }
                                                              }