Transaction Hash:
Block:
19879756 at May-16-2024 03:08:11 AM +UTC
Transaction Fee:
0.002329549641494817 ETH
$4.84
Gas Used:
451,263 Gas / 5.162288159 Gwei
Emitted Events:
| 151 |
SmartToken.Transfer( _from=[Sender] 0x02cba548ae1fd9ab17d746d0d0476d89216406ea, _to=0x74de5d4FCbf63E00296fd95d33236B9794016631, _value=1379652319113238699828 )
|
| 152 |
SmartToken.Transfer( _from=0x74de5d4FCbf63E00296fd95d33236B9794016631, _to=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, _value=1367580361320997861205 )
|
| 153 |
SmartToken.Approval( _owner=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, _spender=KyberSwapRFQ, _value=115792089237316195423570985008687907853269984665640564039457584007913129639935 )
|
| 154 |
TetherToken.Transfer( from=0x807cF9A772d5a3f9CeFBc1192e939D62f0D9bD38, to=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, value=950443002 )
|
| 155 |
SmartToken.Transfer( _from=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, _to=0x807cF9A772d5a3f9CeFBc1192e939D62f0D9bD38, _value=1367580361320997861205 )
|
| 156 |
KyberSwapRFQ.OrderFilledRFQ( orderHash=0AD1E295830FF971F081D6E1E8BFF93AEFCC42ED0320DEF0195ABFCF2DA25FAD, maker=0x807cF9A772d5a3f9CeFBc1192e939D62f0D9bD38, taker=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, makerAsset=TetherToken, takerAsset=SmartToken, makingAmount=950443002, takingAmount=1367580361320997861205 )
|
| 157 |
0xf081470f5c6fbccf48cc4e5b82dd926409dcdd67.0xddac40937f35385a34f721af292e5a83fc5b840f722bff57c2fc71adba708c48( 0xddac40937f35385a34f721af292e5a83fc5b840f722bff57c2fc71adba708c48, 0000000000000000000000007a819fa46734a49d0112796f9377e024c350fb26, 0000000000000000000000000000000000000000000000000000000038a69bfa, 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7 )
|
| 158 |
AdminUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000807cf9a772d5a3f9cefbc1192e939d62f0d9bd38, 0x000000000000000000000000f081470f5c6fbccf48cc4e5b82dd926409dcdd67, 000000000000000000000000000000000000000000000004d66d6167d9608f98 )
|
| 159 |
TetherToken.Transfer( from=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, to=0x807cF9A772d5a3f9CeFBc1192e939D62f0D9bD38, value=950443002 )
|
| 160 |
KyberSwapRFQ.OrderFilledRFQ( orderHash=1296A5A01502C1E67633603B19D73C5FA19157B20219F890B8D16094FD18CDF3, maker=0x807cF9A772d5a3f9CeFBc1192e939D62f0D9bD38, taker=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, makerAsset=AdminUpgradeabilityProxy, takerAsset=TetherToken, makingAmount=89238089290072756120, takingAmount=950443002 )
|
| 161 |
0xf081470f5c6fbccf48cc4e5b82dd926409dcdd67.0xddac40937f35385a34f721af292e5a83fc5b840f722bff57c2fc71adba708c48( 0xddac40937f35385a34f721af292e5a83fc5b840f722bff57c2fc71adba708c48, 0000000000000000000000007a819fa46734a49d0112796f9377e024c350fb26, 000000000000000000000000000000000000000000000004d66d6167d9608f98, 0000000000000000000000006de037ef9ad2725eb40118bb1702ebb27e4aeb24 )
|
| 162 |
AdminUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000f081470f5c6fbccf48cc4e5b82dd926409dcdd67, 0x00000000000000000000000074de5d4fcbf63e00296fd95d33236b9794016631, 000000000000000000000000000000000000000000000004d66d6167d9608f98 )
|
| 163 |
MetaAggregationRouterV2.Swapped( sender=0x74de5d4FCbf63E00296fd95d33236B9794016631, srcToken=SmartToken, dstToken=AdminUpgradeabilityProxy, dstReceiver=0x74de5d4FCbf63E00296fd95d33236B9794016631, spentAmount=1367580361320997861205, returnAmount=89238089290072756120 )
|
| 164 |
MetaAggregationRouterV2.Exchange( pair=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, amountOut=89238089290072756120, output=AdminUpgradeabilityProxy )
|
| 165 |
MetaAggregationRouterV2.ClientData( clientData=0x7B22536F75726365223A226D6574616D61736B222C22416D6F756E74496E555344223A223935362E34323030363038353035363234222C22416D6F756E744F7574555344223A223934382E36303038383931353334373334222C22526566657272616C223A22222C22466C616773223A332C22496E74656772697479496E666F223A7B224B65794944223A2231222C225369676E6174757265223A2259667477686C4D73765277394A6757676F744F6A70596245567030375730754650537949766C4F384434543972414367416F61545779543768664448323672577443462F58466E5561484372366470585A564B4C53614C666D34774A2B66482B344B4E496732386C396672716C72567369426B796479463930307A467162763752483048504A442B5164723858583154714678306B5243524A4D6B4D43475844457050584D6D5869464A706170354B4464477A417146484A43372B4B314A70486834635354636B73437737524D42744C30757275496F3279714B6F30574E38354E525344766171397038364B777177612B62754A6431705A43434B61474C4A61414373314364584C53663532476D51305776444F684E3732537949384C54594B73694A7565422B4A384E427A4C715A3037577135356765734759716C4B6730466F6A532B5A6D384A477967617A446667714B573567673D3D227D7D )
|
| 166 |
SmartToken.Transfer( _from=0x74de5d4FCbf63E00296fd95d33236B9794016631, _to=GnosisSafeProxy, _value=12071957792240838623 )
|
| 167 |
AdminUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x00000000000000000000000074de5d4fcbf63e00296fd95d33236b9794016631, 0x00000000000000000000000002cba548ae1fd9ab17d746d0d0476d89216406ea, 000000000000000000000000000000000000000000000004d66d6167d9608f98 )
|
| 168 |
0x881d40237659c251811cec9c364ef91dc08d300c.0xbeee1e6e7fe307ddcf84b0a16137a4430ad5e2480fc4f4a8e250ab56ccd7630d( 0xbeee1e6e7fe307ddcf84b0a16137a4430ad5e2480fc4f4a8e250ab56ccd7630d, 0xa06d1ebec95550faee235885bf6dd56b011479008896fbe07e1c3bf19fead10e, 0x00000000000000000000000002cba548ae1fd9ab17d746d0d0476d89216406ea )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x02cBa548...9216406EA |
0.03562643974190609 Eth
Nonce: 27
|
0.033296890100411273 Eth
Nonce: 28
| 0.002329549641494817 | ||
| 0x1F573D6F...d79a7FF1C | |||||
| 0x6De037ef...27e4Aeb24 | |||||
| 0x7A819Fa4...4c350FB26 | |||||
|
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 7.101630600805319639 Eth | 7.101636421000548023 Eth | 0.000005820195228384 |
Execution Trace
Metamask: Swap Router.5f575529( )
-
SmartToken.transferFrom( _from=0x02cBa548ae1fd9aB17d746d0D0476D89216406EA, _to=0x74de5d4FCbf63E00296fd95d33236B9794016631, _value=1379652319113238699828 ) => ( success=True )
MetaMask: Swaps Spender.e3547335( )0x3a77bc2b4208afed4bb9610588b005e90908655f.92f5f037( )-
SmartToken.allowance( 0x74de5d4FCbf63E00296fd95d33236B9794016631, 0x6131B5fae19EA4f9D964eAc0408E4408b66337b5 ) => ( 115792089237316195423570985008687907853269984665640564038581373604895322072317 )
MetaAggregationRouterV2.swap( execution=[{name:callTarget, type:address, order:1, indexed:false, value:0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, valueString:0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67}, {name:approveTarget, type:address, order:2, indexed:false, value:0x0000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000}, {name:targetData, type:bytes, order:3, indexed:false, value:0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000C00000000000000000000000001F573D6FB3F13D689FF844B4CE37794D79A7FF1C0000000000000000000000006DE037EF9AD2725EB40118BB1702EBB27E4AEB2400000000000000000000000074DE5D4FCBF63E00296FD95D33236B97940166310000000000000000000000000000000000000000000000000000000066457D300000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002A00000000000000000000000000000000000000000000000000000000000000040CA6182DA00000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007A819FA46734A49D0112796F9377E024C350FB260000000000000000000000000000000000000000664578DB760D50750705BA3D000000000000000000000000DAC17F958D2EE523A2206206994597C13D831EC70000000000000000000000001F573D6FB3F13D689FF844B4CE37794D79A7FF1C000000000000000000000000807CF9A772D5A3F9CEFBC1192E939D62F0D9BD3800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038A69BFA00000000000000000000000000000000000000000000004A22FD74DEC2703755000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000004A22FD74DEC2703755000000000000000000000000F081470F5C6FBCCF48CC4E5B82DD926409DCDD670000000000000000000000000000000000000000000000000000000000000041D60A408F35216BAFEFEC628956652538AF28D7652F9C337ED57E4B76BCB6458C6354427F731A0AEE145F6A74204A2B6056D5799C5A647ED3AF22DC0F0168A2BB1B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040CA6182DA00000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007A819FA46734A49D0112796F9377E024C350FB260000000000000000000000000000000000000000664578DB17B1EB3F5D83BDBD0000000000000000000000006DE037EF9AD2725EB40118BB1702EBB27E4AEB24000000000000000000000000DAC17F958D2EE523A2206206994597C13D831EC7000000000000000000000000807CF9A772D5A3F9CEFBC1192E939D62F0D9BD380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004D66D6167D9608F980000000000000000000000000000000000000000000000000000000038A69BFA00000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000038A69BFA000000000000000000000000F081470F5C6FBCCF48CC4E5B82DD926409DCDD670000000000000000000000000000000000000000000000000000000000000041BAF86B6E7FB44ED0504616B221C393220B1AC506F62A4144C01E596F1044976C3392A5C375F8257E64922C38733E41B6C4F95A0CBC5C7A189C524EA65BE6A7EF1B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000051295C9CD1580000000000000004D66D6167D9608F98, valueString:0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000C00000000000000000000000001F573D6FB3F13D689FF844B4CE37794D79A7FF1C0000000000000000000000006DE037EF9AD2725EB40118BB1702EBB27E4AEB2400000000000000000000000074DE5D4FCBF63E00296FD95D33236B97940166310000000000000000000000000000000000000000000000000000000066457D300000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002A00000000000000000000000000000000000000000000000000000000000000040CA6182DA00000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007A819FA46734A49D0112796F9377E024C350FB260000000000000000000000000000000000000000664578DB760D50750705BA3D000000000000000000000000DAC17F958D2EE523A2206206994597C13D831EC70000000000000000000000001F573D6FB3F13D689FF844B4CE37794D79A7FF1C000000000000000000000000807CF9A772D5A3F9CEFBC1192E939D62F0D9BD3800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038A69BFA00000000000000000000000000000000000000000000004A22FD74DEC2703755000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000004A22FD74DEC2703755000000000000000000000000F081470F5C6FBCCF48CC4E5B82DD926409DCDD670000000000000000000000000000000000000000000000000000000000000041D60A408F35216BAFEFEC628956652538AF28D7652F9C337ED57E4B76BCB6458C6354427F731A0AEE145F6A74204A2B6056D5799C5A647ED3AF22DC0F0168A2BB1B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040CA6182DA00000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007A819FA46734A49D0112796F9377E024C350FB260000000000000000000000000000000000000000664578DB17B1EB3F5D83BDBD0000000000000000000000006DE037EF9AD2725EB40118BB1702EBB27E4AEB24000000000000000000000000DAC17F958D2EE523A2206206994597C13D831EC7000000000000000000000000807CF9A772D5A3F9CEFBC1192E939D62F0D9BD380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004D66D6167D9608F980000000000000000000000000000000000000000000000000000000038A69BFA00000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000038A69BFA000000000000000000000000F081470F5C6FBCCF48CC4E5B82DD926409DCDD670000000000000000000000000000000000000000000000000000000000000041BAF86B6E7FB44ED0504616B221C393220B1AC506F62A4144C01E596F1044976C3392A5C375F8257E64922C38733E41B6C4F95A0CBC5C7A189C524EA65BE6A7EF1B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000051295C9CD1580000000000000004D66D6167D9608F98}, {name:desc, type:tuple, order:4, indexed:false, value:[{name:srcToken, type:address, order:1, indexed:false, value:0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C, valueString:0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C}, {name:dstToken, type:address, order:2, indexed:false, value:0x6De037ef9aD2725EB40118Bb1702EBb27e4Aeb24, valueString:0x6De037ef9aD2725EB40118Bb1702EBb27e4Aeb24}, {name:srcReceivers, type:address[], order:3, indexed:false, value:[0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67], valueString:[0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67]}, {name:srcAmounts, type:uint256[], order:4, indexed:false, value:[1367580361320997861205], valueString:[1367580361320997861205]}, {name:feeReceivers, type:address[], order:5, indexed:false, value:[], valueString:[]}, {name:feeAmounts, type:uint256[], order:6, indexed:false, value:[], valueString:[]}, {name:dstReceiver, type:address, order:7, indexed:false, value:0x74de5d4FCbf63E00296fd95d33236B9794016631, valueString:0x74de5d4FCbf63E00296fd95d33236B9794016631}, {name:amount, type:uint256, order:8, indexed:false, value:1367580361320997861205, valueString:1367580361320997861205}, {name:minReturnAmount, type:uint256, order:9, indexed:false, value:87453327504271300997, valueString:87453327504271300997}, {name:flags, type:uint256, order:10, indexed:false, value:0, valueString:0}, {name:permit, type:bytes, order:11, indexed:false, value:0x, valueString:0x}], valueString:[{name:srcToken, type:address, order:1, indexed:false, value:0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C, valueString:0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C}, {name:dstToken, type:address, order:2, indexed:false, value:0x6De037ef9aD2725EB40118Bb1702EBb27e4Aeb24, valueString:0x6De037ef9aD2725EB40118Bb1702EBb27e4Aeb24}, {name:srcReceivers, type:address[], order:3, indexed:false, value:[0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67], valueString:[0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67]}, {name:srcAmounts, type:uint256[], order:4, indexed:false, value:[1367580361320997861205], valueString:[1367580361320997861205]}, {name:feeReceivers, type:address[], order:5, indexed:false, value:[], valueString:[]}, {name:feeAmounts, type:uint256[], order:6, indexed:false, value:[], valueString:[]}, {name:dstReceiver, type:address, order:7, indexed:false, value:0x74de5d4FCbf63E00296fd95d33236B9794016631, valueString:0x74de5d4FCbf63E00296fd95d33236B9794016631}, {name:amount, type:uint256, order:8, indexed:false, value:1367580361320997861205, valueString:1367580361320997861205}, {name:minReturnAmount, type:uint256, order:9, indexed:false, value:87453327504271300997, valueString:87453327504271300997}, {name:flags, type:uint256, order:10, indexed:false, value:0, valueString:0}, {name:permit, type:bytes, order:11, indexed:false, value:0x, valueString:0x}]}, {name:clientData, type:bytes, order:5, indexed:false, value:0x7B22536F75726365223A226D6574616D61736B222C22416D6F756E74496E555344223A223935362E34323030363038353035363234222C22416D6F756E744F7574555344223A223934382E36303038383931353334373334222C22526566657272616C223A22222C22466C616773223A332C22496E74656772697479496E666F223A7B224B65794944223A2231222C225369676E6174757265223A2259667477686C4D73765277394A6757676F744F6A70596245567030375730754650537949766C4F384434543972414367416F61545779543768664448323672577443462F58466E5561484372366470585A564B4C53614C666D34774A2B66482B344B4E496732386C396672716C72567369426B796479463930307A467162763752483048504A442B5164723858583154714678306B5243524A4D6B4D43475844457050584D6D5869464A706170354B4464477A417146484A43372B4B314A70486834635354636B73437737524D42744C30757275496F3279714B6F30574E38354E525344766171397038364B777177612B62754A6431705A43434B61474C4A61414373314364584C53663532476D51305776444F684E3732537949384C54594B73694A7565422B4A384E427A4C715A3037577135356765734759716C4B6730466F6A532B5A6D384A477967617A446667714B573567673D3D227D7D, valueString:0x7B22536F75726365223A226D6574616D61736B222C22416D6F756E74496E555344223A223935362E34323030363038353035363234222C22416D6F756E744F7574555344223A223934382E36303038383931353334373334222C22526566657272616C223A22222C22466C616773223A332C22496E74656772697479496E666F223A7B224B65794944223A2231222C225369676E6174757265223A2259667477686C4D73765277394A6757676F744F6A70596245567030375730754650537949766C4F384434543972414367416F61545779543768664448323672577443462F58466E5561484372366470585A564B4C53614C666D34774A2B66482B344B4E496732386C396672716C72567369426B796479463930307A467162763752483048504A442B5164723858583154714678306B5243524A4D6B4D43475844457050584D6D5869464A706170354B4464477A417146484A43372B4B314A70486834635354636B73437737524D42744C30757275496F3279714B6F30574E38354E525344766171397038364B777177612B62754A6431705A43434B61474C4A61414373314364584C53663532476D51305776444F684E3732537949384C54594B73694A7565422B4A384E427A4C715A3037577135356765734759716C4B6730466F6A532B5A6D384A477967617A446667714B573567673D3D227D7D}] ) => ( returnAmount=89238089290072756120, gasUsed=321256 )-
SmartToken.transferFrom( _from=0x74de5d4FCbf63E00296fd95d33236B9794016631, _to=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, _value=1367580361320997861205 ) => ( success=True )
AdminUpgradeabilityProxy.70a08231( )
-
RenderToken.balanceOf( _owner=0x74de5d4FCbf63E00296fd95d33236B9794016631 ) => ( 0 )
-
-
SmartToken.balanceOf( 0x6131B5fae19EA4f9D964eAc0408E4408b66337b5 ) => ( 0 )
AdminUpgradeabilityProxy.70a08231( )
-
RenderToken.balanceOf( _owner=0x6131B5fae19EA4f9D964eAc0408E4408b66337b5 ) => ( 0 )
-
0xf081470f5c6fbccf48cc4e5b82dd926409dcdd67.d9c45357( )0xa3fe30e2c53e2744a7e2002e70fd88b476409745.ca6182da( )-
SmartToken.balanceOf( 0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67 ) => ( 1367580361320997861206 )
-
SmartToken.allowance( 0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, 0x7A819Fa46734a49D0112796f9377E024c350FB26 ) => ( 0 )
-
SmartToken.approve( _spender=0x7A819Fa46734a49D0112796f9377E024c350FB26, _value=115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( success=True )
-
KyberSwapRFQ.fillOrderRFQTo( order=[{name:info, type:uint256, order:1, indexed:false, value:31651457615652046657531787837, valueString:31651457615652046657531787837}, {name:makerAsset, type:address, order:2, indexed:false, value:0xdAC17F958D2ee523a2206206994597C13D831ec7, valueString:0xdAC17F958D2ee523a2206206994597C13D831ec7}, {name:takerAsset, type:address, order:3, indexed:false, value:0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C, valueString:0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C}, {name:maker, type:address, order:4, indexed:false, value:0x807cF9A772d5a3f9CeFBc1192e939D62f0D9bD38, valueString:0x807cF9A772d5a3f9CeFBc1192e939D62f0D9bD38}, {name:allowedSender, type:address, order:5, indexed:false, value:0x0000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000}, {name:makingAmount, type:uint256, order:6, indexed:false, value:950443002, valueString:950443002}, {name:takingAmount, type:uint256, order:7, indexed:false, value:1367580361320997861205, valueString:1367580361320997861205}], signature=0xD60A408F35216BAFEFEC628956652538AF28D7652F9C337ED57E4B76BCB6458C6354427F731A0AEE145F6A74204A2B6056D5799C5A647ED3AF22DC0F0168A2BB1B, makingAmount=0, takingAmount=1367580361320997861205, target=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67 ) => ( 950443002, 1367580361320997861205 )
-
0xa3fe30e2c53e2744a7e2002e70fd88b476409745.ca6182da( )-
TetherToken.balanceOf( who=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67 ) => ( 950443003 )
-
TetherToken.allowance( _owner=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67, _spender=0x7A819Fa46734a49D0112796f9377E024c350FB26 ) => ( remaining=115792089237316195423570985008687907853269984665640564039457584007913129639935 )
-
KyberSwapRFQ.fillOrderRFQTo( order=[{name:info, type:uint256, order:1, indexed:false, value:31651457608852907313934351805, valueString:31651457608852907313934351805}, {name:makerAsset, type:address, order:2, indexed:false, value:0x6De037ef9aD2725EB40118Bb1702EBb27e4Aeb24, valueString:0x6De037ef9aD2725EB40118Bb1702EBb27e4Aeb24}, {name:takerAsset, type:address, order:3, indexed:false, value:0xdAC17F958D2ee523a2206206994597C13D831ec7, valueString:0xdAC17F958D2ee523a2206206994597C13D831ec7}, {name:maker, type:address, order:4, indexed:false, value:0x807cF9A772d5a3f9CeFBc1192e939D62f0D9bD38, valueString:0x807cF9A772d5a3f9CeFBc1192e939D62f0D9bD38}, {name:allowedSender, type:address, order:5, indexed:false, value:0x0000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000}, {name:makingAmount, type:uint256, order:6, indexed:false, value:89238089290072756120, valueString:89238089290072756120}, {name:takingAmount, type:uint256, order:7, indexed:false, value:950443002, valueString:950443002}], signature=0xBAF86B6E7FB44ED0504616B221C393220B1AC506F62A4144C01E596F1044976C3392A5C375F8257E64922C38733E41B6C4F95A0CBC5C7A189C524EA65BE6A7EF1B, makingAmount=0, takingAmount=950443002, target=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67 ) => ( 89238089290072756120, 950443002 )
-
AdminUpgradeabilityProxy.70a08231( )
-
RenderToken.balanceOf( _owner=0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67 ) => ( 89238089290072756121 )
-
-
SmartToken.balanceOf( 0xf081470f5C6FBCCF48cC4e5B82Dd926409DcdD67 ) => ( 1 )
AdminUpgradeabilityProxy.a9059cbb( )
-
RenderToken.transfer( _to=0x74de5d4FCbf63E00296fd95d33236B9794016631, _value=89238089290072756120 ) => ( True )
-
AdminUpgradeabilityProxy.70a08231( )
-
RenderToken.balanceOf( _owner=0x6131B5fae19EA4f9D964eAc0408E4408b66337b5 ) => ( 0 )
-
AdminUpgradeabilityProxy.70a08231( )
-
RenderToken.balanceOf( _owner=0x74de5d4FCbf63E00296fd95d33236B9794016631 ) => ( 89238089290072756120 )
-
-
-
SmartToken.transfer( _to=0x2aCf35C9A3F4c5C3F4c78EF5Fb64c3EE82f07c45, _value=12071957792240838623 ) => ( success=True )
-
SmartToken.balanceOf( 0x74de5d4FCbf63E00296fd95d33236B9794016631 ) => ( 0 )
AdminUpgradeabilityProxy.70a08231( )
-
RenderToken.balanceOf( _owner=0x74de5d4FCbf63E00296fd95d33236B9794016631 ) => ( 89238089290072756120 )
-
AdminUpgradeabilityProxy.a9059cbb( )
-
RenderToken.transfer( _to=0x02cBa548ae1fd9aB17d746d0D0476D89216406EA, _value=89238089290072756120 ) => ( True )
-
-
File 1 of 7: SmartToken
File 2 of 7: TetherToken
File 3 of 7: KyberSwapRFQ
File 4 of 7: AdminUpgradeabilityProxy
File 5 of 7: MetaAggregationRouterV2
File 6 of 7: GnosisSafeProxy
File 7 of 7: RenderToken
pragma solidity ^0.4.11;
/*
Overflow protected math functions
*/
contract SafeMath {
/**
constructor
*/
function SafeMath() {
}
/**
@dev returns the sum of _x and _y, asserts if the calculation overflows
@param _x value 1
@param _y value 2
@return sum
*/
function safeAdd(uint256 _x, uint256 _y) internal returns (uint256) {
uint256 z = _x + _y;
assert(z >= _x);
return z;
}
/**
@dev returns the difference of _x minus _y, asserts if the subtraction results in a negative number
@param _x minuend
@param _y subtrahend
@return difference
*/
function safeSub(uint256 _x, uint256 _y) internal returns (uint256) {
assert(_x >= _y);
return _x - _y;
}
/**
@dev returns the product of multiplying _x by _y, asserts if the calculation overflows
@param _x factor 1
@param _y factor 2
@return product
*/
function safeMul(uint256 _x, uint256 _y) internal returns (uint256) {
uint256 z = _x * _y;
assert(_x == 0 || z / _x == _y);
return z;
}
}
/*
Owned contract interface
*/
contract IOwned {
// this function isn't abstract since the compiler emits automatically generated getter functions as external
function owner() public constant returns (address owner) { owner; }
function transferOwnership(address _newOwner) public;
function acceptOwnership() public;
}
/*
Provides support and utilities for contract ownership
*/
contract Owned is IOwned {
address public owner;
address public newOwner;
event OwnerUpdate(address _prevOwner, address _newOwner);
/**
@dev constructor
*/
function Owned() {
owner = msg.sender;
}
// allows execution by the owner only
modifier ownerOnly {
assert(msg.sender == owner);
_;
}
/**
@dev allows transferring the contract ownership
the new owner still need to accept the transfer
can only be called by the contract owner
@param _newOwner new contract owner
*/
function transferOwnership(address _newOwner) public ownerOnly {
require(_newOwner != owner);
newOwner = _newOwner;
}
/**
@dev used by a new owner to accept an ownership transfer
*/
function acceptOwnership() public {
require(msg.sender == newOwner);
OwnerUpdate(owner, newOwner);
owner = newOwner;
newOwner = 0x0;
}
}
/*
Token Holder interface
*/
contract ITokenHolder is IOwned {
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) public;
}
/*
We consider every contract to be a 'token holder' since it's currently not possible
for a contract to deny receiving tokens.
The TokenHolder's contract sole purpose is to provide a safety mechanism that allows
the owner to send tokens that were sent to the contract by mistake back to their sender.
*/
contract TokenHolder is ITokenHolder, Owned {
/**
@dev constructor
*/
function TokenHolder() {
}
// validates an address - currently only checks that it isn't null
modifier validAddress(address _address) {
require(_address != 0x0);
_;
}
// verifies that the address is different than this contract address
modifier notThis(address _address) {
require(_address != address(this));
_;
}
/**
@dev withdraws tokens held by the contract and sends them to an account
can only be called by the owner
@param _token ERC20 token contract address
@param _to account to receive the new amount
@param _amount amount to withdraw
*/
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount)
public
ownerOnly
validAddress(_token)
validAddress(_to)
notThis(_to)
{
assert(_token.transfer(_to, _amount));
}
}
/*
ERC20 Standard Token interface
*/
contract IERC20Token {
// these functions aren't abstract since the compiler emits automatically generated getter functions as external
function name() public constant returns (string name) { name; }
function symbol() public constant returns (string symbol) { symbol; }
function decimals() public constant returns (uint8 decimals) { decimals; }
function totalSupply() public constant returns (uint256 totalSupply) { totalSupply; }
function balanceOf(address _owner) public constant returns (uint256 balance) { _owner; balance; }
function allowance(address _owner, address _spender) public constant returns (uint256 remaining) { _owner; _spender; remaining; }
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
}
/**
ERC20 Standard Token implementation
*/
contract ERC20Token is IERC20Token, SafeMath {
string public standard = 'Token 0.1';
string public name = '';
string public symbol = '';
uint8 public decimals = 0;
uint256 public totalSupply = 0;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
/**
@dev constructor
@param _name token name
@param _symbol token symbol
@param _decimals decimal points, for display purposes
*/
function ERC20Token(string _name, string _symbol, uint8 _decimals) {
require(bytes(_name).length > 0 && bytes(_symbol).length > 0); // validate input
name = _name;
symbol = _symbol;
decimals = _decimals;
}
// validates an address - currently only checks that it isn't null
modifier validAddress(address _address) {
require(_address != 0x0);
_;
}
/**
@dev send coins
throws on any error rather then return a false flag to minimize user errors
@param _to target address
@param _value transfer amount
@return true if the transfer was successful, false if it wasn't
*/
function transfer(address _to, uint256 _value)
public
validAddress(_to)
returns (bool success)
{
balanceOf[msg.sender] = safeSub(balanceOf[msg.sender], _value);
balanceOf[_to] = safeAdd(balanceOf[_to], _value);
Transfer(msg.sender, _to, _value);
return true;
}
/**
@dev an account/contract attempts to get the coins
throws on any error rather then return a false flag to minimize user errors
@param _from source address
@param _to target address
@param _value transfer amount
@return true if the transfer was successful, false if it wasn't
*/
function transferFrom(address _from, address _to, uint256 _value)
public
validAddress(_from)
validAddress(_to)
returns (bool success)
{
allowance[_from][msg.sender] = safeSub(allowance[_from][msg.sender], _value);
balanceOf[_from] = safeSub(balanceOf[_from], _value);
balanceOf[_to] = safeAdd(balanceOf[_to], _value);
Transfer(_from, _to, _value);
return true;
}
/**
@dev allow another account/contract to spend some tokens on your behalf
throws on any error rather then return a false flag to minimize user errors
also, to minimize the risk of the approve/transferFrom attack vector
(see https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/), approve has to be called twice
in 2 separate transactions - once to change the allowance to 0 and secondly to change it to the new allowance value
@param _spender approved address
@param _value allowance amount
@return true if the approval was successful, false if it wasn't
*/
function approve(address _spender, uint256 _value)
public
validAddress(_spender)
returns (bool success)
{
// if the allowance isn't 0, it can only be updated to 0 to prevent an allowance change immediately after withdrawal
require(_value == 0 || allowance[msg.sender][_spender] == 0);
allowance[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
}
/*
Smart Token interface
*/
contract ISmartToken is ITokenHolder, IERC20Token {
function disableTransfers(bool _disable) public;
function issue(address _to, uint256 _amount) public;
function destroy(address _from, uint256 _amount) public;
}
/*
Smart Token v0.2
'Owned' is specified here for readability reasons
*/
contract SmartToken is ISmartToken, ERC20Token, Owned, TokenHolder {
string public version = '0.2';
bool public transfersEnabled = true; // true if transfer/transferFrom are enabled, false if not
// triggered when a smart token is deployed - the _token address is defined for forward compatibility, in case we want to trigger the event from a factory
event NewSmartToken(address _token);
// triggered when the total supply is increased
event Issuance(uint256 _amount);
// triggered when the total supply is decreased
event Destruction(uint256 _amount);
/**
@dev constructor
@param _name token name
@param _symbol token short symbol, 1-6 characters
@param _decimals for display purposes only
*/
function SmartToken(string _name, string _symbol, uint8 _decimals)
ERC20Token(_name, _symbol, _decimals)
{
require(bytes(_symbol).length <= 6); // validate input
NewSmartToken(address(this));
}
// allows execution only when transfers aren't disabled
modifier transfersAllowed {
assert(transfersEnabled);
_;
}
/**
@dev disables/enables transfers
can only be called by the contract owner
@param _disable true to disable transfers, false to enable them
*/
function disableTransfers(bool _disable) public ownerOnly {
transfersEnabled = !_disable;
}
/**
@dev increases the token supply and sends the new tokens to an account
can only be called by the contract owner
@param _to account to receive the new amount
@param _amount amount to increase the supply by
*/
function issue(address _to, uint256 _amount)
public
ownerOnly
validAddress(_to)
notThis(_to)
{
totalSupply = safeAdd(totalSupply, _amount);
balanceOf[_to] = safeAdd(balanceOf[_to], _amount);
Issuance(_amount);
Transfer(this, _to, _amount);
}
/**
@dev removes tokens from an account and decreases the token supply
can only be called by the contract owner
@param _from account to remove the amount from
@param _amount amount to decrease the supply by
*/
function destroy(address _from, uint256 _amount)
public
ownerOnly
{
balanceOf[_from] = safeSub(balanceOf[_from], _amount);
totalSupply = safeSub(totalSupply, _amount);
Transfer(_from, this, _amount);
Destruction(_amount);
}
// ERC20 standard method overrides with some extra functionality
/**
@dev send coins
throws on any error rather then return a false flag to minimize user errors
note that when transferring to the smart token's address, the coins are actually destroyed
@param _to target address
@param _value transfer amount
@return true if the transfer was successful, false if it wasn't
*/
function transfer(address _to, uint256 _value) public transfersAllowed returns (bool success) {
assert(super.transfer(_to, _value));
// transferring to the contract address destroys tokens
if (_to == address(this)) {
balanceOf[_to] -= _value;
totalSupply -= _value;
Destruction(_value);
}
return true;
}
/**
@dev an account/contract attempts to get the coins
throws on any error rather then return a false flag to minimize user errors
note that when transferring to the smart token's address, the coins are actually destroyed
@param _from source address
@param _to target address
@param _value transfer amount
@return true if the transfer was successful, false if it wasn't
*/
function transferFrom(address _from, address _to, uint256 _value) public transfersAllowed returns (bool success) {
assert(super.transferFrom(_from, _to, _value));
// transferring to the contract address destroys tokens
if (_to == address(this)) {
balanceOf[_to] -= _value;
totalSupply -= _value;
Destruction(_value);
}
return true;
}
}File 2 of 7: TetherToken
pragma solidity ^0.4.17;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws 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;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
if (newOwner != address(0)) {
owner = newOwner;
}
}
}
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20Basic {
uint public _totalSupply;
function totalSupply() public constant returns (uint);
function balanceOf(address who) public constant returns (uint);
function transfer(address to, uint value) public;
event Transfer(address indexed from, address indexed to, uint value);
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) public constant returns (uint);
function transferFrom(address from, address to, uint value) public;
function approve(address spender, uint value) public;
event Approval(address indexed owner, address indexed spender, uint value);
}
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is Ownable, ERC20Basic {
using SafeMath for uint;
mapping(address => uint) public balances;
// additional variables for use if transaction fees ever became necessary
uint public basisPointsRate = 0;
uint public maximumFee = 0;
/**
* @dev Fix for the ERC20 short address attack.
*/
modifier onlyPayloadSize(uint size) {
require(!(msg.data.length < size + 4));
_;
}
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
uint fee = (_value.mul(basisPointsRate)).div(10000);
if (fee > maximumFee) {
fee = maximumFee;
}
uint sendAmount = _value.sub(fee);
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(sendAmount);
if (fee > 0) {
balances[owner] = balances[owner].add(fee);
Transfer(msg.sender, owner, fee);
}
Transfer(msg.sender, _to, sendAmount);
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public constant returns (uint balance) {
return balances[_owner];
}
}
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is BasicToken, ERC20 {
mapping (address => mapping (address => uint)) public allowed;
uint public constant MAX_UINT = 2**256 - 1;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
var _allowance = allowed[_from][msg.sender];
// Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
// if (_value > _allowance) throw;
uint fee = (_value.mul(basisPointsRate)).div(10000);
if (fee > maximumFee) {
fee = maximumFee;
}
if (_allowance < MAX_UINT) {
allowed[_from][msg.sender] = _allowance.sub(_value);
}
uint sendAmount = _value.sub(fee);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(sendAmount);
if (fee > 0) {
balances[owner] = balances[owner].add(fee);
Transfer(_from, owner, fee);
}
Transfer(_from, _to, sendAmount);
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender, 0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
}
/**
* @dev Function to check the amount of tokens than an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) public constant returns (uint remaining) {
return allowed[_owner][_spender];
}
}
/**
* @title Pausable
* @dev Base contract which allows children to implement an emergency stop mechanism.
*/
contract Pausable is Ownable {
event Pause();
event Unpause();
bool public paused = false;
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*/
modifier whenNotPaused() {
require(!paused);
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*/
modifier whenPaused() {
require(paused);
_;
}
/**
* @dev called by the owner to pause, triggers stopped state
*/
function pause() onlyOwner whenNotPaused public {
paused = true;
Pause();
}
/**
* @dev called by the owner to unpause, returns to normal state
*/
function unpause() onlyOwner whenPaused public {
paused = false;
Unpause();
}
}
contract BlackList is Ownable, BasicToken {
/////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
function getBlackListStatus(address _maker) external constant returns (bool) {
return isBlackListed[_maker];
}
function getOwner() external constant returns (address) {
return owner;
}
mapping (address => bool) public isBlackListed;
function addBlackList (address _evilUser) public onlyOwner {
isBlackListed[_evilUser] = true;
AddedBlackList(_evilUser);
}
function removeBlackList (address _clearedUser) public onlyOwner {
isBlackListed[_clearedUser] = false;
RemovedBlackList(_clearedUser);
}
function destroyBlackFunds (address _blackListedUser) public onlyOwner {
require(isBlackListed[_blackListedUser]);
uint dirtyFunds = balanceOf(_blackListedUser);
balances[_blackListedUser] = 0;
_totalSupply -= dirtyFunds;
DestroyedBlackFunds(_blackListedUser, dirtyFunds);
}
event DestroyedBlackFunds(address _blackListedUser, uint _balance);
event AddedBlackList(address _user);
event RemovedBlackList(address _user);
}
contract UpgradedStandardToken is StandardToken{
// those methods are called by the legacy contract
// and they must ensure msg.sender to be the contract address
function transferByLegacy(address from, address to, uint value) public;
function transferFromByLegacy(address sender, address from, address spender, uint value) public;
function approveByLegacy(address from, address spender, uint value) public;
}
contract TetherToken is Pausable, StandardToken, BlackList {
string public name;
string public symbol;
uint public decimals;
address public upgradedAddress;
bool public deprecated;
// The contract can be initialized with a number of tokens
// All the tokens are deposited to the owner address
//
// @param _balance Initial supply of the contract
// @param _name Token Name
// @param _symbol Token symbol
// @param _decimals Token decimals
function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
_totalSupply = _initialSupply;
name = _name;
symbol = _symbol;
decimals = _decimals;
balances[owner] = _initialSupply;
deprecated = false;
}
// Forward ERC20 methods to upgraded contract if this one is deprecated
function transfer(address _to, uint _value) public whenNotPaused {
require(!isBlackListed[msg.sender]);
if (deprecated) {
return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
} else {
return super.transfer(_to, _value);
}
}
// Forward ERC20 methods to upgraded contract if this one is deprecated
function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
require(!isBlackListed[_from]);
if (deprecated) {
return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
} else {
return super.transferFrom(_from, _to, _value);
}
}
// Forward ERC20 methods to upgraded contract if this one is deprecated
function balanceOf(address who) public constant returns (uint) {
if (deprecated) {
return UpgradedStandardToken(upgradedAddress).balanceOf(who);
} else {
return super.balanceOf(who);
}
}
// Forward ERC20 methods to upgraded contract if this one is deprecated
function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
if (deprecated) {
return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
} else {
return super.approve(_spender, _value);
}
}
// Forward ERC20 methods to upgraded contract if this one is deprecated
function allowance(address _owner, address _spender) public constant returns (uint remaining) {
if (deprecated) {
return StandardToken(upgradedAddress).allowance(_owner, _spender);
} else {
return super.allowance(_owner, _spender);
}
}
// deprecate current contract in favour of a new one
function deprecate(address _upgradedAddress) public onlyOwner {
deprecated = true;
upgradedAddress = _upgradedAddress;
Deprecate(_upgradedAddress);
}
// deprecate current contract if favour of a new one
function totalSupply() public constant returns (uint) {
if (deprecated) {
return StandardToken(upgradedAddress).totalSupply();
} else {
return _totalSupply;
}
}
// Issue a new amount of tokens
// these tokens are deposited into the owner address
//
// @param _amount Number of tokens to be issued
function issue(uint amount) public onlyOwner {
require(_totalSupply + amount > _totalSupply);
require(balances[owner] + amount > balances[owner]);
balances[owner] += amount;
_totalSupply += amount;
Issue(amount);
}
// Redeem tokens.
// These tokens are withdrawn from the owner address
// if the balance must be enough to cover the redeem
// or the call will fail.
// @param _amount Number of tokens to be issued
function redeem(uint amount) public onlyOwner {
require(_totalSupply >= amount);
require(balances[owner] >= amount);
_totalSupply -= amount;
balances[owner] -= amount;
Redeem(amount);
}
function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
// Ensure transparency by hardcoding limit beyond which fees can never be added
require(newBasisPoints < 20);
require(newMaxFee < 50);
basisPointsRate = newBasisPoints;
maximumFee = newMaxFee.mul(10**decimals);
Params(basisPointsRate, maximumFee);
}
// Called when new token are issued
event Issue(uint amount);
// Called when tokens are redeemed
event Redeem(uint amount);
// Called when contract is deprecated
event Deprecate(address newAddress);
// Called if contract ever adds fees
event Params(uint feeBasisPoints, uint maxFee);
}File 3 of 7: KyberSwapRFQ
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.0;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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 Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
* 0 before setting it to a non-zero value.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @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).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/draft-EIP712.sol)
pragma solidity ^0.8.0;
// EIP-712 is Final as of 2022-08-11. This file is deprecated.
import "./EIP712.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\\x19Ethereum Signed Message:\
32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\\x19\\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\\x19\\x00", validator, data));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.8;
import "./ECDSA.sol";
import "../ShortStrings.sol";
import "../../interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* _Available since v3.4._
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {EIP-5267}.
*
* _Available since v4.9._
*/
function eip712Domain()
public
view
virtual
override
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_name.toStringWithFallback(_nameFallback),
_version.toStringWithFallback(_versionFallback),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.8;
import "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(_FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
abstract contract KSAdmin {
address public admin;
mapping(address => bool) public operators; // address => bool
event TransferAdmin(address indexed admin);
event UpdateOperator(address indexed user, bool grantOrRevoke);
modifier isAdmin() {
require(msg.sender == admin, 'forbidden');
_;
}
modifier isOperator() {
require(operators[msg.sender], 'forbidden');
_;
}
constructor() {
admin = msg.sender;
operators[msg.sender] = true;
}
function transferAdmin(address _admin) external virtual isAdmin {
require(_admin != address(0), 'forbidden');
admin = _admin;
emit TransferAdmin(_admin);
}
function updateOperator(address user, bool grantOrRevoke) external isAdmin {
operators[user] = grantOrRevoke;
emit UpdateOperator(user, grantOrRevoke);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function withdraw(uint256) external;
function balanceOf(address account) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6;
pragma abicoder v2;
interface IRFQ {
event RescueFund(address indexed token, uint256 amount);
struct OrderRFQ {
// lowest 64 bits is the order id, next 64 bits is the expiration timestamp
// highest bit is unwrap WETH flag which is set on taker's side
// [unwrap eth(1 bit) | unused (127 bits) | expiration timestamp(64 bits) | orderId (64 bits)]
uint256 info;
address makerAsset;
address takerAsset;
address maker;
address allowedSender; // null address on public orders
uint256 makingAmount;
uint256 takingAmount;
}
/// @notice Fills an order's quote, either fully or partially
/// @dev Funds will be sent to msg.sender
/// @param order Order quote to fill
/// @param signature Signature to confirm quote ownership
/// @param makingAmount Maker amount
/// @param takingAmount Taker amount
function fillOrderRFQ(
OrderRFQ memory order,
bytes calldata signature,
uint256 makingAmount,
uint256 takingAmount
)
external
payable
returns (
uint256, /* actualmakingAmount */
uint256 /* actualtakingAmount */
);
/// @notice Main function for fulfilling orders
/// @param order Order quote to fill
/// @param signature Signature to confirm quote ownership
/// @param makingAmount Maker amount
/// @param takingAmount Taker amount
/// @param target Address that will receive swapped funds
function fillOrderRFQTo(
OrderRFQ memory order,
bytes calldata signature,
uint256 makingAmount,
uint256 takingAmount,
address payable target
)
external
payable
returns (
uint256, /* actualmakingAmount */
uint256 /* actualtakingAmount */
);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import '@openzeppelin/contracts/interfaces/IERC1271.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol';
import 'contracts/interfaces/IWETH.sol';
import 'contracts/interfaces/pool-types/IRFQ.sol';
import 'contracts/base/KSAdmin.sol';
/// Taken from 1inch Router at 0x1111111254fb6c44bac0bed2854e76f90643097d
/// with minor modifications
/*
“Copyright (c) 2019-2021 1inch
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE”.
*/
contract KyberSwapRFQ is IRFQ, EIP712('KyberSwap RFQ', '1'), KSAdmin {
using SafeERC20 for IERC20;
event OrderFilledRFQ(
bytes32 orderHash,
address indexed maker,
address indexed taker,
address makerAsset,
address takerAsset,
uint256 makingAmount,
uint256 takingAmount
);
bytes32 public constant LIMIT_ORDER_RFQ_TYPEHASH =
keccak256(
// solhint-disable-next-line
'OrderRFQ(uint256 info,address makerAsset,address takerAsset,address maker,address allowedSender,uint256 makingAmount,uint256 takingAmount)'
);
uint256 private constant _UNWRAPWETH_MASK = 1 << 255;
IWETH private immutable WETH;
mapping(address => mapping(uint256 => uint256)) private invalidator;
constructor(IWETH _weth) {
WETH = IWETH(_weth);
}
receive() external payable {
// solhint-disable-next-line avoid-tx-origin
// ETH should only come from WETH contract
require(msg.sender == address(WETH), 'KS_RFQ: Not WETH contract');
}
function DOMAIN_SEPARATOR() external view returns (bytes32) {
return _domainSeparatorV4();
}
function rescueFund(IERC20 token, uint256 amount) external isAdmin {
if (address(token) == address(0)) {
(bool success, ) = payable(msg.sender).call{value: amount}('');
require(success, 'rescueFund: failed to collect native');
} else {
token.safeTransfer(msg.sender, amount);
}
emit RescueFund(address(token), amount);
}
/// @notice Returns bitmask for double-spend invalidators based on lowest byte of order.info and filled quotes
/// @return Result Each bit represents whenever corresponding quote was filled
function invalidatorForOrderRFQ(address maker, uint256 slot) external view returns (uint256) {
return invalidator[maker][slot];
}
/// @notice Cancels order's quote
function cancelOrderRFQ(uint256 orderInfo) external {
_invalidateOrder(msg.sender, orderInfo);
}
/// @notice Fills an order's quote, either fully or partially
/// @dev Funds will be sent to msg.sender
/// @param order Order quote to fill
/// @param signature Signature to confirm quote ownership
/// @param makingAmount Maker amount
/// @param takingAmount Taker amount
function fillOrderRFQ(
OrderRFQ memory order,
bytes memory signature,
uint256 makingAmount,
uint256 takingAmount
)
external
payable
returns (
uint256, /* actualmakingAmount */
uint256 /* actualtakingAmount */
)
{
return fillOrderRFQTo(order, signature, makingAmount, takingAmount, payable(msg.sender));
}
/// @notice Main function for fulfilling orders
/// @param order Order quote to fill
/// @param signature Signature to confirm quote ownership
/// @param makingAmount Maker amount
/// @param takingAmount Taker amount
/// @param target Address that will receive swapped funds
function fillOrderRFQTo(
OrderRFQ memory order,
bytes memory signature,
uint256 makingAmount,
uint256 takingAmount,
address payable target
)
public
payable
returns (
uint256, /* actualmakingAmount */
uint256 /* actualtakingAmount */
)
{
address maker = order.maker;
bool unwrapWETH = (order.info & _UNWRAPWETH_MASK) > 0;
{
// Stack too deep
uint256 info = order.info;
// Check time expiration
uint256 expiration = uint128(info) >> 64;
require(expiration == 0 || block.timestamp <= expiration, 'KS_RFQ: order expired');
_invalidateOrder(maker, info);
}
{
// stack too deep
uint256 orderMakingAmount = order.makingAmount;
uint256 orderTakingAmount = order.takingAmount;
// Compute partial fill if needed
// Both zeros = fill whole order
if (takingAmount == 0 && makingAmount == 0) {
makingAmount = orderMakingAmount;
takingAmount = orderTakingAmount;
} else if (takingAmount == 0) {
// makingAmount specified, calculate takingAmount
require(makingAmount <= orderMakingAmount, 'KS_RFQ: maker amount exceeded');
// expected amount = orderTakingAmount * makingAmount / orderMakingAmount
// add taker fee: (orderMakingAmount - 1) / orderMakingAmount
takingAmount = (orderTakingAmount * makingAmount + orderMakingAmount - 1) / orderMakingAmount;
} else if (makingAmount == 0) {
// takingAmount specified, calculate makingAmount
require(takingAmount <= orderTakingAmount, 'KS_RFQ: taker amount exceeded');
makingAmount = (orderMakingAmount * takingAmount) / orderTakingAmount;
} else {
revert('KS_RFQ: both amounts are non-zero');
}
}
require(makingAmount > 0 && takingAmount > 0, "KS_RFQ: can't swap zero amount");
// Validate order
require(order.allowedSender == address(0) || order.allowedSender == msg.sender, 'KS_RFQ: private order');
bytes32 orderHash = _hashTypedDataV4(keccak256(abi.encode(LIMIT_ORDER_RFQ_TYPEHASH, order)));
_validate(maker, orderHash, signature);
// Maker => Taker
if (order.makerAsset == address(WETH) && unwrapWETH) {
IERC20(order.makerAsset).safeTransferFrom(maker, address(this), makingAmount);
WETH.withdraw(makingAmount);
target.transfer(makingAmount);
} else {
IERC20(order.makerAsset).safeTransferFrom(maker, target, makingAmount);
}
// Taker => Maker
if (address(order.takerAsset) == address(WETH) && msg.value > 0) {
require(msg.value == takingAmount, 'KS_RFQ: wrong msg.value');
WETH.deposit{value: takingAmount}();
WETH.transfer(maker, takingAmount);
} else {
require(msg.value == 0, 'KS_RFQ: wrong msg.value');
IERC20(order.takerAsset).safeTransferFrom(msg.sender, maker, takingAmount);
}
emit OrderFilledRFQ(orderHash, maker, target, order.makerAsset, order.takerAsset, makingAmount, takingAmount);
return (makingAmount, takingAmount);
}
function _validate(
address signer,
bytes32 orderHash,
bytes memory signature
) private view {
(address recoveredSigner, ) = ECDSA.tryRecover(orderHash, signature);
require(recoveredSigner != address(0), 'KS_RFQ: invalid signer');
if (recoveredSigner != signer) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271.isValidSignature.selector, orderHash, signature)
);
require(
success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector,
'KS_RFQ: bad signature'
);
}
}
function _invalidateOrder(address maker, uint256 orderInfo) private {
uint256 invalidatorSlot = uint64(orderInfo) >> 8;
uint256 invalidatorBit = 1 << uint8(orderInfo);
mapping(uint256 => uint256) storage invalidatorStorage = invalidator[maker];
uint256 invalidated = invalidatorStorage[invalidatorSlot];
require(invalidated & invalidatorBit == 0, 'KS_RFQ: invalidated order');
invalidatorStorage[invalidatorSlot] = invalidated | invalidatorBit;
}
}
File 4 of 7: AdminUpgradeabilityProxy
/**
*Submitted for verification at Etherscan.io on 2018-10-22
*/
pragma solidity ^0.4.24;
// File: contracts/upgradeability/Proxy.sol
/**
* @title Proxy
* @dev Implements delegation of calls to other contracts, with proper
* forwarding of return values and bubbling of failures.
* It defines a fallback function that delegates all calls to the address
* returned by the abstract _implementation() internal function.
*/
contract Proxy {
/**
* @dev Fallback function.
* Implemented entirely in `_fallback`.
*/
function () payable external {
_fallback();
}
/**
* @return The Address of the implementation.
*/
function _implementation() internal view returns (address);
/**
* @dev Delegates execution to an implementation contract.
* This is a low level function that doesn't return to its internal call site.
* It will return to the external caller whatever the implementation returns.
* @param implementation Address to delegate.
*/
function _delegate(address implementation) internal {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize)
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize)
switch result
// delegatecall returns 0 on error.
case 0 { revert(0, returndatasize) }
default { return(0, returndatasize) }
}
}
/**
* @dev Function that is run as the first thing in the fallback function.
* Can be redefined in derived contracts to add functionality.
* Redefinitions must call super._willFallback().
*/
function _willFallback() internal {
}
/**
* @dev fallback implementation.
* Extracted to enable manual triggering.
*/
function _fallback() internal {
_willFallback();
_delegate(_implementation());
}
}
// File: openzeppelin-solidity/contracts/AddressUtils.sol
/**
* Utility library of inline functions on addresses
*/
library AddressUtils {
/**
* Returns whether the target address is a contract
* @dev This function will return false if invoked during the constructor of a contract,
* as the code is not actually created until after the constructor finishes.
* @param addr address to check
* @return whether the target address is a contract
*/
function isContract(address addr) internal view returns (bool) {
uint256 size;
// XXX Currently there is no better way to check if there is a contract in an address
// than to check the size of the code at that address.
// See https://ethereum.stackexchange.com/a/14016/36603
// for more details about how this works.
// TODO Check this again before the Serenity release, because all addresses will be
// contracts then.
// solium-disable-next-line security/no-inline-assembly
assembly { size := extcodesize(addr) }
return size > 0;
}
}
// File: contracts/upgradeability/UpgradeabilityProxy.sol
/**
* @title UpgradeabilityProxy
* @dev This contract implements a proxy that allows to change the
* implementation address to which it will delegate.
* Such a change is called an implementation upgrade.
*/
contract UpgradeabilityProxy is Proxy {
/**
* @dev Emitted when the implementation is upgraded.
* @param implementation Address of the new implementation.
*/
event Upgraded(address indexed implementation);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is
* validated in the constructor.
*/
bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;
/**
* @dev Contract constructor.
* @param _implementation Address of the initial implementation.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
constructor(address _implementation, bytes _data) public payable {
assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation"));
_setImplementation(_implementation);
if(_data.length > 0) {
require(_implementation.delegatecall(_data));
}
}
/**
* @dev Returns the current implementation.
* @return Address of the current implementation
*/
function _implementation() internal view returns (address impl) {
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
impl := sload(slot)
}
}
/**
* @dev Upgrades the proxy to a new implementation.
* @param newImplementation Address of the new implementation.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Sets the implementation address of the proxy.
* @param newImplementation Address of the new implementation.
*/
function _setImplementation(address newImplementation) private {
require(AddressUtils.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
sstore(slot, newImplementation)
}
}
}
// File: contracts/upgradeability/AdminUpgradeabilityProxy.sol
/**
* @title AdminUpgradeabilityProxy
* @dev This contract combines an upgradeability proxy with an authorization
* mechanism for administrative tasks.
* All external functions in this contract must be guarded by the
* `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
* feature proposal that would enable this to be done automatically.
*/
contract AdminUpgradeabilityProxy is UpgradeabilityProxy {
/**
* @dev Emitted when the administration has been transferred.
* @param previousAdmin Address of the previous admin.
* @param newAdmin Address of the new admin.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is
* validated in the constructor.
*/
bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b;
/**
* @dev Modifier to check whether the `msg.sender` is the admin.
* If it is, it will run the function. Otherwise, it will delegate the call
* to the implementation.
*/
modifier ifAdmin() {
if (msg.sender == _admin()) {
_;
} else {
_fallback();
}
}
/**
* Contract constructor.
* It sets the `msg.sender` as the proxy administrator.
* @param _implementation address of the initial implementation.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
constructor(address _implementation, bytes _data) UpgradeabilityProxy(_implementation, _data) public payable {
assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin"));
_setAdmin(msg.sender);
}
/**
* @return The address of the proxy admin.
*/
function admin() external view ifAdmin returns (address) {
return _admin();
}
/**
* @return The address of the implementation.
*/
function implementation() external view ifAdmin returns (address) {
return _implementation();
}
/**
* @dev Changes the admin of the proxy.
* Only the current admin can call this function.
* @param newAdmin Address to transfer proxy administration to.
*/
function changeAdmin(address newAdmin) external ifAdmin {
require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
emit AdminChanged(_admin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev Upgrade the backing implementation of the proxy.
* Only the admin can call this function.
* @param newImplementation Address of the new implementation.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeTo(newImplementation);
}
/**
* @dev Upgrade the backing implementation of the proxy and call a function
* on the new implementation.
* This is useful to initialize the proxied contract.
* @param newImplementation Address of the new implementation.
* @param data Data to send as msg.data in the low level call.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
*/
function upgradeToAndCall(address newImplementation, bytes data) payable external ifAdmin {
_upgradeTo(newImplementation);
require(newImplementation.delegatecall(data));
}
/**
* @return The admin slot.
*/
function _admin() internal view returns (address adm) {
bytes32 slot = ADMIN_SLOT;
assembly {
adm := sload(slot)
}
}
/**
* @dev Sets the address of the proxy admin.
* @param newAdmin Address of the new proxy admin.
*/
function _setAdmin(address newAdmin) internal {
bytes32 slot = ADMIN_SLOT;
assembly {
sstore(slot, newAdmin)
}
}
/**
* @dev Only fall back when the sender is not the admin.
*/
function _willFallback() internal {
require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
super._willFallback();
}
}File 5 of 7: MetaAggregationRouterV2
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/utils/Context.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import './dependency/Permitable.sol';
import './interfaces/IAggregationExecutor.sol';
import './interfaces/IAggregationExecutor1Inch.sol';
import './libraries/TransferHelper.sol';
import './libraries/RevertReasonParser.sol';
contract MetaAggregationRouterV2 is Permitable, Ownable {
using SafeERC20 for IERC20;
address public immutable WETH;
address private constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
uint256 private constant _PARTIAL_FILL = 0x01;
uint256 private constant _REQUIRES_EXTRA_ETH = 0x02;
uint256 private constant _SHOULD_CLAIM = 0x04;
uint256 private constant _BURN_FROM_MSG_SENDER = 0x08;
uint256 private constant _BURN_FROM_TX_ORIGIN = 0x10;
uint256 private constant _SIMPLE_SWAP = 0x20;
uint256 private constant _FEE_ON_DST = 0x40;
uint256 private constant _FEE_IN_BPS = 0x80;
uint256 private constant _APPROVE_FUND = 0x100;
uint256 private constant BPS = 10000;
mapping(address => bool) public isWhitelist;
struct SwapDescriptionV2 {
IERC20 srcToken;
IERC20 dstToken;
address[] srcReceivers; // transfer src token to these addresses, default
uint256[] srcAmounts;
address[] feeReceivers;
uint256[] feeAmounts;
address dstReceiver;
uint256 amount;
uint256 minReturnAmount;
uint256 flags;
bytes permit;
}
/// @dev use for swapGeneric and swap to avoid stack too deep
struct SwapExecutionParams {
address callTarget; // call this address
address approveTarget; // approve this address if _APPROVE_FUND set
bytes targetData;
SwapDescriptionV2 desc;
bytes clientData;
}
struct SimpleSwapData {
address[] firstPools;
uint256[] firstSwapAmounts;
bytes[] swapDatas;
uint256 deadline;
bytes destTokenFeeData;
}
event Swapped(
address sender,
IERC20 srcToken,
IERC20 dstToken,
address dstReceiver,
uint256 spentAmount,
uint256 returnAmount
);
event ClientData(bytes clientData);
event Exchange(address pair, uint256 amountOut, address output);
event Fee(address token, uint256 totalAmount, uint256 totalFee, address[] recipients, uint256[] amounts, bool isBps);
constructor(address _WETH) {
WETH = _WETH;
}
receive() external payable {}
function rescueFunds(address token, uint256 amount) external onlyOwner {
if (_isETH(IERC20(token))) {
TransferHelper.safeTransferETH(msg.sender, amount);
} else {
TransferHelper.safeTransfer(token, msg.sender, amount);
}
}
function updateWhitelist(address[] memory addr, bool[] memory value) external onlyOwner {
require(addr.length == value.length);
for (uint256 i; i < addr.length; ++i) {
isWhitelist[addr[i]] = value[i];
}
}
function swapGeneric(SwapExecutionParams calldata execution)
external
payable
returns (uint256 returnAmount, uint256 gasUsed)
{
uint256 gasBefore = gasleft();
require(isWhitelist[execution.callTarget], 'Address not whitelisted');
if (execution.approveTarget != execution.callTarget && execution.approveTarget != address(0)) {
require(isWhitelist[execution.approveTarget], 'Address not whitelisted');
}
SwapDescriptionV2 memory desc = execution.desc;
require(desc.minReturnAmount > 0, 'Invalid min return amount');
// if extra eth is needed, in case srcToken is ETH
_collectExtraETHIfNeeded(desc);
_permit(desc.srcToken, desc.amount, desc.permit);
bool feeInBps = _flagsChecked(desc.flags, _FEE_IN_BPS);
uint256 spentAmount;
address dstReceiver = desc.dstReceiver == address(0) ? msg.sender : desc.dstReceiver;
if (!_flagsChecked(desc.flags, _FEE_ON_DST)) {
// fee on src token
// take fee on srcToken
// take fee and deduct total amount
desc.amount = _takeFee(desc.srcToken, msg.sender, desc.feeReceivers, desc.feeAmounts, desc.amount, feeInBps);
bool collected;
if (!_isETH(desc.srcToken) && _flagsChecked(desc.flags, _SHOULD_CLAIM)) {
(collected, desc.amount) = _collectTokenIfNeeded(desc, msg.sender, address(this));
}
_transferFromOrApproveTarget(msg.sender, execution.approveTarget, desc, collected);
// execute swap
(spentAmount, returnAmount) = _executeSwap(
execution.callTarget,
execution.targetData,
desc,
_isETH(desc.srcToken) ? desc.amount : 0,
dstReceiver
);
} else {
bool collected;
if (!_isETH(desc.srcToken) && _flagsChecked(desc.flags, _SHOULD_CLAIM)) {
(collected, desc.amount) = _collectTokenIfNeeded(desc, msg.sender, address(this));
}
uint256 initialDstReceiverBalance = _getBalance(desc.dstToken, dstReceiver);
_transferFromOrApproveTarget(msg.sender, execution.approveTarget, desc, collected);
// fee on dst token
// router get dst token first
(spentAmount, returnAmount) = _executeSwap(
execution.callTarget,
execution.targetData,
desc,
_isETH(desc.srcToken) ? msg.value : 0,
address(this)
);
{
// then take fee on dst token
uint256 leftAmount = _takeFee(
desc.dstToken,
address(this),
desc.feeReceivers,
desc.feeAmounts,
returnAmount,
feeInBps
);
_doTransferERC20(desc.dstToken, address(this), dstReceiver, leftAmount);
}
returnAmount = _getBalance(desc.dstToken, dstReceiver) - initialDstReceiverBalance;
}
// check return amount
_checkReturnAmount(spentAmount, returnAmount, desc);
//revoke allowance
if (!_isETH(desc.srcToken) && execution.approveTarget != address(0)) {
desc.srcToken.safeApprove(execution.approveTarget, 0);
}
emit Swapped(msg.sender, desc.srcToken, desc.dstToken, dstReceiver, spentAmount, returnAmount);
emit Exchange(execution.callTarget, returnAmount, _isETH(desc.dstToken) ? WETH : address(desc.dstToken));
emit ClientData(execution.clientData);
unchecked {
gasUsed = gasBefore - gasleft();
}
}
function swap(SwapExecutionParams calldata execution)
external
payable
returns (uint256 returnAmount, uint256 gasUsed)
{
uint256 gasBefore = gasleft();
SwapDescriptionV2 memory desc = execution.desc;
require(desc.minReturnAmount > 0, 'Min return should not be 0');
require(execution.targetData.length > 0, 'executorData should be not zero');
// simple mode swap
if (_flagsChecked(desc.flags, _SIMPLE_SWAP)) {
return
swapSimpleMode(IAggregationExecutor(execution.callTarget), desc, execution.targetData, execution.clientData);
}
_collectExtraETHIfNeeded(desc);
_permit(desc.srcToken, desc.amount, desc.permit);
bool feeInBps = _flagsChecked(desc.flags, _FEE_IN_BPS);
uint256 spentAmount;
address dstReceiver = desc.dstReceiver == address(0) ? msg.sender : desc.dstReceiver;
if (!_flagsChecked(desc.flags, _FEE_ON_DST)) {
// fee on src token
{
// take fee on srcToken
// deduct total swap amount
desc.amount = _takeFee(
desc.srcToken,
msg.sender,
desc.feeReceivers,
desc.feeAmounts,
_isETH(desc.srcToken) ? msg.value : desc.amount,
feeInBps
);
// transfer fund from msg.sender to our executor
_transferFromOrApproveTarget(msg.sender, address(0), desc, false);
// execute swap
(spentAmount, returnAmount) = _executeSwap(
execution.callTarget,
abi.encodeWithSelector(IAggregationExecutor.callBytes.selector, execution.targetData),
desc,
_isETH(desc.srcToken) ? desc.amount : 0,
dstReceiver
);
}
} else {
// fee on dst token
// router get dst token first
uint256 initialDstReceiverBalance = _getBalance(desc.dstToken, dstReceiver);
// transfer fund from msg.sender to our executor
_transferFromOrApproveTarget(msg.sender, address(0), desc, false);
// swap to receive dstToken on this router
(spentAmount, returnAmount) = _executeSwap(
execution.callTarget,
abi.encodeWithSelector(IAggregationExecutor.callBytes.selector, execution.targetData),
desc,
_isETH(desc.srcToken) ? msg.value : 0,
address(this)
);
{
// then take fee on dst token
uint256 leftAmount = _takeFee(
desc.dstToken,
address(this),
desc.feeReceivers,
desc.feeAmounts,
returnAmount,
feeInBps
);
_doTransferERC20(desc.dstToken, address(this), dstReceiver, leftAmount);
}
returnAmount = _getBalance(desc.dstToken, dstReceiver) - initialDstReceiverBalance;
}
_checkReturnAmount(spentAmount, returnAmount, desc);
emit Swapped(msg.sender, desc.srcToken, desc.dstToken, dstReceiver, spentAmount, returnAmount);
emit Exchange(execution.callTarget, returnAmount, _isETH(desc.dstToken) ? WETH : address(desc.dstToken));
emit ClientData(execution.clientData);
unchecked {
gasUsed = gasBefore - gasleft();
}
}
function swapSimpleMode(
IAggregationExecutor caller,
SwapDescriptionV2 memory desc,
bytes calldata executorData,
bytes calldata clientData
) public returns (uint256 returnAmount, uint256 gasUsed) {
uint256 gasBefore = gasleft();
require(!_isETH(desc.srcToken), 'src is eth, should use normal swap');
_permit(desc.srcToken, desc.amount, desc.permit);
address dstReceiver = (desc.dstReceiver == address(0)) ? msg.sender : desc.dstReceiver;
{
bool isBps = _flagsChecked(desc.flags, _FEE_IN_BPS);
if (!_flagsChecked(desc.flags, _FEE_ON_DST)) {
// take fee and deduct total swap amount
desc.amount = _takeFee(desc.srcToken, msg.sender, desc.feeReceivers, desc.feeAmounts, desc.amount, isBps);
} else {
dstReceiver = address(this);
}
}
uint256 initialDstBalance = _getBalance(desc.dstToken, dstReceiver);
uint256 initialSrcBalance = _getBalance(desc.srcToken, msg.sender);
_swapMultiSequencesWithSimpleMode(
caller,
address(desc.srcToken),
desc.amount,
address(desc.dstToken),
dstReceiver,
executorData
);
// amount returned to this router
returnAmount = _getBalance(desc.dstToken, dstReceiver) - initialDstBalance;
{
// take fee
if (_flagsChecked(desc.flags, _FEE_ON_DST)) {
{
bool isBps = _flagsChecked(desc.flags, _FEE_IN_BPS);
returnAmount = _takeFee(
desc.dstToken,
address(this),
desc.feeReceivers,
desc.feeAmounts,
returnAmount,
isBps
);
}
IERC20 dstToken = desc.dstToken;
dstReceiver = desc.dstReceiver == address(0) ? msg.sender : desc.dstReceiver;
// dst receiver initial balance
initialDstBalance = _getBalance(dstToken, dstReceiver);
// transfer remainning token to dst receiver
_doTransferERC20(dstToken, address(this), dstReceiver, returnAmount);
// amount returned to dst receiver
returnAmount = _getBalance(dstToken, dstReceiver) - initialDstBalance;
}
}
uint256 spentAmount = initialSrcBalance - _getBalance(desc.srcToken, msg.sender);
_checkReturnAmount(spentAmount, returnAmount, desc);
emit Swapped(msg.sender, desc.srcToken, desc.dstToken, dstReceiver, spentAmount, returnAmount);
emit Exchange(address(caller), returnAmount, _isETH(desc.dstToken) ? WETH : address(desc.dstToken));
emit ClientData(clientData);
unchecked {
gasUsed = gasBefore - gasleft();
}
}
function _doTransferERC20(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
require(from != to, 'sender != recipient');
if (amount > 0) {
if (_isETH(token)) {
if (from == address(this)) TransferHelper.safeTransferETH(to, amount);
} else {
if (from == address(this)) {
TransferHelper.safeTransfer(address(token), to, amount);
} else {
TransferHelper.safeTransferFrom(address(token), from, to, amount);
}
}
}
}
// Only use this mode if the first pool of each sequence can receive tokenIn directly into the pool
function _swapMultiSequencesWithSimpleMode(
IAggregationExecutor caller,
address tokenIn,
uint256 totalSwapAmount,
address tokenOut,
address dstReceiver,
bytes calldata data
) internal {
SimpleSwapData memory swapData = abi.decode(data, (SimpleSwapData));
require(swapData.deadline >= block.timestamp, 'ROUTER: Expired');
require(
swapData.firstPools.length == swapData.firstSwapAmounts.length &&
swapData.firstPools.length == swapData.swapDatas.length,
'invalid swap data length'
);
uint256 numberSeq = swapData.firstPools.length;
for (uint256 i = 0; i < numberSeq; i++) {
// collect amount to the first pool
{
uint256 balanceBefore = _getBalance(IERC20(tokenIn), msg.sender);
_doTransferERC20(IERC20(tokenIn), msg.sender, swapData.firstPools[i], swapData.firstSwapAmounts[i]);
require(swapData.firstSwapAmounts[i] <= totalSwapAmount, 'invalid swap amount');
uint256 spentAmount = balanceBefore - _getBalance(IERC20(tokenIn), msg.sender);
totalSwapAmount -= spentAmount;
}
{
// solhint-disable-next-line avoid-low-level-calls
// may take some native tokens for commission fee
(bool success, bytes memory result) = address(caller).call(
abi.encodeWithSelector(caller.swapSingleSequence.selector, swapData.swapDatas[i])
);
if (!success) {
revert(RevertReasonParser.parse(result, 'swapSingleSequence failed: '));
}
}
}
{
// solhint-disable-next-line avoid-low-level-calls
// may take some native tokens for commission fee
(bool success, bytes memory result) = address(caller).call(
abi.encodeWithSelector(
caller.finalTransactionProcessing.selector,
tokenIn,
tokenOut,
dstReceiver,
swapData.destTokenFeeData
)
);
if (!success) {
revert(RevertReasonParser.parse(result, 'finalTransactionProcessing failed: '));
}
}
}
function _getBalance(IERC20 token, address account) internal view returns (uint256) {
if (_isETH(token)) {
return account.balance;
} else {
return token.balanceOf(account);
}
}
function _isETH(IERC20 token) internal pure returns (bool) {
return (address(token) == ETH_ADDRESS);
}
/// @dev this function calls to external contract to execute swap and also validate the returned amounts
function _executeSwap(
address callTarget,
bytes memory targetData,
SwapDescriptionV2 memory desc,
uint256 value,
address dstReceiver
) internal returns (uint256 spentAmount, uint256 returnAmount) {
uint256 initialDstBalance = _getBalance(desc.dstToken, dstReceiver);
uint256 routerInitialSrcBalance = _getBalance(desc.srcToken, address(this));
uint256 routerInitialDstBalance = _getBalance(desc.dstToken, address(this));
{
// call to external contract
(bool success, ) = callTarget.call{value: value}(targetData);
require(success, 'Call failed');
}
// if the `callTarget` returns amount to `msg.sender`, meaning this contract
if (dstReceiver != address(this)) {
uint256 stuckAmount = _getBalance(desc.dstToken, address(this)) - routerInitialDstBalance;
_doTransferERC20(desc.dstToken, address(this), dstReceiver, stuckAmount);
}
// safe check here
returnAmount = _getBalance(desc.dstToken, dstReceiver) - initialDstBalance;
spentAmount = desc.amount;
//should refund tokens router collected when partial fill
if (
_flagsChecked(desc.flags, _PARTIAL_FILL) && (_isETH(desc.srcToken) || _flagsChecked(desc.flags, _SHOULD_CLAIM))
) {
uint256 currBalance = _getBalance(desc.srcToken, address(this));
if (currBalance != routerInitialSrcBalance) {
spentAmount = routerInitialSrcBalance - currBalance;
_doTransferERC20(desc.srcToken, address(this), msg.sender, desc.amount - spentAmount);
}
}
}
function _collectExtraETHIfNeeded(SwapDescriptionV2 memory desc) internal {
bool srcETH = _isETH(desc.srcToken);
if (_flagsChecked(desc.flags, _REQUIRES_EXTRA_ETH)) {
require(msg.value > (srcETH ? desc.amount : 0), 'Invalid msg.value');
} else {
require(msg.value == (srcETH ? desc.amount : 0), 'Invalid msg.value');
}
}
function _collectTokenIfNeeded(
SwapDescriptionV2 memory desc,
address from,
address to
) internal returns (bool collected, uint256 amount) {
require(!_isETH(desc.srcToken), 'Claim token is ETH');
uint256 initialRouterSrcBalance = _getBalance(desc.srcToken, address(this));
_doTransferERC20(desc.srcToken, from, to, desc.amount);
collected = true;
amount = _getBalance(desc.srcToken, address(this)) - initialRouterSrcBalance;
}
/// @dev transfer fund to `callTarget` or approve `approveTarget`
function _transferFromOrApproveTarget(
address from,
address approveTarget,
SwapDescriptionV2 memory desc,
bool collected
) internal {
// if token is collected
require(desc.srcReceivers.length == desc.srcAmounts.length, 'invalid srcReceivers length');
if (collected) {
if (_flagsChecked(desc.flags, _APPROVE_FUND) && approveTarget != address(0)) {
// approve to approveTarget since some systems use an allowance proxy contract
desc.srcToken.safeIncreaseAllowance(approveTarget, desc.amount);
return;
}
}
uint256 total;
for (uint256 i; i < desc.srcReceivers.length; ++i) {
total += desc.srcAmounts[i];
_doTransferERC20(desc.srcToken, collected ? address(this) : from, desc.srcReceivers[i], desc.srcAmounts[i]);
}
require(total <= desc.amount, 'Exceeded desc.amount');
}
/// @dev token transferred from `from` to `feeData.recipients`
function _takeFee(
IERC20 token,
address from,
address[] memory recipients,
uint256[] memory amounts,
uint256 totalAmount,
bool inBps
) internal returns (uint256 leftAmount) {
leftAmount = totalAmount;
uint256 recipientsLen = recipients.length;
if (recipientsLen > 0) {
bool isETH = _isETH(token);
uint256 balanceBefore = _getBalance(token, isETH ? address(this) : from);
require(amounts.length == recipientsLen, 'Invalid length');
for (uint256 i; i < recipientsLen; ++i) {
uint256 amount = inBps ? (totalAmount * amounts[i]) / BPS : amounts[i];
_doTransferERC20(token, isETH ? address(this) : from, recipients[i], amount);
}
uint256 totalFee = balanceBefore - _getBalance(token, isETH ? address(this) : from);
leftAmount = totalAmount - totalFee;
emit Fee(address(token), totalAmount, totalFee, recipients, amounts, inBps);
}
}
function _checkReturnAmount(
uint256 spentAmount,
uint256 returnAmount,
SwapDescriptionV2 memory desc
) internal pure {
if (_flagsChecked(desc.flags, _PARTIAL_FILL)) {
require(returnAmount * desc.amount >= desc.minReturnAmount * spentAmount, 'Return amount is not enough');
} else {
require(returnAmount >= desc.minReturnAmount, 'Return amount is not enough');
}
}
function _flagsChecked(uint256 number, uint256 flag) internal pure returns (bool) {
return number & flag != 0;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol';
import '../libraries/RevertReasonParser.sol';
/*
“Copyright (c) 2019-2021 1inch
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE”.
*/
contract Permitable {
event Error(string reason);
function _permit(
IERC20 token,
uint256 amount,
bytes memory permit
) internal {
if (permit.length == 32 * 7) {
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory result) = address(token).call(
abi.encodePacked(IERC20Permit.permit.selector, permit)
);
if (!success) {
string memory reason = RevertReasonParser.parse(result, 'Permit call failed: ');
if (token.allowance(msg.sender, address(this)) < amount) {
revert(reason);
} else {
emit Error(reason);
}
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12;
interface IAggregationExecutor {
function callBytes(bytes calldata data) external payable; // 0xd9c45357
// callbytes per swap sequence
function swapSingleSequence(bytes calldata data) external;
function finalTransactionProcessing(
address tokenIn,
address tokenOut,
address to,
bytes calldata destTokenFeeData
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import '@openzeppelin/contracts/interfaces/IERC20.sol';
interface IAggregationExecutor1Inch {
function callBytes(address msgSender, bytes calldata data) external payable; // 0x2636f7f8
}
interface IAggregationRouter1InchV4 {
function swap(
IAggregationExecutor1Inch caller,
SwapDescription1Inch calldata desc,
bytes calldata data
) external payable returns (uint256 returnAmount, uint256 gasLeft);
}
struct SwapDescription1Inch {
IERC20 srcToken;
IERC20 dstToken;
address payable srcReceiver;
address payable dstReceiver;
uint256 amount;
uint256 minReturnAmount;
uint256 flags;
bytes permit;
}
struct SwapDescriptionExecutor1Inch {
IERC20 srcToken;
IERC20 dstToken;
address payable srcReceiver1Inch;
address payable dstReceiver;
address[] srcReceivers;
uint256[] srcAmounts;
uint256 amount;
uint256 minReturnAmount;
uint256 flags;
bytes permit;
}
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.7.6;
/*
“Copyright (c) 2019-2021 1inch
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE”.
*/
library RevertReasonParser {
function parse(bytes memory data, string memory prefix) internal pure returns (string memory) {
// https://solidity.readthedocs.io/en/latest/control-structures.html#revert
// We assume that revert reason is abi-encoded as Error(string)
// 68 = 4-byte selector 0x08c379a0 + 32 bytes offset + 32 bytes length
if (data.length >= 68 && data[0] == '\\x08' && data[1] == '\\xc3' && data[2] == '\\x79' && data[3] == '\\xa0') {
string memory reason;
// solhint-disable no-inline-assembly
assembly {
// 68 = 32 bytes data length + 4-byte selector + 32 bytes offset
reason := add(data, 68)
}
/*
revert reason is padded up to 32 bytes with ABI encoder: Error(string)
also sometimes there is extra 32 bytes of zeros padded in the end:
https://github.com/ethereum/solidity/issues/10170
because of that we can't check for equality and instead check
that string length + extra 68 bytes is less than overall data length
*/
require(data.length >= 68 + bytes(reason).length, 'Invalid revert reason');
return string(abi.encodePacked(prefix, 'Error(', reason, ')'));
}
// 36 = 4-byte selector 0x4e487b71 + 32 bytes integer
else if (data.length == 36 && data[0] == '\\x4e' && data[1] == '\\x48' && data[2] == '\\x7b' && data[3] == '\\x71') {
uint256 code;
// solhint-disable no-inline-assembly
assembly {
// 36 = 32 bytes data length + 4-byte selector
code := mload(add(data, 36))
}
return string(abi.encodePacked(prefix, 'Panic(', _toHex(code), ')'));
}
return string(abi.encodePacked(prefix, 'Unknown(', _toHex(data), ')'));
}
function _toHex(uint256 value) private pure returns (string memory) {
return _toHex(abi.encodePacked(value));
}
function _toHex(bytes memory data) private pure returns (string memory) {
bytes16 alphabet = 0x30313233343536373839616263646566;
bytes memory str = new bytes(2 + data.length * 2);
str[0] = '0';
str[1] = 'x';
for (uint256 i = 0; i < data.length; i++) {
str[2 * i + 2] = alphabet[uint8(data[i] >> 4)];
str[2 * i + 3] = alphabet[uint8(data[i] & 0x0f)];
}
return string(str);
}
}
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.5.16;
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
if (value == 0) return;
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
if (value == 0) return;
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferETH(address to, uint256 value) internal {
if (value == 0) return;
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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 Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
File 6 of 7: GnosisSafeProxy
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/// @title IProxy - Helper interface to access masterCopy of the Proxy on-chain
/// @author Richard Meissner - <richard@gnosis.io>
interface IProxy {
function masterCopy() external view returns (address);
}
/// @title GnosisSafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
/// @author Stefan George - <stefan@gnosis.io>
/// @author Richard Meissner - <richard@gnosis.io>
contract GnosisSafeProxy {
// singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
// To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`
address internal singleton;
/// @dev Constructor function sets address of singleton contract.
/// @param _singleton Singleton address.
constructor(address _singleton) {
require(_singleton != address(0), "Invalid singleton address provided");
singleton = _singleton;
}
/// @dev Fallback function forwards all transactions and returns all received return data.
fallback() external payable {
// solhint-disable-next-line no-inline-assembly
assembly {
let _singleton := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
// 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
mstore(0, _singleton)
return(0, 0x20)
}
calldatacopy(0, 0, calldatasize())
let success := delegatecall(gas(), _singleton, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
if eq(success, 0) {
revert(0, returndatasize())
}
return(0, returndatasize())
}
}
}
/// @title Proxy Factory - Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
/// @author Stefan George - <stefan@gnosis.pm>
contract GnosisSafeProxyFactory {
event ProxyCreation(GnosisSafeProxy proxy, address singleton);
/// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
/// @param singleton Address of singleton contract.
/// @param data Payload for message call sent to new proxy contract.
function createProxy(address singleton, bytes memory data) public returns (GnosisSafeProxy proxy) {
proxy = new GnosisSafeProxy(singleton);
if (data.length > 0)
// solhint-disable-next-line no-inline-assembly
assembly {
if eq(call(gas(), proxy, 0, add(data, 0x20), mload(data), 0, 0), 0) {
revert(0, 0)
}
}
emit ProxyCreation(proxy, singleton);
}
/// @dev Allows to retrieve the runtime code of a deployed Proxy. This can be used to check that the expected Proxy was deployed.
function proxyRuntimeCode() public pure returns (bytes memory) {
return type(GnosisSafeProxy).runtimeCode;
}
/// @dev Allows to retrieve the creation code used for the Proxy deployment. With this it is easily possible to calculate predicted address.
function proxyCreationCode() public pure returns (bytes memory) {
return type(GnosisSafeProxy).creationCode;
}
/// @dev Allows to create new proxy contact using CREATE2 but it doesn't run the initializer.
/// This method is only meant as an utility to be called from other methods
/// @param _singleton Address of singleton contract.
/// @param initializer Payload for message call sent to new proxy contract.
/// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
function deployProxyWithNonce(
address _singleton,
bytes memory initializer,
uint256 saltNonce
) internal returns (GnosisSafeProxy proxy) {
// If the initializer changes the proxy address should change too. Hashing the initializer data is cheaper than just concatinating it
bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
bytes memory deploymentData = abi.encodePacked(type(GnosisSafeProxy).creationCode, uint256(uint160(_singleton)));
// solhint-disable-next-line no-inline-assembly
assembly {
proxy := create2(0x0, add(0x20, deploymentData), mload(deploymentData), salt)
}
require(address(proxy) != address(0), "Create2 call failed");
}
/// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
/// @param _singleton Address of singleton contract.
/// @param initializer Payload for message call sent to new proxy contract.
/// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
function createProxyWithNonce(
address _singleton,
bytes memory initializer,
uint256 saltNonce
) public returns (GnosisSafeProxy proxy) {
proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
if (initializer.length > 0)
// solhint-disable-next-line no-inline-assembly
assembly {
if eq(call(gas(), proxy, 0, add(initializer, 0x20), mload(initializer), 0, 0), 0) {
revert(0, 0)
}
}
emit ProxyCreation(proxy, _singleton);
}
/// @dev Allows to create new proxy contact, execute a message call to the new proxy and call a specified callback within one transaction
/// @param _singleton Address of singleton contract.
/// @param initializer Payload for message call sent to new proxy contract.
/// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
/// @param callback Callback that will be invoced after the new proxy contract has been successfully deployed and initialized.
function createProxyWithCallback(
address _singleton,
bytes memory initializer,
uint256 saltNonce,
IProxyCreationCallback callback
) public returns (GnosisSafeProxy proxy) {
uint256 saltNonceWithCallback = uint256(keccak256(abi.encodePacked(saltNonce, callback)));
proxy = createProxyWithNonce(_singleton, initializer, saltNonceWithCallback);
if (address(callback) != address(0)) callback.proxyCreated(proxy, _singleton, initializer, saltNonce);
}
/// @dev Allows to get the address for a new proxy contact created via `createProxyWithNonce`
/// This method is only meant for address calculation purpose when you use an initializer that would revert,
/// therefore the response is returned with a revert. When calling this method set `from` to the address of the proxy factory.
/// @param _singleton Address of singleton contract.
/// @param initializer Payload for message call sent to new proxy contract.
/// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
function calculateCreateProxyWithNonceAddress(
address _singleton,
bytes calldata initializer,
uint256 saltNonce
) external returns (GnosisSafeProxy proxy) {
proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
revert(string(abi.encodePacked(proxy)));
}
}
interface IProxyCreationCallback {
function proxyCreated(
GnosisSafeProxy proxy,
address _singleton,
bytes calldata initializer,
uint256 saltNonce
) external;
}File 7 of 7: RenderToken
pragma solidity ^0.4.24;
// File: /Users/matthewmcclure/repos/Token-Audit/node_modules/openzeppelin-zos/contracts/token/ERC20/ERC20Basic.sol
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
// File: /Users/matthewmcclure/repos/Token-Audit/node_modules/openzeppelin-zos/contracts/token/ERC20/ERC20.sol
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// File: /Users/matthewmcclure/repos/Token-Audit/node_modules/openzeppelin-zos/contracts/token/ERC20/SafeERC20.sol
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure.
* 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 {
function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
assert(token.transfer(to, value));
}
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 value
)
internal
{
assert(token.transferFrom(from, to, value));
}
function safeApprove(ERC20 token, address spender, uint256 value) internal {
assert(token.approve(spender, value));
}
}
// File: /Users/matthewmcclure/repos/Token-Audit/node_modules/zos-lib/contracts/migrations/Migratable.sol
/**
* @title Migratable
* Helper contract to support intialization and migration schemes between
* different implementations of a contract in the context of upgradeability.
* To use it, replace the constructor with a function that has the
* `isInitializer` modifier starting with `"0"` as `migrationId`.
* When you want to apply some migration code during an upgrade, increase
* the `migrationId`. Or, if the migration code must be applied only after
* another migration has been already applied, use the `isMigration` modifier.
* This helper supports multiple inheritance.
* WARNING: It is the developer's responsibility to ensure that migrations are
* applied in a correct order, or that they are run at all.
* See `Initializable` for a simpler version.
*/
contract Migratable {
/**
* @dev Emitted when the contract applies a migration.
* @param contractName Name of the Contract.
* @param migrationId Identifier of the migration applied.
*/
event Migrated(string contractName, string migrationId);
/**
* @dev Mapping of the already applied migrations.
* (contractName => (migrationId => bool))
*/
mapping (string => mapping (string => bool)) internal migrated;
/**
* @dev Internal migration id used to specify that a contract has already been initialized.
*/
string constant private INITIALIZED_ID = "initialized";
/**
* @dev Modifier to use in the initialization function of a contract.
* @param contractName Name of the contract.
* @param migrationId Identifier of the migration.
*/
modifier isInitializer(string contractName, string migrationId) {
validateMigrationIsPending(contractName, INITIALIZED_ID);
validateMigrationIsPending(contractName, migrationId);
_;
emit Migrated(contractName, migrationId);
migrated[contractName][migrationId] = true;
migrated[contractName][INITIALIZED_ID] = true;
}
/**
* @dev Modifier to use in the migration of a contract.
* @param contractName Name of the contract.
* @param requiredMigrationId Identifier of the previous migration, required
* to apply new one.
* @param newMigrationId Identifier of the new migration to be applied.
*/
modifier isMigration(string contractName, string requiredMigrationId, string newMigrationId) {
require(isMigrated(contractName, requiredMigrationId), "Prerequisite migration ID has not been run yet");
validateMigrationIsPending(contractName, newMigrationId);
_;
emit Migrated(contractName, newMigrationId);
migrated[contractName][newMigrationId] = true;
}
/**
* @dev Returns true if the contract migration was applied.
* @param contractName Name of the contract.
* @param migrationId Identifier of the migration.
* @return true if the contract migration was applied, false otherwise.
*/
function isMigrated(string contractName, string migrationId) public view returns(bool) {
return migrated[contractName][migrationId];
}
/**
* @dev Initializer that marks the contract as initialized.
* It is important to run this if you had deployed a previous version of a Migratable contract.
* For more information see https://github.com/zeppelinos/zos-lib/issues/158.
*/
function initialize() isInitializer("Migratable", "1.2.1") public {
}
/**
* @dev Reverts if the requested migration was already executed.
* @param contractName Name of the contract.
* @param migrationId Identifier of the migration.
*/
function validateMigrationIsPending(string contractName, string migrationId) private {
require(!isMigrated(contractName, migrationId), "Requested target migration ID has already been run");
}
}
// File: /Users/matthewmcclure/repos/Token-Audit/node_modules/openzeppelin-zos/contracts/ownership/Ownable.sol
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable is Migratable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function initialize(address _sender) public isInitializer("Ownable", "1.9.0") {
owner = _sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
// File: /Users/matthewmcclure/repos/Token-Audit/node_modules/openzeppelin-zos/contracts/math/SafeMath.sol
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws 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 a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}
// File: /Users/matthewmcclure/repos/Token-Audit/contracts/Escrow.sol
/**
* @title Escrow
* @dev Escrow contract that works with RNDR token
* This contract holds tokens while render jobs are being completed
* and information on token allottment per job
*/
contract Escrow is Migratable, Ownable {
using SafeERC20 for ERC20;
using SafeMath for uint256;
// This is a mapping of job IDs to the number of tokens allotted to the job
mapping(string => uint256) private jobBalances;
// This is the address of the render token contract
address public renderTokenAddress;
// This is the address with authority to call the disburseJob function
address public disbursalAddress;
// Emit new disbursal address when disbursalAddress has been changed
event DisbursalAddressUpdate(address disbursalAddress);
// Emit the jobId along with the new balance of the job
// Used on job creation, additional funding added to jobs, and job disbursal
// Internal systems for assigning jobs will watch this event to determine balances available
event JobBalanceUpdate(string _jobId, uint256 _balance);
// Emit new contract address when renderTokenAddress has been changed
event RenderTokenAddressUpdate(address renderTokenAddress);
/**
* @dev Modifier to check if the message sender can call the disburseJob function
*/
modifier canDisburse() {
require(msg.sender == disbursalAddress, "message sender not authorized to disburse funds");
_;
}
/**
* @dev Initailization
* @param _owner because this contract uses proxies, owner must be passed in as a param
* @param _renderTokenAddress see renderTokenAddress
*/
function initialize (address _owner, address _renderTokenAddress) public isInitializer("Escrow", "0") {
require(_owner != address(0), "_owner must not be null");
require(_renderTokenAddress != address(0), "_renderTokenAddress must not be null");
Ownable.initialize(_owner);
disbursalAddress = _owner;
renderTokenAddress = _renderTokenAddress;
}
/**
* @dev Change the address authorized to distribute tokens for completed jobs
*
* Because there are no on-chain details to indicate who performed a render, an outside
* system must call the disburseJob function with the information needed to properly
* distribute tokens. This function updates the address with the authority to perform distributions
* @param _newDisbursalAddress see disbursalAddress
*/
function changeDisbursalAddress(address _newDisbursalAddress) external onlyOwner {
disbursalAddress = _newDisbursalAddress;
emit DisbursalAddressUpdate(disbursalAddress);
}
/**
* @dev Change the address allowances will be sent to after job completion
*
* Ideally, this will not be used, but is included as a failsafe.
* RNDR is still in its infancy, and changes may need to be made to this
* contract and / or the renderToken contract. Including methods to update the
* addresses allows the contracts to update independently.
* If the RNDR token contract is ever migrated to another address for
* either added security or functionality, this will need to be called.
* @param _newRenderTokenAddress see renderTokenAddress
*/
function changeRenderTokenAddress(address _newRenderTokenAddress) external onlyOwner {
require(_newRenderTokenAddress != address(0), "_newRenderTokenAddress must not be null");
renderTokenAddress = _newRenderTokenAddress;
emit RenderTokenAddressUpdate(renderTokenAddress);
}
/**
* @dev Send allowances to node(s) that performed a job
*
* This can only be called by the disbursalAddress, an accound owned
* by OTOY, and it provides the number of tokens to send to each node
* @param _jobId the ID of the job used in the jobBalances mapping
* @param _recipients the address(es) of the nodes that performed rendering
* @param _amounts the amount(s) to send to each address. These must be in the same
* order as the recipient addresses
*/
function disburseJob(string _jobId, address[] _recipients, uint256[] _amounts) external canDisburse {
require(jobBalances[_jobId] > 0, "_jobId has no available balance");
require(_recipients.length == _amounts.length, "_recipients and _amounts must be the same length");
for(uint256 i = 0; i < _recipients.length; i++) {
jobBalances[_jobId] = jobBalances[_jobId].sub(_amounts[i]);
ERC20(renderTokenAddress).safeTransfer(_recipients[i], _amounts[i]);
}
emit JobBalanceUpdate(_jobId, jobBalances[_jobId]);
}
/**
* @dev Add RNDR tokens to a job
*
* This can only be called by a function on the RNDR token contract
* @param _jobId the ID of the job used in the jobBalances mapping
* @param _tokens the number of tokens sent by the artist to fund the job
*/
function fundJob(string _jobId, uint256 _tokens) external {
// Jobs can only be created by the address stored in the renderTokenAddress variable
require(msg.sender == renderTokenAddress, "message sender not authorized");
jobBalances[_jobId] = jobBalances[_jobId].add(_tokens);
emit JobBalanceUpdate(_jobId, jobBalances[_jobId]);
}
/**
* @dev See the tokens available for a job
*
* @param _jobId the ID used to lookup the job balance
*/
function jobBalance(string _jobId) external view returns(uint256) {
return jobBalances[_jobId];
}
}
// File: /Users/matthewmcclure/repos/Token-Audit/contracts/MigratableERC20.sol
/**
* @title MigratableERC20
* @dev This strategy carries out an optional migration of the token balances. This migration is performed and paid for
* @dev by the token holders. The new token contract starts with no initial supply and no balances. The only way to
* @dev "mint" the new tokens is for users to "turn in" their old ones. This is done by first approving the amount they
* @dev want to migrate via `ERC20.approve(newTokenAddress, amountToMigrate)` and then calling a function of the new
* @dev token called `migrateTokens`. The old tokens are sent to a burn address, and the holder receives an equal amount
* @dev in the new contract.
*/
contract MigratableERC20 is Migratable {
using SafeERC20 for ERC20;
/// Burn address where the old tokens are going to be transferred
address public constant BURN_ADDRESS = address(0xdead);
/// Address of the old token contract
ERC20 public legacyToken;
/**
* @dev Initializes the new token contract
* @param _legacyToken address of the old token contract
*/
function initialize(address _legacyToken) isInitializer("OptInERC20Migration", "1.9.0") public {
legacyToken = ERC20(_legacyToken);
}
/**
* @dev Migrates the total balance of the token holder to this token contract
* @dev This function will burn the old token balance and mint the same balance in the new token contract
*/
function migrate() public {
uint256 amount = legacyToken.balanceOf(msg.sender);
migrateToken(amount);
}
/**
* @dev Migrates the given amount of old-token balance to the new token contract
* @dev This function will burn a given amount of tokens from the old contract and mint the same amount in the new one
* @param _amount uint256 representing the amount of tokens to be migrated
*/
function migrateToken(uint256 _amount) public {
migrateTokenTo(msg.sender, _amount);
}
/**
* @dev Burns a given amount of the old token contract for a token holder and mints the same amount of
* @dev new tokens for a given recipient address
* @param _amount uint256 representing the amount of tokens to be migrated
* @param _to address the recipient that will receive the new minted tokens
*/
function migrateTokenTo(address _to, uint256 _amount) public {
_mintMigratedTokens(_to, _amount);
legacyToken.safeTransferFrom(msg.sender, BURN_ADDRESS, _amount);
}
/**
* @dev Internal minting function
* This function must be overwritten by the implementation
*/
function _mintMigratedTokens(address _to, uint256 _amount) internal;
}
// File: /Users/matthewmcclure/repos/Token-Audit/node_modules/openzeppelin-zos/contracts/token/ERC20/BasicToken.sol
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
uint256 totalSupply_;
/**
* @dev total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256) {
return balances[_owner];
}
}
// File: /Users/matthewmcclure/repos/Token-Audit/node_modules/openzeppelin-zos/contracts/token/ERC20/StandardToken.sol
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
*
* 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
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) public view returns (uint256) {
return allowed[_owner][_spender];
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
*
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The amount of tokens to increase the allowance by.
*/
function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
*
* approve should be called when allowed[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
// File: contracts/RenderToken.sol
// Escrow constract
/**
* @title RenderToken
* @dev ERC20 mintable token
* The token will be minted by the crowdsale contract only
*/
contract RenderToken is Migratable, MigratableERC20, Ownable, StandardToken {
string public constant name = "Render Token";
string public constant symbol = "RNDR";
uint8 public constant decimals = 18;
// The address of the contract that manages job balances. Address is used for forwarding tokens
// that come in to fund jobs
address public escrowContractAddress;
// Emit new contract address when escrowContractAddress has been changed
event EscrowContractAddressUpdate(address escrowContractAddress);
// Emit information related to tokens being escrowed
event TokensEscrowed(address indexed sender, string jobId, uint256 amount);
// Emit information related to legacy tokens being migrated
event TokenMigration(address indexed receiver, uint256 amount);
/**
* @dev Initailization
* @param _owner because this contract uses proxies, owner must be passed in as a param
*/
function initialize(address _owner, address _legacyToken) public isInitializer("RenderToken", "0") {
require(_owner != address(0), "_owner must not be null");
require(_legacyToken != address(0), "_legacyToken must not be null");
Ownable.initialize(_owner);
MigratableERC20.initialize(_legacyToken);
}
/**
* @dev Take tokens prior to beginning a job
*
* This function is called by the artist, and it will transfer tokens
* to a separate escrow contract to be held until the job is completed
* @param _jobID is the ID of the job used within the ORC backend
* @param _amount is the number of RNDR tokens being held in escrow
*/
function holdInEscrow(string _jobID, uint256 _amount) public {
require(transfer(escrowContractAddress, _amount), "token transfer to escrow address failed");
Escrow(escrowContractAddress).fundJob(_jobID, _amount);
emit TokensEscrowed(msg.sender, _jobID, _amount);
}
/**
* @dev Mints new tokens equal to the amount of legacy tokens burned
*
* This function is called internally, but triggered by a user choosing to
* migrate their balance.
* @param _to is the address tokens will be sent to
* @param _amount is the number of RNDR tokens being sent to the address
*/
function _mintMigratedTokens(address _to, uint256 _amount) internal {
require(_to != address(0), "_to address must not be null");
totalSupply_ = totalSupply_.add(_amount);
balances[_to] = balances[_to].add(_amount);
emit TokenMigration(_to, _amount);
emit Transfer(address(0), _to, _amount);
}
/**
* @dev Set the address of the escrow contract
*
* This will dictate the contract that will hold tokens in escrow and keep
* a ledger of funds available for jobs.
* RNDR is still in its infancy, and changes may need to be made to this
* contract and / or the escrow contract. Including methods to update the
* addresses allows the contracts to update independently.
* If the escrow contract is ever migrated to another address for
* either added security or functionality, this will need to be called.
* @param _escrowAddress see escrowContractAddress
*/
function setEscrowContractAddress(address _escrowAddress) public onlyOwner {
require(_escrowAddress != address(0), "_escrowAddress must not be null");
escrowContractAddress = _escrowAddress;
emit EscrowContractAddressUpdate(escrowContractAddress);
}
}