Transaction Hash:
Block:
15800894 at Oct-22-2022 03:16:11 AM +UTC
Transaction Fee:
0.005006867568440832 ETH
$13.99
Gas Used:
254,307 Gas / 19.688280576 Gwei
Emitted Events:
| 41 |
UltraLightNodeV2.PacketReceived( srcChainId=111, srcAddress=0x701a9570...210360883, dstAddress=Bridge, nonce=3581, payloadHash=742E8D5CE27E0174B12F79CB8E5CCAEE4F9FF9DD35B8A4533DFA23ED26326048 )
|
| 42 |
Pool.CreditChainPath( chainId=111, srcPoolId=13, amountSD=0, idealBalance=347015996539005221654 )
|
| 43 |
StargateEthVault.TransferNative( src=Pool, dst=0xe42e3160...16879E9cb, wad=13991600000000000 )
|
| 44 |
Pool.SwapRemote( to=0xe42e3160...16879E9cb, amountSD=13991600000000000, protocolFee=6580000000000, dstFee=420000000000 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x10181654...633390A2E | |||||
| 0x66A71Dce...C225Cd675 | (LayerZero: Ethereum Endpoint) | ||||
| 0x72E2F483...FeF72eD9c | 14,555.714223017380314047 Eth | 14,555.700231417380314047 Eth | 0.0139916 | ||
|
0xDAFEA492...692c98Bc5
Miner
| (Flashbots: Builder) | 1.166004220230312586 Eth | 1.166857279342967164 Eth | 0.000853059112654578 | |
| 0xe42e3160...16879E9cb | 0.000154419246159294 Eth | 0.014146019246159294 Eth | 0.0139916 | ||
| 0xe93685f3...95988D950 | (Layer Zero: Executor) |
38.014714884134497708 Eth
Nonce: 43955
|
38.009708016566056876 Eth
Nonce: 43956
| 0.005006867568440832 |
Execution Trace
OptimizedTransparentUpgradeableProxy.252f7b01( )
0x76a15d86fbbe691557c8b7a9c4bebf1d8afe00a7.252f7b01( )UltraLightNodeV2.validateTransactionProof( _srcChainId=111, _dstAddress=0x296F55F8Fb28E498B858d0BcDA06D955B2Cb3f97, _gasLimit=1205000, _lookupHash=A09E5EF237ABA2D5C0212BC037F941DFFEAC5FE4E2DC208E2C59561786E895C9, _blockData=236CDAF91C38D5E2A595FB64613B87F980A0C70250B8918D9B34F4CFCCA2CAFB, _transactionProof=0x00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000B000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000A2DF90A2A822080B90A24F90A2101830610BAB90100000000400200000040000000000000000000400000000000200000010000001000000080000000000004000000180000000000000000000000000000002000000040000000000000000000080000200000010000000000000000000080000000000400000000000100800000000000000000900000004000000000980001000000000004000000000000000000000000000000012C0000000000008000000000020000004000432000000004000000000020000000000000000000800010000000001002000008000000000000000000000000400000000000000000000000001010800002000000000000000000100000010000000000400000400008000000F90916F87A94B69C8CBCD90A39D8D3D3CCF0A3E968511C3856A0F842A0E1FFFCC4923D04B559F4D29A8BFC6CDA04EB5B0D3C460751C2402C5C5CC9109CA0000000000000000000000000B49C4E680174E331CB0A7FF3AB58AFC9738D5F8BA00000000000000000000000000000000000000000000000000031BCED02DB0000F89B94B69C8CBCD90A39D8D3D3CCF0A3E968511C3856A0F863A08C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925A0000000000000000000000000B49C4E680174E331CB0A7FF3AB58AFC9738D5F8BA0000000000000000000000000B0D502E938ED5F4DF2E681FE6E419FF29631D62BA00000000000000000000000000000000000000000000000000031BCED02DB0000F9013A94D22363E3762CA7339569F3D33EADE20127D5F98CE1A034660FC8AF304464529F48A778E03D03E4D34BCD5F9B6F0CFBF3CD238C642F7FB901000000000000000000000000000000000000000000000000000000000000000065000000000000000000000000000000000000000000000000000000000000000D000000000000000000000000B49C4E680174E331CB0A7FF3AB58AFC9738D5F8B0000000000000000000000000000000000000000000000000031B5493BD6E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061C9F36800000000000000000000000000000000000000000000000000000005FC0690080000000000000000000000000000000000000000000000000000000145F680B000F89B94B69C8CBCD90A39D8D3D3CCF0A3E968511C3856A0F863A0DDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EFA0000000000000000000000000B49C4E680174E331CB0A7FF3AB58AFC9738D5F8BA0000000000000000000000000D22363E3762CA7339569F3D33EADE20127D5F98CA00000000000000000000000000000000000000000000000000031BCED02DB0000F8B994D22363E3762CA7339569F3D33EADE20127D5F98CE1A06939F93E3F21CF1362EB17155B740277DE5687DAE9A83A85909FD71DA95944E7B8800000000000000000000000000000000000000000000000000000000000000065000000000000000000000000000000000000000000000000000000000000000D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012CFD07A485D96BB16F8589481E792E5A9003CC1C8BF5569A00F34B65D75B017E1A0DF21C415B78ED2552CC9971249E32A053ABCE6087A0AE0FBF3F78DB5174A3493A00000000000000000000000000000000000000000000000000029D9E10E183880F8D9944D73ADB72BC3DD368966EDD0F0B2148401A178E2E1A0B0C632F55F1E1B3B2C3D82F41EE4716BB4C00F0F5D84CDAFC141581BB8757A4FB8A0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000022000100000000000000000000000000000000000000000000000000000000000320C8000000000000000000000000000000000000000000000000000000000000F8D994A0CC33DD6F4819D473226257792AFE230EC3C67FE1A04E41EE13E03CD5E0446487B524FDC48AF6ACF26C074DACDBDFB6B574B42C8146B8A0000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000014000000000000000000000000701A95707A0290AC8B90B3719E8EE5B2103608830000000000000000000000000000000000000000000000000007500A2C99B320F902DA944D73ADB72BC3DD368966EDD0F0B2148401A178E2E1A0E9BDED5F24A4168E4F3BF44E00298C993B22376AAD8C58C7DDA9718A54CBEA82B902A0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002540000000000000DFD006F701A95707A0290AC8B90B3719E8EE5B2103608830065296F55F8FB28E498B858D0BCDA06D955B2CB3F970000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000D000000000000000000000000000000000000000000000000000000000000000D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012CFD07A485D96BB160000000000000000000000000000000000000000000000000031B5493BD6E00000000000000000000000000000000000000000000000000000000061C9F36800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000145F680B000000000000000000000000000000000000000000000000000000005FC069008000000000000000000000000000000000000000000000000000031BBA70C5A500000000000000000000000000000000000000000000000000000000000000001C000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000014E42E316000B1AC5F9FB9536BB6987E916879E9CB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F87994701A95707A0290AC8B90B3719E8EE5B210360883E1A08D3EE0DF6A4B7E82A7F20A763F1C6826E6176323E655AF64F32318827D2112D4B84000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000DFD0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001 )-
MPTValidator01.validateProof( _receiptsRoot=236CDAF91C38D5E2A595FB64613B87F980A0C70250B8918D9B34F4CFCCA2CAFB, _transactionProof=0x00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000B000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000A2DF90A2A822080B90A24F90A2101830610BAB90100000000400200000040000000000000000000400000000000200000010000001000000080000000000004000000180000000000000000000000000000002000000040000000000000000000080000200000010000000000000000000080000000000400000000000100800000000000000000900000004000000000980001000000000004000000000000000000000000000000012C0000000000008000000000020000004000432000000004000000000020000000000000000000800010000000001002000008000000000000000000000000400000000000000000000000001010800002000000000000000000100000010000000000400000400008000000F90916F87A94B69C8CBCD90A39D8D3D3CCF0A3E968511C3856A0F842A0E1FFFCC4923D04B559F4D29A8BFC6CDA04EB5B0D3C460751C2402C5C5CC9109CA0000000000000000000000000B49C4E680174E331CB0A7FF3AB58AFC9738D5F8BA00000000000000000000000000000000000000000000000000031BCED02DB0000F89B94B69C8CBCD90A39D8D3D3CCF0A3E968511C3856A0F863A08C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925A0000000000000000000000000B49C4E680174E331CB0A7FF3AB58AFC9738D5F8BA0000000000000000000000000B0D502E938ED5F4DF2E681FE6E419FF29631D62BA00000000000000000000000000000000000000000000000000031BCED02DB0000F9013A94D22363E3762CA7339569F3D33EADE20127D5F98CE1A034660FC8AF304464529F48A778E03D03E4D34BCD5F9B6F0CFBF3CD238C642F7FB901000000000000000000000000000000000000000000000000000000000000000065000000000000000000000000000000000000000000000000000000000000000D000000000000000000000000B49C4E680174E331CB0A7FF3AB58AFC9738D5F8B0000000000000000000000000000000000000000000000000031B5493BD6E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061C9F36800000000000000000000000000000000000000000000000000000005FC0690080000000000000000000000000000000000000000000000000000000145F680B000F89B94B69C8CBCD90A39D8D3D3CCF0A3E968511C3856A0F863A0DDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EFA0000000000000000000000000B49C4E680174E331CB0A7FF3AB58AFC9738D5F8BA0000000000000000000000000D22363E3762CA7339569F3D33EADE20127D5F98CA00000000000000000000000000000000000000000000000000031BCED02DB0000F8B994D22363E3762CA7339569F3D33EADE20127D5F98CE1A06939F93E3F21CF1362EB17155B740277DE5687DAE9A83A85909FD71DA95944E7B8800000000000000000000000000000000000000000000000000000000000000065000000000000000000000000000000000000000000000000000000000000000D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012CFD07A485D96BB16F8589481E792E5A9003CC1C8BF5569A00F34B65D75B017E1A0DF21C415B78ED2552CC9971249E32A053ABCE6087A0AE0FBF3F78DB5174A3493A00000000000000000000000000000000000000000000000000029D9E10E183880F8D9944D73ADB72BC3DD368966EDD0F0B2148401A178E2E1A0B0C632F55F1E1B3B2C3D82F41EE4716BB4C00F0F5D84CDAFC141581BB8757A4FB8A0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000022000100000000000000000000000000000000000000000000000000000000000320C8000000000000000000000000000000000000000000000000000000000000F8D994A0CC33DD6F4819D473226257792AFE230EC3C67FE1A04E41EE13E03CD5E0446487B524FDC48AF6ACF26C074DACDBDFB6B574B42C8146B8A0000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000014000000000000000000000000701A95707A0290AC8B90B3719E8EE5B2103608830000000000000000000000000000000000000000000000000007500A2C99B320F902DA944D73ADB72BC3DD368966EDD0F0B2148401A178E2E1A0E9BDED5F24A4168E4F3BF44E00298C993B22376AAD8C58C7DDA9718A54CBEA82B902A0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002540000000000000DFD006F701A95707A0290AC8B90B3719E8EE5B2103608830065296F55F8FB28E498B858D0BCDA06D955B2CB3F970000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000D000000000000000000000000000000000000000000000000000000000000000D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012CFD07A485D96BB160000000000000000000000000000000000000000000000000031B5493BD6E00000000000000000000000000000000000000000000000000000000061C9F36800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000145F680B000000000000000000000000000000000000000000000000000000005FC069008000000000000000000000000000000000000000000000000000031BBA70C5A500000000000000000000000000000000000000000000000000000000000000001C000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000014E42E316000B1AC5F9FB9536BB6987E916879E9CB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F87994701A95707A0290AC8B90B3719E8EE5B210360883E1A08D3EE0DF6A4B7E82A7F20A763F1C6826E6176323E655AF64F32318827D2112D4B84000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000DFD0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001, _remoteAddressSize=20 ) => ( packet=[{name:srcChainId, type:uint16, order:1, indexed:false, value:111, valueString:111}, {name:dstChainId, type:uint16, order:2, indexed:false, value:101, valueString:101}, {name:nonce, type:uint64, order:3, indexed:false, value:3581, valueString:3581}, {name:dstAddress, type:address, order:4, indexed:false, value:0x296F55F8Fb28E498B858d0BcDA06D955B2Cb3f97, valueString:0x296F55F8Fb28E498B858d0BcDA06D955B2Cb3f97}, {name:srcAddress, type:bytes, order:5, indexed:false, value:0x701A95707A0290AC8B90B3719E8EE5B210360883, valueString:0x701A95707A0290AC8B90B3719E8EE5B210360883}, {name:ulnAddress, type:bytes32, order:6, indexed:false, value:0000000000000000000000004D73ADB72BC3DD368966EDD0F0B2148401A178E2, valueString:0000000000000000000000004D73ADB72BC3DD368966EDD0F0B2148401A178E2}, {name:payload, type:bytes, order:7, indexed:false, value:0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000D000000000000000000000000000000000000000000000000000000000000000D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012CFD07A485D96BB160000000000000000000000000000000000000000000000000031B5493BD6E00000000000000000000000000000000000000000000000000000000061C9F36800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000145F680B000000000000000000000000000000000000000000000000000000005FC069008000000000000000000000000000000000000000000000000000031BBA70C5A500000000000000000000000000000000000000000000000000000000000000001C000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000014E42E316000B1AC5F9FB9536BB6987E916879E9CB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000D000000000000000000000000000000000000000000000000000000000000000D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012CFD07A485D96BB160000000000000000000000000000000000000000000000000031B5493BD6E00000000000000000000000000000000000000000000000000000000061C9F36800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000145F680B000000000000000000000000000000000000000000000000000000005FC069008000000000000000000000000000000000000000000000000000031BBA70C5A500000000000000000000000000000000000000000000000000000000000000001C000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000014E42E316000B1AC5F9FB9536BB6987E916879E9CB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000}] ) Endpoint.receivePayload( _srcChainId=111, _srcAddress=0x701A95707A0290AC8B90B3719E8EE5B210360883296F55F8FB28E498B858D0BCDA06D955B2CB3F97, _dstAddress=0x296F55F8Fb28E498B858d0BcDA06D955B2Cb3f97, _nonce=3581, _gasLimit=1205000, _payload=0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000D000000000000000000000000000000000000000000000000000000000000000D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012CFD07A485D96BB160000000000000000000000000000000000000000000000000031B5493BD6E00000000000000000000000000000000000000000000000000000000061C9F36800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000145F680B000000000000000000000000000000000000000000000000000000005FC069008000000000000000000000000000000000000000000000000000031BBA70C5A500000000000000000000000000000000000000000000000000000000000000001C000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000014E42E316000B1AC5F9FB9536BB6987E916879E9CB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 )Bridge.lzReceive( _srcChainId=111, _srcAddress=0x701A95707A0290AC8B90B3719E8EE5B210360883296F55F8FB28E498B858D0BCDA06D955B2CB3F97, _nonce=3581, _payload=0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000D000000000000000000000000000000000000000000000000000000000000000D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012CFD07A485D96BB160000000000000000000000000000000000000000000000000031B5493BD6E00000000000000000000000000000000000000000000000000000000061C9F36800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000145F680B000000000000000000000000000000000000000000000000000000005FC069008000000000000000000000000000000000000000000000000000031BBA70C5A500000000000000000000000000000000000000000000000000000000000000001C000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000014E42E316000B1AC5F9FB9536BB6987E916879E9CB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 )Stargate Finance: Router.a18fa804( )-
Stargate Finance : Factory.068bcd8d( ) -
Pool.creditChainPath( _dstChainId=111, _dstPoolId=13, _c=[{name:credits, type:uint256, order:1, indexed:false, value:0, valueString:0}, {name:idealBalance, type:uint256, order:2, indexed:false, value:347015996539005221654, valueString:347015996539005221654}] )
-
Stargate Finance: Router.2f925555( )-
Stargate Finance : Factory.068bcd8d( ) -
Pool.swapRemote( _srcChainId=111, _srcPoolId=13, _to=0xe42e316000B1Ac5F9fb9536bb6987E916879E9cb, _s=[{name:amount, type:uint256, order:1, indexed:false, value:13991600000000000, valueString:13991600000000000}, {name:eqFee, type:uint256, order:2, indexed:false, value:420000000000, valueString:420000000000}, {name:eqReward, type:uint256, order:3, indexed:false, value:0, valueString:0}, {name:lpFee, type:uint256, order:4, indexed:false, value:1400000000000, valueString:1400000000000}, {name:protocolFee, type:uint256, order:5, indexed:false, value:6580000000000, valueString:6580000000000}, {name:lkbRemove, type:uint256, order:6, indexed:false, value:13998600000000000, valueString:13998600000000000}] ) => ( amountLD=13991600000000000 )
-
-
File 1 of 7: OptimizedTransparentUpgradeableProxy
File 2 of 7: UltraLightNodeV2
File 3 of 7: Pool
File 4 of 7: StargateEthVault
File 5 of 7: MPTValidator01
File 6 of 7: Endpoint
File 7 of 7: Bridge
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal {
// solhint-disable-next-line no-inline-assembly
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
/**
* @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal virtual view returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _fallback() internal {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback () payable external {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive () payable external {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overriden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "./Proxy.sol";
import "../utils/Address.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*
* Upgradeability is only provided internally through {_upgradeTo}. For an externally upgradeable proxy see
* {TransparentUpgradeableProxy}.
*/
contract UpgradeableProxy is Proxy {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializating the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) payable {
assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
_setImplementation(_logic);
if(_data.length > 0) {
// solhint-disable-next-line avoid-low-level-calls
(bool success,) = _logic.delegatecall(_data);
require(success);
}
}
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation address.
*/
function _implementation() internal override view returns (address impl) {
bytes32 slot = _IMPLEMENTATION_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
impl := sload(slot)
}
}
/**
* @dev Upgrades the proxy to a new implementation.
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "UpgradeableProxy: new implementation is not a contract");
bytes32 slot = _IMPLEMENTATION_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(slot, newImplementation)
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../openzeppelin/proxy/UpgradeableProxy.sol";
/**
* @dev This contract implements a proxy that is upgradeable by an admin.
*
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
* clashing], which can potentially be used in an attack, this contract uses the
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
* things that go hand in hand:
*
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
* that call matches one of the admin functions exposed by the proxy itself.
* 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
* implementation. If the admin tries to call a function on the implementation it will fail with an error that says
* "admin cannot fallback to proxy target".
*
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
* the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
* to sudden errors when trying to call a function from the proxy implementation.
*
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
* you should think of the `ProxyAdmin` instance as the real administrative inerface of your proxy.
*/
contract OptimizedTransparentUpgradeableProxy is UpgradeableProxy {
address internal immutable _ADMIN;
/**
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
* optionally initialized with `_data` as explained in {UpgradeableProxy-constructor}.
*/
constructor(
address initialLogic,
address initialAdmin,
bytes memory _data
) payable UpgradeableProxy(initialLogic, _data) {
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
bytes32 slot = _ADMIN_SLOT;
_ADMIN = initialAdmin;
// still store it to work with EIP-1967
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(slot, initialAdmin)
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
*/
modifier ifAdmin() {
if (msg.sender == _admin()) {
_;
} else {
_fallback();
}
}
/**
* @dev Returns the current admin.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function admin() external ifAdmin returns (address) {
return _admin();
}
/**
* @dev Returns the current implementation.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function implementation() external ifAdmin returns (address) {
return _implementation();
}
/**
* @dev Upgrade the implementation of the proxy.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeTo(newImplementation);
}
/**
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
* proxied contract.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
*/
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
_upgradeTo(newImplementation);
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = newImplementation.delegatecall(data);
require(success);
}
/**
* @dev Returns the current admin.
*/
function _admin() internal view returns (address adm) {
return _ADMIN;
}
/**
* @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
*/
function _beforeFallback() internal virtual override {
require(msg.sender != _admin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
super._beforeFallback();
}
}
File 2 of 7: UltraLightNodeV2
{"Address.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize, which returns 0 for contracts in\n // construction, since the code is only stored at the end of the\n // constructor execution.\n\n uint256 size;\n // solhint-disable-next-line no-inline-assembly\n assembly { size := extcodesize(account) }\n return size \u003e 0;\n }\n\n /**\n * @dev Replacement for Solidity\u0027s `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-low-level-calls, avoid-call-value\n (bool success, ) = recipient.call{ value: amount }(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain`call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {\n require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = target.call{ value: value }(data);\n return _verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = target.staticcall(data);\n return _verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return _verifyCallResult(success, returndata, errorMessage);\n }\n\n function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n"},"Buffer.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\n// https://github.com/ensdomains/buffer\n\npragma solidity ^0.7.0;\n\n/**\n * @dev A library for working with mutable byte buffers in Solidity.\n *\n * Byte buffers are mutable and expandable, and provide a variety of primitives\n * for writing to them. At any time you can fetch a bytes object containing the\n * current contents of the buffer. The bytes object should not be stored between\n * operations, as it may change due to resizing of the buffer.\n */\nlibrary Buffer {\n /**\n * @dev Represents a mutable buffer. Buffers have a current value (buf) and\n * a capacity. The capacity may be longer than the current value, in\n * which case it can be extended without the need to allocate more memory.\n */\n struct buffer {\n bytes buf;\n uint capacity;\n }\n\n /**\n * @dev Initializes a buffer with an initial capacity.a co\n * @param buf The buffer to initialize.\n * @param capacity The number of bytes of space to allocate the buffer.\n * @return The buffer, for chaining.\n */\n function init(buffer memory buf, uint capacity) internal pure returns (buffer memory) {\n if (capacity % 32 != 0) {\n capacity += 32 - (capacity % 32);\n }\n // Allocate space for the buffer data\n buf.capacity = capacity;\n assembly {\n let ptr := mload(0x40)\n mstore(buf, ptr)\n mstore(ptr, 0)\n mstore(0x40, add(32, add(ptr, capacity)))\n }\n return buf;\n }\n\n\n /**\n * @dev Writes a byte string to a buffer. Resizes if doing so would exceed\n * the capacity of the buffer.\n * @param buf The buffer to append to.\n * @param off The start offset to write to.\n * @param rawData The data to append.\n * @param len The number of bytes to copy.\n * @return The original buffer, for chaining.\n */\n function writeRawBytes(\n buffer memory buf,\n uint off,\n bytes memory rawData,\n uint offData,\n uint len\n ) internal pure returns (buffer memory) {\n if (off + len \u003e buf.capacity) {\n resize(buf, max(buf.capacity, len + off) * 2);\n }\n\n uint dest;\n uint src;\n assembly {\n // Memory address of the buffer data\n let bufptr := mload(buf)\n // Length of existing buffer data\n let buflen := mload(bufptr)\n // Start address = buffer address + offset + sizeof(buffer length)\n dest := add(add(bufptr, 32), off)\n // Update buffer length if we\u0027re extending it\n if gt(add(len, off), buflen) {\n mstore(bufptr, add(len, off))\n }\n src := add(rawData, offData)\n }\n\n // Copy word-length chunks while possible\n for (; len \u003e= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n // Copy remaining bytes\n uint mask = 256**(32 - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n\n return buf;\n }\n\n /**\n * @dev Writes a byte string to a buffer. Resizes if doing so would exceed\n * the capacity of the buffer.\n * @param buf The buffer to append to.\n * @param off The start offset to write to.\n * @param data The data to append.\n * @param len The number of bytes to copy.\n * @return The original buffer, for chaining.\n */\n function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns (buffer memory) {\n require(len \u003c= data.length);\n\n if (off + len \u003e buf.capacity) {\n resize(buf, max(buf.capacity, len + off) * 2);\n }\n\n uint dest;\n uint src;\n assembly {\n // Memory address of the buffer data\n let bufptr := mload(buf)\n // Length of existing buffer data\n let buflen := mload(bufptr)\n // Start address = buffer address + offset + sizeof(buffer length)\n dest := add(add(bufptr, 32), off)\n // Update buffer length if we\u0027re extending it\n if gt(add(len, off), buflen) {\n mstore(bufptr, add(len, off))\n }\n src := add(data, 32)\n }\n\n // Copy word-length chunks while possible\n for (; len \u003e= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n // Copy remaining bytes\n uint mask = 256**(32 - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n\n return buf;\n }\n\n function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {\n return write(buf, buf.buf.length, data, data.length);\n }\n\n function resize(buffer memory buf, uint capacity) private pure {\n bytes memory oldbuf = buf.buf;\n init(buf, capacity);\n append(buf, oldbuf);\n }\n\n function max(uint a, uint b) private pure returns (uint) {\n if (a \u003e b) {\n return a;\n }\n return b;\n }\n}\n"},"Context.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity \u003e=0.6.0 \u003c0.8.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n"},"IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller\u0027s account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller\u0027s tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender\u0027s allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller\u0027s\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},"ILayerZeroEndpoint.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.5.0;\n\nimport \"./ILayerZeroUserApplicationConfig.sol\";\n\ninterface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {\n // @notice send a LayerZero message to the specified address at a LayerZero endpoint.\n // @param _dstChainId - the destination chain identifier\n // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains\n // @param _payload - a custom bytes payload to send to the destination contract\n // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address\n // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction\n // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination\n function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;\n\n // @notice used by the messaging library to publish verified payload\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source contract (as bytes) at the source chain\n // @param _dstAddress - the address on destination chain\n // @param _nonce - the unbound message ordering nonce\n // @param _gasLimit - the gas limit for external contract execution\n // @param _payload - verified payload to send to the destination contract\n function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;\n\n // @notice get the inboundNonce of a receiver from a source chain which could be EVM or non-EVM chain\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);\n\n // @notice get the outboundNonce from this source chain which, consequently, is always an EVM\n // @param _srcAddress - the source chain contract address\n function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);\n\n // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery\n // @param _dstChainId - the destination chain identifier\n // @param _userApplication - the user app address on this EVM chain\n // @param _payload - the custom message to send over LayerZero\n // @param _payInZRO - if false, user app pays the protocol fee in native token\n // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain\n function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);\n\n // @notice get this Endpoint\u0027s immutable source identifier\n function getChainId() external view returns (uint16);\n\n // @notice the interface to retry failed message on this Endpoint destination\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n // @param _payload - the payload to be retried\n function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;\n\n // @notice query if any STORED payload (message blocking) at the endpoint.\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);\n\n // @notice query if the _libraryAddress is valid for sending msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getSendLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the _libraryAddress is valid for receiving msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getReceiveLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the non-reentrancy guard for send() is on\n // @return true if the guard is on. false otherwise\n function isSendingPayload() external view returns (bool);\n\n // @notice query if the non-reentrancy guard for receive() is on\n // @return true if the guard is on. false otherwise\n function isReceivingPayload() external view returns (bool);\n\n // @notice get the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _userApplication - the contract address of the user application\n // @param _configType - type of configuration. every messaging library has its own convention.\n function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);\n\n // @notice get the send() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getSendVersion(address _userApplication) external view returns (uint16);\n\n // @notice get the lzReceive() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getReceiveVersion(address _userApplication) external view returns (uint16);\n}\n"},"ILayerZeroMessagingLibrary.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.7.0;\n\nimport \"./ILayerZeroUserApplicationConfig.sol\";\n\ninterface ILayerZeroMessagingLibrary {\n // send(), messages will be inflight.\n function send(address _userApplication, uint64 _lastNonce, uint16 _chainId, bytes calldata _destination, bytes calldata _payload, address payable refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;\n\n // estimate native fee at the send side\n function estimateFees(uint16 _chainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);\n\n //---------------------------------------------------------------------------\n // setConfig / getConfig are User Application (UA) functions to specify Oracle, Relayer, blockConfirmations, libraryVersion\n function setConfig(uint16 _chainId, address _userApplication, uint _configType, bytes calldata _config) external;\n\n function getConfig(uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);\n}\n"},"ILayerZeroMessagingLibraryV2.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.7.0;\n\nimport \"./ILayerZeroUserApplicationConfig.sol\";\nimport \"./ILayerZeroMessagingLibrary.sol\";\n\ninterface ILayerZeroMessagingLibraryV2 is ILayerZeroMessagingLibrary {\n function getOutboundNonce(uint16 _chainId, bytes calldata _path) external view returns (uint64);\n}\n"},"ILayerZeroOracleV2.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.7.0;\n\ninterface ILayerZeroOracleV2 {\n // @notice query price and assign jobs at the same time\n // @param _dstChainId - the destination endpoint identifier\n // @param _outboundProofType - the proof type identifier to specify proof to be relayed\n // @param _outboundBlockConfirmation - block confirmation delay before relaying blocks\n // @param _userApplication - the source sending contract address\n function assignJob(uint16 _dstChainId, uint16 _outboundProofType, uint64 _outboundBlockConfirmation, address _userApplication) external returns (uint price);\n\n // @notice query the oracle price for relaying block information to the destination chain\n // @param _dstChainId the destination endpoint identifier\n // @param _outboundProofType the proof type identifier to specify the data to be relayed\n // @param _outboundBlockConfirmation - block confirmation delay before relaying blocks\n // @param _userApplication - the source sending contract address\n function getFee(uint16 _dstChainId, uint16 _outboundProofType, uint64 _outboundBlockConfirmation, address _userApplication) external view returns (uint price);\n\n // @notice withdraw the accrued fee in ultra light node\n // @param _to - the fee receiver\n // @param _amount - the withdrawal amount\n function withdrawFee(address payable _to, uint _amount) external;\n}\n"},"ILayerZeroReceiver.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.5.0;\n\ninterface ILayerZeroReceiver {\n // @notice LayerZero endpoint will invoke this function to deliver the message on the destination\n // @param _srcChainId - the source endpoint identifier\n // @param _srcAddress - the source sending contract address from the source chain\n // @param _nonce - the ordered message nonce\n // @param _payload - the signed payload is the UA bytes has encoded to be sent\n function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;\n}\n"},"ILayerZeroRelayerV2.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.7.0;\n\ninterface ILayerZeroRelayerV2 {\n // @notice query price and assign jobs at the same time\n // @param _dstChainId - the destination endpoint identifier\n // @param _outboundProofType - the proof type identifier to specify proof to be relayed\n // @param _userApplication - the source sending contract address. relayers may apply price discrimination to user apps\n // @param _payloadSize - the length of the payload. it is an indicator of gas usage for relaying cross-chain messages\n // @param _adapterParams - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain\n function assignJob(uint16 _dstChainId, uint16 _outboundProofType, address _userApplication, uint _payloadSize, bytes calldata _adapterParams) external returns (uint price);\n\n // @notice query the relayer price for relaying the payload and its proof to the destination chain\n // @param _dstChainId - the destination endpoint identifier\n // @param _outboundProofType - the proof type identifier to specify proof to be relayed\n // @param _userApplication - the source sending contract address. relayers may apply price discrimination to user apps\n // @param _payloadSize - the length of the payload. it is an indicator of gas usage for relaying cross-chain messages\n // @param _adapterParams - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain\n function getFee(uint16 _dstChainId, uint16 _outboundProofType, address _userApplication, uint _payloadSize, bytes calldata _adapterParams) external view returns (uint price);\n\n // @notice withdraw the accrued fee in ultra light node\n // @param _to - the fee receiver\n // @param _amount - the withdrawal amount\n function withdrawFee(address payable _to, uint _amount) external;\n}\n"},"ILayerZeroTreasury.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.5.0;\n\ninterface ILayerZeroTreasury {\n function getFees(bool payInZro, uint relayerFee, uint oracleFee) external view returns (uint);\n}\n"},"ILayerZeroUltraLightNodeV2.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.7.0;\npragma abicoder v2;\n\ninterface ILayerZeroUltraLightNodeV2 {\n // Relayer functions\n function validateTransactionProof(uint16 _srcChainId, address _dstAddress, uint _gasLimit, bytes32 _lookupHash, bytes32 _blockData, bytes calldata _transactionProof) external;\n\n // an Oracle delivers the block data using updateHash()\n function updateHash(uint16 _srcChainId, bytes32 _lookupHash, uint _confirmations, bytes32 _blockData) external;\n\n // can only withdraw the receivable of the msg.sender\n function withdrawNative(address payable _to, uint _amount) external;\n\n function withdrawZRO(address _to, uint _amount) external;\n\n // view functions\n function getAppConfig(uint16 _remoteChainId, address _userApplicationAddress) external view returns (ApplicationConfiguration memory);\n\n function accruedNativeFee(address _address) external view returns (uint);\n\n struct ApplicationConfiguration {\n uint16 inboundProofLibraryVersion;\n uint64 inboundBlockConfirmations;\n address relayer;\n uint16 outboundProofType;\n uint64 outboundBlockConfirmations;\n address oracle;\n }\n\n event HashReceived(uint16 indexed srcChainId, address indexed oracle, bytes32 lookupHash, bytes32 blockData, uint confirmations);\n event RelayerParams(bytes adapterParams, uint16 outboundProofType);\n event Packet(bytes payload);\n event InvalidDst(uint16 indexed srcChainId, bytes srcAddress, address indexed dstAddress, uint64 nonce, bytes32 payloadHash);\n event PacketReceived(uint16 indexed srcChainId, bytes srcAddress, address indexed dstAddress, uint64 nonce, bytes32 payloadHash);\n event AppConfigUpdated(address indexed userApplication, uint indexed configType, bytes newConfig);\n event AddInboundProofLibraryForChain(uint16 indexed chainId, address lib);\n event EnableSupportedOutboundProof(uint16 indexed chainId, uint16 proofType);\n event SetChainAddressSize(uint16 indexed chainId, uint size);\n event SetDefaultConfigForChainId(uint16 indexed chainId, uint16 inboundProofLib, uint64 inboundBlockConfirm, address relayer, uint16 outboundProofType, uint64 outboundBlockConfirm, address oracle);\n event SetDefaultAdapterParamsForChainId(uint16 indexed chainId, uint16 indexed proofType, bytes adapterParams);\n event SetLayerZeroToken(address indexed tokenAddress);\n event SetRemoteUln(uint16 indexed chainId, bytes32 uln);\n event SetTreasury(address indexed treasuryAddress);\n event WithdrawZRO(address indexed msgSender, address indexed to, uint amount);\n event WithdrawNative(address indexed msgSender, address indexed to, uint amount);\n}\n"},"ILayerZeroUserApplicationConfig.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.5.0;\n\ninterface ILayerZeroUserApplicationConfig {\n // @notice set the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _configType - type of configuration. every messaging library has its own convention.\n // @param _config - configuration in the bytes. can encode arbitrary content.\n function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;\n\n // @notice set the send() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setSendVersion(uint16 _version) external;\n\n // @notice set the lzReceive() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setReceiveVersion(uint16 _version) external;\n\n // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload\n // @param _srcChainId - the chainId of the source chain\n // @param _srcAddress - the contract address of the source contract at the source chain\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;\n}\n"},"ILayerZeroValidationLibrary.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity \u003e=0.7.0;\npragma abicoder v2;\n\nimport \"./LayerZeroPacket.sol\";\n\ninterface ILayerZeroValidationLibrary {\n function validateProof(bytes32 blockData, bytes calldata _data, uint _remoteAddressSize) external returns (LayerZeroPacket.Packet memory packet);\n}\n"},"LayerZeroPacket.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.7.6;\n\nimport \"./Buffer.sol\";\nimport \"./SafeMath.sol\";\n\nlibrary LayerZeroPacket {\n using Buffer for Buffer.buffer;\n using SafeMath for uint;\n\n struct Packet {\n uint16 srcChainId;\n uint16 dstChainId;\n uint64 nonce;\n address dstAddress;\n bytes srcAddress;\n bytes32 ulnAddress;\n bytes payload;\n }\n\n function getPacket(\n bytes memory data,\n uint16 srcChain,\n uint sizeOfSrcAddress,\n bytes32 ulnAddress\n ) internal pure returns (LayerZeroPacket.Packet memory) {\n uint16 dstChainId;\n address dstAddress;\n uint size;\n uint64 nonce;\n\n // The log consists of the destination chain id and then a bytes payload\n // 0--------------------------------------------31\n // 0 | total bytes size\n // 32 | destination chain id\n // 64 | bytes offset\n // 96 | bytes array size\n // 128 | payload\n assembly {\n dstChainId := mload(add(data, 32))\n size := mload(add(data, 96)) /// size of the byte array\n nonce := mload(add(data, 104)) // offset to convert to uint64 128 is index -24\n dstAddress := mload(add(data, sub(add(128, sizeOfSrcAddress), 4))) // offset to convert to address 12 -8\n }\n\n Buffer.buffer memory srcAddressBuffer;\n srcAddressBuffer.init(sizeOfSrcAddress);\n srcAddressBuffer.writeRawBytes(0, data, 136, sizeOfSrcAddress); // 128 + 8\n\n uint payloadSize = size.sub(28).sub(sizeOfSrcAddress);\n Buffer.buffer memory payloadBuffer;\n payloadBuffer.init(payloadSize);\n payloadBuffer.writeRawBytes(0, data, sizeOfSrcAddress.add(156), payloadSize); // 148 + 8\n return LayerZeroPacket.Packet(srcChain, dstChainId, nonce, dstAddress, srcAddressBuffer.buf, ulnAddress, payloadBuffer.buf);\n }\n\n function getPacketV2(\n bytes memory data,\n uint sizeOfSrcAddress,\n bytes32 ulnAddress\n ) internal pure returns (LayerZeroPacket.Packet memory) {\n // packet def: abi.encodePacked(nonce, srcChain, srcAddress, dstChain, dstAddress, payload);\n // data def: abi.encode(packet) = offset(32) + length(32) + packet\n // if from EVM\n // 0 - 31 0 - 31 | total bytes size\n // 32 - 63 32 - 63 | location\n // 64 - 95 64 - 95 | size of the packet\n // 96 - 103 96 - 103 | nonce\n // 104 - 105 104 - 105 | srcChainId\n // 106 - P 106 - 125 | srcAddress, where P = 106 + sizeOfSrcAddress - 1,\n // P+1 - P+2 126 - 127 | dstChainId\n // P+3 - P+22 128 - 147 | dstAddress\n // P+23 - END 148 - END | payload\n\n // decode the packet\n uint256 realSize;\n uint64 nonce;\n uint16 srcChain;\n uint16 dstChain;\n address dstAddress;\n assembly {\n realSize := mload(add(data, 64))\n nonce := mload(add(data, 72)) // 104 - 32\n srcChain := mload(add(data, 74)) // 106 - 32\n dstChain := mload(add(data, add(76, sizeOfSrcAddress))) // P + 3 - 32 = 105 + size + 3 - 32 = 76 + size\n dstAddress := mload(add(data, add(96, sizeOfSrcAddress))) // P + 23 - 32 = 105 + size + 23 - 32 = 96 + size\n }\n\n require(srcChain != 0, \"LayerZeroPacket: invalid packet\");\n\n Buffer.buffer memory srcAddressBuffer;\n srcAddressBuffer.init(sizeOfSrcAddress);\n srcAddressBuffer.writeRawBytes(0, data, 106, sizeOfSrcAddress);\n\n uint nonPayloadSize = sizeOfSrcAddress.add(32);// 2 + 2 + 8 + 20, 32 + 20 = 52 if sizeOfSrcAddress == 20\n uint payloadSize = realSize.sub(nonPayloadSize);\n Buffer.buffer memory payloadBuffer;\n payloadBuffer.init(payloadSize);\n payloadBuffer.writeRawBytes(0, data, nonPayloadSize.add(96), payloadSize);\n\n return LayerZeroPacket.Packet(srcChain, dstChain, nonce, dstAddress, srcAddressBuffer.buf, ulnAddress, payloadBuffer.buf);\n }\n\n function getPacketV3(\n bytes memory data,\n uint sizeOfSrcAddress,\n bytes32 ulnAddress\n ) internal pure returns (LayerZeroPacket.Packet memory) {\n // data def: abi.encodePacked(nonce, srcChain, srcAddress, dstChain, dstAddress, payload);\n // if from EVM\n // 0 - 31 0 - 31 | total bytes size\n // 32 - 39 32 - 39 | nonce\n // 40 - 41 40 - 41 | srcChainId\n // 42 - P 42 - 61 | srcAddress, where P = 41 + sizeOfSrcAddress,\n // P+1 - P+2 62 - 63 | dstChainId\n // P+3 - P+22 64 - 83 | dstAddress\n // P+23 - END 84 - END | payload\n\n // decode the packet\n uint256 realSize = data.length;\n uint nonPayloadSize = sizeOfSrcAddress.add(32);// 2 + 2 + 8 + 20, 32 + 20 = 52 if sizeOfSrcAddress == 20\n require(realSize \u003e= nonPayloadSize, \"LayerZeroPacket: invalid packet\");\n uint payloadSize = realSize - nonPayloadSize;\n\n uint64 nonce;\n uint16 srcChain;\n uint16 dstChain;\n address dstAddress;\n assembly {\n nonce := mload(add(data, 8)) // 40 - 32\n srcChain := mload(add(data, 10)) // 42 - 32\n dstChain := mload(add(data, add(12, sizeOfSrcAddress))) // P + 3 - 32 = 41 + size + 3 - 32 = 12 + size\n dstAddress := mload(add(data, add(32, sizeOfSrcAddress))) // P + 23 - 32 = 41 + size + 23 - 32 = 32 + size\n }\n\n require(srcChain != 0, \"LayerZeroPacket: invalid packet\");\n\n Buffer.buffer memory srcAddressBuffer;\n srcAddressBuffer.init(sizeOfSrcAddress);\n srcAddressBuffer.writeRawBytes(0, data, 42, sizeOfSrcAddress);\n\n Buffer.buffer memory payloadBuffer;\n if (payloadSize \u003e 0) {\n payloadBuffer.init(payloadSize);\n payloadBuffer.writeRawBytes(0, data, nonPayloadSize.add(32), payloadSize);\n }\n\n return LayerZeroPacket.Packet(srcChain, dstChain, nonce, dstAddress, srcAddressBuffer.buf, ulnAddress, payloadBuffer.buf);\n }\n}\n"},"NonceContract.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.7.6;\n\nimport \"./ILayerZeroEndpoint.sol\";\n\ncontract NonceContract {\n ILayerZeroEndpoint public immutable endpoint;\n // outboundNonce = [dstChainId][remoteAddress + localAddress]\n mapping(uint16 =\u003e mapping(bytes =\u003e uint64)) public outboundNonce;\n\n constructor(address _endpoint) {\n endpoint = ILayerZeroEndpoint(_endpoint);\n }\n\n function increment(uint16 _chainId, address _ua, bytes calldata _path) external returns (uint64) {\n require(endpoint.getSendLibraryAddress(_ua) == msg.sender, \"NonceContract: msg.sender is not valid sendlibrary\");\n return ++outboundNonce[_chainId][_path];\n }\n}\n"},"Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\nimport \"./Context.sol\";\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor () {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n emit OwnershipTransferred(_owner, address(0));\n _owner = address(0);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n"},"ReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot\u0027s contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler\u0027s defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction\u0027s gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor () {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n"},"SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\nimport \"./IERC20.sol\";\nimport \"./SafeMath.sol\";\nimport \"./Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(IERC20 token, address spender, uint256 value) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // \u0027safeIncreaseAllowance\u0027 and \u0027safeDecreaseAllowance\u0027\n // solhint-disable-next-line max-line-length\n require((value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 newAllowance = token.allowance(address(this), spender).sub(value, \"SafeERC20: decreased allowance below zero\");\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity\u0027s return data size checking mechanism, since\n // we\u0027re implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length \u003e 0) { // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n"},"SafeMath.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Wrappers over Solidity\u0027s arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it\u0027s recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n uint256 c = a + b;\n if (c \u003c a) return (false, 0);\n return (true, c);\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n if (b \u003e a) return (false, 0);\n return (true, a - b);\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n // Gas optimization: this is cheaper than requiring \u0027a\u0027 not being zero, but the\n // benefit is lost if \u0027b\u0027 is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity\u0027s `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c \u003e= a, \"SafeMath: addition overflow\");\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity\u0027s `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b \u003c= a, \"SafeMath: subtraction overflow\");\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity\u0027s `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n if (a == 0) return 0;\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity\u0027s `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b \u003e 0, \"SafeMath: division by zero\");\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity\u0027s `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b \u003e 0, \"SafeMath: modulo by zero\");\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity\u0027s `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b \u003c= a, errorMessage);\n return a - b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryDiv}.\n *\n * Counterpart to Solidity\u0027s `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b \u003e 0, errorMessage);\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity\u0027s `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b \u003e 0, errorMessage);\n return a % b;\n }\n}\n"},"UltraLightNodeV2.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.7.6;\npragma abicoder v2;\n\nimport \"./Ownable.sol\";\nimport \"./SafeMath.sol\";\nimport \"./ReentrancyGuard.sol\";\nimport \"./IERC20.sol\";\nimport \"./SafeERC20.sol\";\n\nimport \"./ILayerZeroValidationLibrary.sol\";\nimport \"./ILayerZeroReceiver.sol\";\nimport \"./ILayerZeroTreasury.sol\";\nimport \"./ILayerZeroEndpoint.sol\";\n// v2\nimport \"./ILayerZeroMessagingLibraryV2.sol\";\nimport \"./ILayerZeroOracleV2.sol\";\nimport \"./ILayerZeroUltraLightNodeV2.sol\";\nimport \"./ILayerZeroRelayerV2.sol\";\nimport \"./NonceContract.sol\";\n\ncontract UltraLightNodeV2 is ILayerZeroMessagingLibraryV2, ILayerZeroUltraLightNodeV2, ReentrancyGuard, Ownable {\n using SafeERC20 for IERC20;\n using SafeMath for uint;\n\n // Application config\n uint public constant CONFIG_TYPE_INBOUND_PROOF_LIBRARY_VERSION = 1;\n uint public constant CONFIG_TYPE_INBOUND_BLOCK_CONFIRMATIONS = 2;\n uint public constant CONFIG_TYPE_RELAYER = 3;\n uint public constant CONFIG_TYPE_OUTBOUND_PROOF_TYPE = 4;\n uint public constant CONFIG_TYPE_OUTBOUND_BLOCK_CONFIRMATIONS = 5;\n uint public constant CONFIG_TYPE_ORACLE = 6;\n\n // Token and Contracts\n IERC20 public layerZeroToken;\n ILayerZeroTreasury public treasuryContract;\n\n mapping(address =\u003e uint) public nativeFees;\n uint public treasuryZROFees;\n\n // User Application\n mapping(address =\u003e mapping(uint16 =\u003e ApplicationConfiguration)) public appConfig; // app address =\u003e chainId =\u003e config\n mapping(uint16 =\u003e ApplicationConfiguration) public defaultAppConfig; // default UA settings if no version specified\n mapping(uint16 =\u003e mapping(uint16 =\u003e bytes)) public defaultAdapterParams;\n\n // Validation\n mapping(uint16 =\u003e mapping(uint16 =\u003e address)) public inboundProofLibrary; // chainId =\u003e library Id =\u003e inboundProofLibrary contract\n mapping(uint16 =\u003e uint16) public maxInboundProofLibrary; // chainId =\u003e inboundProofLibrary\n mapping(uint16 =\u003e mapping(uint16 =\u003e bool)) public supportedOutboundProof; // chainId =\u003e outboundProofType =\u003e enabled\n mapping(uint16 =\u003e uint) public chainAddressSizeMap;\n mapping(address =\u003e mapping(uint16 =\u003e mapping(bytes32 =\u003e mapping(bytes32 =\u003e uint)))) public hashLookup; //[oracle][srcChainId][blockhash][datahash] -\u003e confirmation\n mapping(uint16 =\u003e bytes32) public ulnLookup; // remote ulns\n\n ILayerZeroEndpoint public immutable endpoint;\n uint16 public immutable localChainId;\n NonceContract public immutable nonceContract;\n\n constructor(address _endpoint, address _nonceContract, uint16 _localChainId) {\n require(_endpoint != address(0x0), \"LayerZero: endpoint cannot be zero address\");\n require(_nonceContract != address(0x0), \"LayerZero: nonceContract cannot be zero address\");\n ILayerZeroEndpoint lzEndpoint = ILayerZeroEndpoint(_endpoint);\n localChainId = _localChainId;\n endpoint = lzEndpoint;\n nonceContract = NonceContract(_nonceContract);\n }\n\n // only the endpoint can call SEND() and setConfig()\n modifier onlyEndpoint() {\n require(address(endpoint) == msg.sender, \"LayerZero: only endpoint\");\n _;\n }\n\n //----------------------------------------------------------------------------------\n // PROTOCOL\n function validateTransactionProof(uint16 _srcChainId, address _dstAddress, uint _gasLimit, bytes32 _lookupHash, bytes32 _blockData, bytes calldata _transactionProof) external override {\n // retrieve UA\u0027s configuration using the _dstAddress from arguments.\n ApplicationConfiguration memory uaConfig = _getAppConfig(_srcChainId, _dstAddress);\n\n // assert that the caller == UA\u0027s relayer\n require(uaConfig.relayer == msg.sender, \"LayerZero: invalid relayer\");\n\n LayerZeroPacket.Packet memory _packet;\n uint remoteAddressSize = chainAddressSizeMap[_srcChainId];\n require(remoteAddressSize != 0, \"LayerZero: incorrect remote address size\");\n {\n // assert that the data submitted by UA\u0027s oracle have no fewer confirmations than UA\u0027s configuration\n uint storedConfirmations = hashLookup[uaConfig.oracle][_srcChainId][_lookupHash][_blockData];\n require(storedConfirmations \u003e 0 \u0026\u0026 storedConfirmations \u003e= uaConfig.inboundBlockConfirmations, \"LayerZero: not enough block confirmations\");\n\n // decode\n address inboundProofLib = inboundProofLibrary[_srcChainId][uaConfig.inboundProofLibraryVersion];\n _packet = ILayerZeroValidationLibrary(inboundProofLib).validateProof(_blockData, _transactionProof, remoteAddressSize);\n }\n\n // packet content assertion\n require(ulnLookup[_srcChainId] == _packet.ulnAddress \u0026\u0026 _packet.ulnAddress != bytes32(0), \"LayerZero: invalid _packet.ulnAddress\");\n require(_packet.srcChainId == _srcChainId, \"LayerZero: invalid srcChain Id\");\n // failsafe because the remoteAddress size being passed into validateProof trims the address this should not hit\n require(_packet.srcAddress.length == remoteAddressSize, \"LayerZero: invalid srcAddress size\");\n require(_packet.dstChainId == localChainId, \"LayerZero: invalid dstChain Id\");\n require(_packet.dstAddress == _dstAddress, \"LayerZero: invalid dstAddress\");\n\n // if the dst is not a contract, then emit and return early. This will break inbound nonces, but this particular\n // path is already broken and wont ever be able to deliver anyways\n if (!_isContract(_dstAddress)) {\n emit InvalidDst(_packet.srcChainId, _packet.srcAddress, _packet.dstAddress, _packet.nonce, keccak256(_packet.payload));\n return;\n }\n\n bytes memory pathData = abi.encodePacked(_packet.srcAddress, _packet.dstAddress);\n emit PacketReceived(_packet.srcChainId, _packet.srcAddress, _packet.dstAddress, _packet.nonce, keccak256(_packet.payload));\n endpoint.receivePayload(_srcChainId, pathData, _dstAddress, _packet.nonce, _gasLimit, _packet.payload);\n }\n\n function send(address _ua, uint64, uint16 _dstChainId, bytes calldata _path, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable override onlyEndpoint {\n address ua = _ua;\n uint16 dstChainId = _dstChainId;\n require(ulnLookup[dstChainId] != bytes32(0), \"LayerZero: dstChainId does not exist\");\n\n bytes memory dstAddress;\n uint64 nonce;\n // code block for solving \u0027Stack Too Deep\u0027\n {\n uint chainAddressSize = chainAddressSizeMap[dstChainId];\n // path = remoteAddress + localAddress\n require(chainAddressSize != 0 \u0026\u0026 _path.length == 20 + chainAddressSize, \"LayerZero: incorrect remote address size\");\n address srcInPath;\n bytes memory path = _path; // copy to memory\n assembly {\n srcInPath := mload(add(add(path, 20), chainAddressSize)) // chainAddressSize + 20\n }\n require(ua == srcInPath, \"LayerZero: wrong path data\");\n dstAddress = _path[0:chainAddressSize];\n nonce = nonceContract.increment(dstChainId, ua, path);\n }\n\n bytes memory payload = _payload;\n ApplicationConfiguration memory uaConfig = _getAppConfig(dstChainId, ua);\n\n // compute all the fees\n uint relayerFee = _handleRelayer(dstChainId, uaConfig, ua, payload.length, _adapterParams);\n uint oracleFee = _handleOracle(dstChainId, uaConfig, ua);\n uint nativeProtocolFee = _handleProtocolFee(relayerFee, oracleFee, ua, _zroPaymentAddress);\n\n // total native fee, does not include ZRO protocol fee\n uint totalNativeFee = relayerFee.add(oracleFee).add(nativeProtocolFee);\n\n // assert the user has attached enough native token for this address\n require(totalNativeFee \u003c= msg.value, \"LayerZero: not enough native for fees\");\n // refund if they send too much\n uint amount = msg.value.sub(totalNativeFee);\n if (amount \u003e 0) {\n (bool success, ) = _refundAddress.call{value: amount}(\"\");\n require(success, \"LayerZero: failed to refund\");\n }\n\n // emit the data packet\n bytes memory encodedPayload = abi.encodePacked(nonce, localChainId, ua, dstChainId, dstAddress, payload);\n emit Packet(encodedPayload);\n }\n\n function _handleRelayer(uint16 _dstChainId, ApplicationConfiguration memory _uaConfig, address _ua, uint _payloadSize, bytes memory _adapterParams) internal returns (uint relayerFee) {\n if (_adapterParams.length == 0) {\n _adapterParams = defaultAdapterParams[_dstChainId][_uaConfig.outboundProofType];\n }\n address relayerAddress = _uaConfig.relayer;\n ILayerZeroRelayerV2 relayer = ILayerZeroRelayerV2(relayerAddress);\n relayerFee = relayer.assignJob(_dstChainId, _uaConfig.outboundProofType, _ua, _payloadSize, _adapterParams);\n\n _creditNativeFee(relayerAddress, relayerFee);\n\n // emit the param events\n emit RelayerParams(_adapterParams, _uaConfig.outboundProofType);\n }\n\n function _handleOracle(uint16 _dstChainId, ApplicationConfiguration memory _uaConfig, address _ua) internal returns (uint oracleFee) {\n address oracleAddress = _uaConfig.oracle;\n oracleFee = ILayerZeroOracleV2(oracleAddress).assignJob(_dstChainId, _uaConfig.outboundProofType, _uaConfig.outboundBlockConfirmations, _ua);\n\n _creditNativeFee(oracleAddress, oracleFee);\n }\n\n function _handleProtocolFee(uint _relayerFee, uint _oracleFee, address _ua, address _zroPaymentAddress) internal returns (uint protocolNativeFee) {\n // if no ZRO token or not specifying a payment address, pay in native token\n bool payInNative = _zroPaymentAddress == address(0x0) || address(layerZeroToken) == address(0x0);\n uint protocolFee = treasuryContract.getFees(!payInNative, _relayerFee, _oracleFee);\n\n if (protocolFee \u003e 0) {\n if (payInNative) {\n address treasuryAddress = address(treasuryContract);\n _creditNativeFee(treasuryAddress, protocolFee);\n protocolNativeFee = protocolFee;\n } else {\n // zro payment address must equal the ua or the tx.origin otherwise the transaction reverts\n require(_zroPaymentAddress == _ua || _zroPaymentAddress == tx.origin, \"LayerZero: must be paid by sender or origin\");\n\n // transfer the LayerZero token to this contract from the payee\n layerZeroToken.safeTransferFrom(_zroPaymentAddress, address(this), protocolFee);\n\n treasuryZROFees = treasuryZROFees.add(protocolFee);\n }\n }\n }\n\n function _creditNativeFee(address _receiver, uint _amount) internal {\n nativeFees[_receiver] = nativeFees[_receiver].add(_amount);\n }\n\n // Can be called by any address to update a block header\n // can only upload new block data or the same block data with more confirmations\n function updateHash(uint16 _srcChainId, bytes32 _lookupHash, uint _confirmations, bytes32 _blockData) external override {\n uint storedConfirmations = hashLookup[msg.sender][_srcChainId][_lookupHash][_blockData];\n\n // if it has a record, requires a larger confirmation.\n require(storedConfirmations \u003c _confirmations, \"LayerZero: oracle data can only update if it has more confirmations\");\n\n // set the new information into storage\n hashLookup[msg.sender][_srcChainId][_lookupHash][_blockData] = _confirmations;\n\n emit HashReceived(_srcChainId, msg.sender, _lookupHash, _blockData, _confirmations);\n }\n\n //----------------------------------------------------------------------------------\n // Other Library Interfaces\n\n // default to DEFAULT setting if ZERO value\n function getAppConfig(uint16 _remoteChainId, address _ua) external view override returns (ApplicationConfiguration memory) {\n return _getAppConfig(_remoteChainId, _ua);\n }\n\n function _getAppConfig(uint16 _remoteChainId, address _ua) internal view returns (ApplicationConfiguration memory) {\n ApplicationConfiguration memory config = appConfig[_ua][_remoteChainId];\n ApplicationConfiguration storage defaultConfig = defaultAppConfig[_remoteChainId];\n\n if (config.inboundProofLibraryVersion == 0) {\n config.inboundProofLibraryVersion = defaultConfig.inboundProofLibraryVersion;\n }\n\n if (config.inboundBlockConfirmations == 0) {\n config.inboundBlockConfirmations = defaultConfig.inboundBlockConfirmations;\n }\n\n if (config.relayer == address(0x0)) {\n config.relayer = defaultConfig.relayer;\n }\n\n if (config.outboundProofType == 0) {\n config.outboundProofType = defaultConfig.outboundProofType;\n }\n\n if (config.outboundBlockConfirmations == 0) {\n config.outboundBlockConfirmations = defaultConfig.outboundBlockConfirmations;\n }\n\n if (config.oracle == address(0x0)) {\n config.oracle = defaultConfig.oracle;\n }\n\n return config;\n }\n\n function setConfig(uint16 _remoteChainId, address _ua, uint _configType, bytes calldata _config) external override onlyEndpoint {\n ApplicationConfiguration storage uaConfig = appConfig[_ua][_remoteChainId];\n if (_configType == CONFIG_TYPE_INBOUND_PROOF_LIBRARY_VERSION) {\n uint16 inboundProofLibraryVersion = abi.decode(_config, (uint16));\n require(inboundProofLibraryVersion \u003c= maxInboundProofLibrary[_remoteChainId], \"LayerZero: invalid inbound proof library version\");\n uaConfig.inboundProofLibraryVersion = inboundProofLibraryVersion;\n } else if (_configType == CONFIG_TYPE_INBOUND_BLOCK_CONFIRMATIONS) {\n uint64 blockConfirmations = abi.decode(_config, (uint64));\n uaConfig.inboundBlockConfirmations = blockConfirmations;\n } else if (_configType == CONFIG_TYPE_RELAYER) {\n address relayer = abi.decode(_config, (address));\n uaConfig.relayer = relayer;\n } else if (_configType == CONFIG_TYPE_OUTBOUND_PROOF_TYPE) {\n uint16 outboundProofType = abi.decode(_config, (uint16));\n require(supportedOutboundProof[_remoteChainId][outboundProofType] || outboundProofType == 0, \"LayerZero: invalid outbound proof type\");\n uaConfig.outboundProofType = outboundProofType;\n } else if (_configType == CONFIG_TYPE_OUTBOUND_BLOCK_CONFIRMATIONS) {\n uint64 blockConfirmations = abi.decode(_config, (uint64));\n uaConfig.outboundBlockConfirmations = blockConfirmations;\n } else if (_configType == CONFIG_TYPE_ORACLE) {\n address oracle = abi.decode(_config, (address));\n uaConfig.oracle = oracle;\n } else {\n revert(\"LayerZero: Invalid config type\");\n }\n\n emit AppConfigUpdated(_ua, _configType, _config);\n }\n\n function getConfig(uint16 _remoteChainId, address _ua, uint _configType) external view override returns (bytes memory) {\n ApplicationConfiguration storage uaConfig = appConfig[_ua][_remoteChainId];\n\n if (_configType == CONFIG_TYPE_INBOUND_PROOF_LIBRARY_VERSION) {\n if (uaConfig.inboundProofLibraryVersion == 0) {\n return abi.encode(defaultAppConfig[_remoteChainId].inboundProofLibraryVersion);\n }\n return abi.encode(uaConfig.inboundProofLibraryVersion);\n } else if (_configType == CONFIG_TYPE_INBOUND_BLOCK_CONFIRMATIONS) {\n if (uaConfig.inboundBlockConfirmations == 0) {\n return abi.encode(defaultAppConfig[_remoteChainId].inboundBlockConfirmations);\n }\n return abi.encode(uaConfig.inboundBlockConfirmations);\n } else if (_configType == CONFIG_TYPE_RELAYER) {\n if (uaConfig.relayer == address(0x0)) {\n return abi.encode(defaultAppConfig[_remoteChainId].relayer);\n }\n return abi.encode(uaConfig.relayer);\n } else if (_configType == CONFIG_TYPE_OUTBOUND_PROOF_TYPE) {\n if (uaConfig.outboundProofType == 0) {\n return abi.encode(defaultAppConfig[_remoteChainId].outboundProofType);\n }\n return abi.encode(uaConfig.outboundProofType);\n } else if (_configType == CONFIG_TYPE_OUTBOUND_BLOCK_CONFIRMATIONS) {\n if (uaConfig.outboundBlockConfirmations == 0) {\n return abi.encode(defaultAppConfig[_remoteChainId].outboundBlockConfirmations);\n }\n return abi.encode(uaConfig.outboundBlockConfirmations);\n } else if (_configType == CONFIG_TYPE_ORACLE) {\n if (uaConfig.oracle == address(0x0)) {\n return abi.encode(defaultAppConfig[_remoteChainId].oracle);\n }\n return abi.encode(uaConfig.oracle);\n } else {\n revert(\"LayerZero: Invalid config type\");\n }\n }\n\n // returns the native fee the UA pays to cover fees\n function estimateFees(uint16 _dstChainId, address _ua, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParams) external view override returns (uint nativeFee, uint zroFee) {\n ApplicationConfiguration memory uaConfig = _getAppConfig(_dstChainId, _ua);\n\n // Relayer Fee\n bytes memory adapterParams;\n if (_adapterParams.length \u003e 0) {\n adapterParams = _adapterParams;\n } else {\n adapterParams = defaultAdapterParams[_dstChainId][uaConfig.outboundProofType];\n }\n uint relayerFee = ILayerZeroRelayerV2(uaConfig.relayer).getFee(_dstChainId, uaConfig.outboundProofType, _ua, _payload.length, adapterParams);\n\n // Oracle Fee\n address ua = _ua; // stack too deep\n uint oracleFee = ILayerZeroOracleV2(uaConfig.oracle).getFee(_dstChainId, uaConfig.outboundProofType, uaConfig.outboundBlockConfirmations, ua);\n\n // LayerZero Fee\n uint protocolFee = treasuryContract.getFees(_payInZRO, relayerFee, oracleFee);\n _payInZRO ? zroFee = protocolFee : nativeFee = protocolFee;\n\n // return the sum of fees\n nativeFee = nativeFee.add(relayerFee).add(oracleFee);\n }\n\n //---------------------------------------------------------------------------\n // Claim Fees\n\n // universal withdraw ZRO token function\n function withdrawZRO(address _to, uint _amount) external override nonReentrant {\n require(msg.sender == address(treasuryContract), \"LayerZero: only treasury\");\n treasuryZROFees = treasuryZROFees.sub(_amount);\n layerZeroToken.safeTransfer(_to, _amount);\n emit WithdrawZRO(msg.sender, _to, _amount);\n }\n\n // universal withdraw native token function.\n // the source contract should perform all the authentication control\n function withdrawNative(address payable _to, uint _amount) external override nonReentrant {\n require(_to != address(0x0), \"LayerZero: _to cannot be zero address\");\n nativeFees[msg.sender] = nativeFees[msg.sender].sub(_amount);\n\n (bool success, ) = _to.call{value: _amount}(\"\");\n require(success, \"LayerZero: withdraw failed\");\n emit WithdrawNative(msg.sender, _to, _amount);\n }\n\n //---------------------------------------------------------------------------\n // Owner calls, configuration only.\n function setLayerZeroToken(address _layerZeroToken) external onlyOwner {\n require(_layerZeroToken != address(0x0), \"LayerZero: _layerZeroToken cannot be zero address\");\n layerZeroToken = IERC20(_layerZeroToken);\n emit SetLayerZeroToken(_layerZeroToken);\n }\n\n function setTreasury(address _treasury) external onlyOwner {\n require(_treasury != address(0x0), \"LayerZero: treasury cannot be zero address\");\n treasuryContract = ILayerZeroTreasury(_treasury);\n emit SetTreasury(_treasury);\n }\n\n function addInboundProofLibraryForChain(uint16 _chainId, address _library) external onlyOwner {\n require(_library != address(0x0), \"LayerZero: library cannot be zero address\");\n uint16 libId = maxInboundProofLibrary[_chainId];\n require(libId \u003c 65535, \"LayerZero: can not add new library\");\n maxInboundProofLibrary[_chainId] = ++libId;\n inboundProofLibrary[_chainId][libId] = _library;\n emit AddInboundProofLibraryForChain(_chainId, _library);\n }\n\n function enableSupportedOutboundProof(uint16 _chainId, uint16 _proofType) external onlyOwner {\n supportedOutboundProof[_chainId][_proofType] = true;\n emit EnableSupportedOutboundProof(_chainId, _proofType);\n }\n\n function setDefaultConfigForChainId(uint16 _chainId, uint16 _inboundProofLibraryVersion, uint64 _inboundBlockConfirmations, address _relayer, uint16 _outboundProofType, uint64 _outboundBlockConfirmations, address _oracle) external onlyOwner {\n require(_inboundProofLibraryVersion \u003c= maxInboundProofLibrary[_chainId] \u0026\u0026 _inboundProofLibraryVersion \u003e 0, \"LayerZero: invalid inbound proof library version\");\n require(_inboundBlockConfirmations \u003e 0, \"LayerZero: invalid inbound block confirmation\");\n require(_relayer != address(0x0), \"LayerZero: invalid relayer address\");\n require(supportedOutboundProof[_chainId][_outboundProofType], \"LayerZero: invalid outbound proof type\");\n require(_outboundBlockConfirmations \u003e 0, \"LayerZero: invalid outbound block confirmation\");\n require(_oracle != address(0x0), \"LayerZero: invalid oracle address\");\n defaultAppConfig[_chainId] = ApplicationConfiguration(_inboundProofLibraryVersion, _inboundBlockConfirmations, _relayer, _outboundProofType, _outboundBlockConfirmations, _oracle);\n emit SetDefaultConfigForChainId(_chainId, _inboundProofLibraryVersion, _inboundBlockConfirmations, _relayer, _outboundProofType, _outboundBlockConfirmations, _oracle);\n }\n\n function setDefaultAdapterParamsForChainId(uint16 _chainId, uint16 _proofType, bytes calldata _adapterParams) external onlyOwner {\n defaultAdapterParams[_chainId][_proofType] = _adapterParams;\n emit SetDefaultAdapterParamsForChainId(_chainId, _proofType, _adapterParams);\n }\n\n function setRemoteUln(uint16 _remoteChainId, bytes32 _remoteUln) external onlyOwner {\n require(ulnLookup[_remoteChainId] == bytes32(0), \"LayerZero: remote uln already set\");\n ulnLookup[_remoteChainId] = _remoteUln;\n emit SetRemoteUln(_remoteChainId, _remoteUln);\n }\n\n function setChainAddressSize(uint16 _chainId, uint _size) external onlyOwner {\n require(chainAddressSizeMap[_chainId] == 0, \"LayerZero: remote chain address size already set\");\n chainAddressSizeMap[_chainId] = _size;\n emit SetChainAddressSize(_chainId, _size);\n }\n\n //----------------------------------------------------------------------------------\n // view functions\n\n function accruedNativeFee(address _address) external view override returns (uint) {\n return nativeFees[_address];\n }\n\n function getOutboundNonce(uint16 _chainId, bytes calldata _path) external view override returns (uint64) {\n return nonceContract.outboundNonce(_chainId, _path);\n }\n\n function _isContract(address addr) internal view returns (bool) {\n uint size;\n assembly {\n size := extcodesize(addr)\n }\n return size != 0;\n }\n}\n"}}File 3 of 7: Pool
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
// imports
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./LPTokenERC20.sol";
import "./interfaces/IStargateFeeLibrary.sol";
// libraries
import "@openzeppelin/contracts/math/SafeMath.sol";
/// Pool contracts on other chains and managed by the Stargate protocol.
contract Pool is LPTokenERC20, ReentrancyGuard {
using SafeMath for uint256;
//---------------------------------------------------------------------------
// CONSTANTS
bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));
uint256 public constant BP_DENOMINATOR = 10000;
//---------------------------------------------------------------------------
// STRUCTS
struct ChainPath {
bool ready; // indicate if the counter chainPath has been created.
uint16 dstChainId;
uint256 dstPoolId;
uint256 weight;
uint256 balance;
uint256 lkb;
uint256 credits;
uint256 idealBalance;
}
struct SwapObj {
uint256 amount;
uint256 eqFee;
uint256 eqReward;
uint256 lpFee;
uint256 protocolFee;
uint256 lkbRemove;
}
struct CreditObj {
uint256 credits;
uint256 idealBalance;
}
//---------------------------------------------------------------------------
// VARIABLES
// chainPath
ChainPath[] public chainPaths; // list of connected chains with shared pools
mapping(uint16 => mapping(uint256 => uint256)) public chainPathIndexLookup; // lookup for chainPath by chainId => poolId =>index
// metadata
uint256 public immutable poolId; // shared id between chains to represent same pool
uint256 public sharedDecimals; // the shared decimals (lowest common decimals between chains)
uint256 public localDecimals; // the decimals for the token
uint256 public immutable convertRate; // the decimals for the token
address public immutable token; // the token for the pool
address public immutable router; // the token for the pool
bool public stopSwap; // flag to stop swapping in extreme cases
// Fee and Liquidity
uint256 public totalLiquidity; // the total amount of tokens added on this side of the chain (fees + deposits - withdrawals)
uint256 public totalWeight; // total weight for pool percentages
uint256 public mintFeeBP; // fee basis points for the mint/deposit
uint256 public protocolFeeBalance; // fee balance created from dao fee
uint256 public mintFeeBalance; // fee balance created from mint fee
uint256 public eqFeePool; // pool rewards in Shared Decimal format. indicate the total budget for reverse swap incentive
address public feeLibrary; // address for retrieving fee params for swaps
// Delta related
uint256 public deltaCredit; // credits accumulated from txn
bool public batched; // flag to indicate if we want batch processing.
bool public defaultSwapMode; // flag for the default mode for swap
bool public defaultLPMode; // flag for the default mode for lp
uint256 public swapDeltaBP; // basis points of poolCredits to activate Delta in swap
uint256 public lpDeltaBP; // basis points of poolCredits to activate Delta in liquidity events
//---------------------------------------------------------------------------
// EVENTS
event Mint(address to, uint256 amountLP, uint256 amountSD, uint256 mintFeeAmountSD);
event Burn(address from, uint256 amountLP, uint256 amountSD);
event RedeemLocalCallback(address _to, uint256 _amountSD, uint256 _amountToMintSD);
event Swap(
uint16 chainId,
uint256 dstPoolId,
address from,
uint256 amountSD,
uint256 eqReward,
uint256 eqFee,
uint256 protocolFee,
uint256 lpFee
);
event SendCredits(uint16 dstChainId, uint256 dstPoolId, uint256 credits, uint256 idealBalance);
event RedeemRemote(uint16 chainId, uint256 dstPoolId, address from, uint256 amountLP, uint256 amountSD);
event RedeemLocal(address from, uint256 amountLP, uint256 amountSD, uint16 chainId, uint256 dstPoolId, bytes to);
event InstantRedeemLocal(address from, uint256 amountLP, uint256 amountSD, address to);
event CreditChainPath(uint16 chainId, uint256 srcPoolId, uint256 amountSD, uint256 idealBalance);
event SwapRemote(address to, uint256 amountSD, uint256 protocolFee, uint256 dstFee);
event WithdrawRemote(uint16 srcChainId, uint256 srcPoolId, uint256 swapAmount, uint256 mintAmount);
event ChainPathUpdate(uint16 dstChainId, uint256 dstPoolId, uint256 weight);
event FeesUpdated(uint256 mintFeeBP);
event FeeLibraryUpdated(address feeLibraryAddr);
event StopSwapUpdated(bool swapStop);
event WithdrawProtocolFeeBalance(address to, uint256 amountSD);
event WithdrawMintFeeBalance(address to, uint256 amountSD);
event DeltaParamUpdated(bool batched, uint256 swapDeltaBP, uint256 lpDeltaBP, bool defaultSwapMode, bool defaultLPMode);
//---------------------------------------------------------------------------
// MODIFIERS
modifier onlyRouter() {
require(msg.sender == router, "Stargate: only the router can call this method");
_;
}
constructor(
uint256 _poolId,
address _router,
address _token,
uint256 _sharedDecimals,
uint256 _localDecimals,
address _feeLibrary,
string memory _name,
string memory _symbol
) LPTokenERC20(_name, _symbol) {
require(_token != address(0x0), "Stargate: _token cannot be 0x0");
require(_router != address(0x0), "Stargate: _router cannot be 0x0");
poolId = _poolId;
router = _router;
token = _token;
sharedDecimals = _sharedDecimals;
decimals = uint8(_sharedDecimals);
localDecimals = _localDecimals;
convertRate = 10**(uint256(localDecimals).sub(sharedDecimals));
totalWeight = 0;
feeLibrary = _feeLibrary;
//delta algo related
batched = false;
defaultSwapMode = true;
defaultLPMode = true;
}
function getChainPathsLength() public view returns (uint256) {
return chainPaths.length;
}
//---------------------------------------------------------------------------
// LOCAL CHAIN FUNCTIONS
function mint(address _to, uint256 _amountLD) external nonReentrant onlyRouter returns (uint256) {
return _mintLocal(_to, _amountLD, true, true);
}
// Local Remote
// ------- ---------
// swap -> swapRemote
function swap(
uint16 _dstChainId,
uint256 _dstPoolId,
address _from,
uint256 _amountLD,
uint256 _minAmountLD,
bool newLiquidity
) external nonReentrant onlyRouter returns (SwapObj memory) {
require(!stopSwap, "Stargate: swap func stopped");
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
require(cp.ready == true, "Stargate: counter chainPath is not ready");
uint256 amountSD = amountLDtoSD(_amountLD);
uint256 minAmountSD = amountLDtoSD(_minAmountLD);
// request fee params from library
SwapObj memory s = IStargateFeeLibrary(feeLibrary).getFees(poolId, _dstPoolId, _dstChainId, _from, amountSD);
// equilibrium fee and reward. note eqFee/eqReward are separated from swap liquidity
eqFeePool = eqFeePool.sub(s.eqReward);
// update the new amount the user gets minus the fees
s.amount = amountSD.sub(s.eqFee).sub(s.protocolFee).sub(s.lpFee);
// users will also get the eqReward
require(s.amount.add(s.eqReward) >= minAmountSD, "Stargate: slippage too high");
// behaviours
// - protocolFee: booked, stayed and withdrawn at remote.
// - eqFee: booked, stayed and withdrawn at remote.
// - lpFee: booked and stayed at remote, can be withdrawn anywhere
s.lkbRemove = amountSD.sub(s.lpFee).add(s.eqReward);
// check for transfer solvency.
require(cp.balance >= s.lkbRemove, "Stargate: dst balance too low");
cp.balance = cp.balance.sub(s.lkbRemove);
if (newLiquidity) {
deltaCredit = deltaCredit.add(amountSD).add(s.eqReward);
} else if (s.eqReward > 0) {
deltaCredit = deltaCredit.add(s.eqReward);
}
// distribute credits on condition.
if (!batched || deltaCredit >= totalLiquidity.mul(swapDeltaBP).div(BP_DENOMINATOR)) {
_delta(defaultSwapMode);
}
emit Swap(_dstChainId, _dstPoolId, _from, s.amount, s.eqReward, s.eqFee, s.protocolFee, s.lpFee);
return s;
}
// Local Remote
// ------- ---------
// sendCredits -> creditChainPath
function sendCredits(uint16 _dstChainId, uint256 _dstPoolId) external nonReentrant onlyRouter returns (CreditObj memory c) {
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
require(cp.ready == true, "Stargate: counter chainPath is not ready");
cp.lkb = cp.lkb.add(cp.credits);
c.idealBalance = totalLiquidity.mul(cp.weight).div(totalWeight);
c.credits = cp.credits;
cp.credits = 0;
emit SendCredits(_dstChainId, _dstPoolId, c.credits, c.idealBalance);
}
// Local Remote
// ------- ---------
// redeemRemote -> swapRemote
function redeemRemote(
uint16 _dstChainId,
uint256 _dstPoolId,
address _from,
uint256 _amountLP
) external nonReentrant onlyRouter {
require(_from != address(0x0), "Stargate: _from cannot be 0x0");
uint256 amountSD = _burnLocal(_from, _amountLP);
//run Delta
if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
_delta(defaultLPMode);
}
uint256 amountLD = amountSDtoLD(amountSD);
emit RedeemRemote(_dstChainId, _dstPoolId, _from, _amountLP, amountLD);
}
function instantRedeemLocal(
address _from,
uint256 _amountLP,
address _to
) external nonReentrant onlyRouter returns (uint256 amountSD) {
require(_from != address(0x0), "Stargate: _from cannot be 0x0");
uint256 _deltaCredit = deltaCredit; // sload optimization.
uint256 _capAmountLP = _amountSDtoLP(_deltaCredit);
if (_amountLP > _capAmountLP) _amountLP = _capAmountLP;
amountSD = _burnLocal(_from, _amountLP);
deltaCredit = _deltaCredit.sub(amountSD);
uint256 amountLD = amountSDtoLD(amountSD);
_safeTransfer(token, _to, amountLD);
emit InstantRedeemLocal(_from, _amountLP, amountSD, _to);
}
// Local Remote
// ------- ---------
// redeemLocal -> redeemLocalCheckOnRemote
// redeemLocalCallback <-
function redeemLocal(
address _from,
uint256 _amountLP,
uint16 _dstChainId,
uint256 _dstPoolId,
bytes calldata _to
) external nonReentrant onlyRouter returns (uint256 amountSD) {
require(_from != address(0x0), "Stargate: _from cannot be 0x0");
// safeguard.
require(chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]].ready == true, "Stargate: counter chainPath is not ready");
amountSD = _burnLocal(_from, _amountLP);
// run Delta
if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
_delta(false);
}
emit RedeemLocal(_from, _amountLP, amountSD, _dstChainId, _dstPoolId, _to);
}
//---------------------------------------------------------------------------
// REMOTE CHAIN FUNCTIONS
// Local Remote
// ------- ---------
// sendCredits -> creditChainPath
function creditChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
CreditObj memory _c
) external nonReentrant onlyRouter {
ChainPath storage cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
cp.balance = cp.balance.add(_c.credits);
if (cp.idealBalance != _c.idealBalance) {
cp.idealBalance = _c.idealBalance;
}
emit CreditChainPath(_dstChainId, _dstPoolId, _c.credits, _c.idealBalance);
}
// Local Remote
// ------- ---------
// swap -> swapRemote
function swapRemote(
uint16 _srcChainId,
uint256 _srcPoolId,
address _to,
SwapObj memory _s
) external nonReentrant onlyRouter returns (uint256 amountLD) {
// booking lpFee
totalLiquidity = totalLiquidity.add(_s.lpFee);
// booking eqFee
eqFeePool = eqFeePool.add(_s.eqFee);
// booking stargateFee
protocolFeeBalance = protocolFeeBalance.add(_s.protocolFee);
// update LKB
uint256 chainPathIndex = chainPathIndexLookup[_srcChainId][_srcPoolId];
chainPaths[chainPathIndex].lkb = chainPaths[chainPathIndex].lkb.sub(_s.lkbRemove);
// user receives the amount + the srcReward
amountLD = amountSDtoLD(_s.amount.add(_s.eqReward));
_safeTransfer(token, _to, amountLD);
emit SwapRemote(_to, _s.amount.add(_s.eqReward), _s.protocolFee, _s.eqFee);
}
// Local Remote
// ------- ---------
// redeemLocal -> redeemLocalCheckOnRemote
// redeemLocalCallback <-
function redeemLocalCallback(
uint16 _srcChainId,
uint256 _srcPoolId,
address _to,
uint256 _amountSD,
uint256 _amountToMintSD
) external nonReentrant onlyRouter {
if (_amountToMintSD > 0) {
_mintLocal(_to, amountSDtoLD(_amountToMintSD), false, false);
}
ChainPath storage cp = getAndCheckCP(_srcChainId, _srcPoolId);
cp.lkb = cp.lkb.sub(_amountSD);
uint256 amountLD = amountSDtoLD(_amountSD);
_safeTransfer(token, _to, amountLD);
emit RedeemLocalCallback(_to, _amountSD, _amountToMintSD);
}
// Local Remote
// ------- ---------
// redeemLocal(amount) -> redeemLocalCheckOnRemote
// redeemLocalCallback <-
function redeemLocalCheckOnRemote(
uint16 _srcChainId,
uint256 _srcPoolId,
uint256 _amountSD
) external nonReentrant onlyRouter returns (uint256 swapAmount, uint256 mintAmount) {
ChainPath storage cp = getAndCheckCP(_srcChainId, _srcPoolId);
if (_amountSD > cp.balance) {
mintAmount = _amountSD - cp.balance;
swapAmount = cp.balance;
cp.balance = 0;
} else {
cp.balance = cp.balance.sub(_amountSD);
swapAmount = _amountSD;
mintAmount = 0;
}
emit WithdrawRemote(_srcChainId, _srcPoolId, swapAmount, mintAmount);
}
//---------------------------------------------------------------------------
// DAO Calls
function createChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
uint256 _weight
) external onlyRouter {
for (uint256 i = 0; i < chainPaths.length; ++i) {
ChainPath memory cp = chainPaths[i];
bool exists = cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId;
require(!exists, "Stargate: cant createChainPath of existing dstChainId and _dstPoolId");
}
totalWeight = totalWeight.add(_weight);
chainPathIndexLookup[_dstChainId][_dstPoolId] = chainPaths.length;
chainPaths.push(ChainPath(false, _dstChainId, _dstPoolId, _weight, 0, 0, 0, 0));
emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
}
function setWeightForChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
uint16 _weight
) external onlyRouter {
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
totalWeight = totalWeight.sub(cp.weight).add(_weight);
cp.weight = _weight;
emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
}
function setFee(uint256 _mintFeeBP) external onlyRouter {
require(_mintFeeBP <= BP_DENOMINATOR, "Bridge: cum fees > 100%");
mintFeeBP = _mintFeeBP;
emit FeesUpdated(mintFeeBP);
}
function setFeeLibrary(address _feeLibraryAddr) external onlyRouter {
require(_feeLibraryAddr != address(0x0), "Stargate: fee library cant be 0x0");
feeLibrary = _feeLibraryAddr;
emit FeeLibraryUpdated(_feeLibraryAddr);
}
function setSwapStop(bool _swapStop) external onlyRouter {
stopSwap = _swapStop;
emit StopSwapUpdated(_swapStop);
}
function setDeltaParam(
bool _batched,
uint256 _swapDeltaBP,
uint256 _lpDeltaBP,
bool _defaultSwapMode,
bool _defaultLPMode
) external onlyRouter {
require(_swapDeltaBP <= BP_DENOMINATOR && _lpDeltaBP <= BP_DENOMINATOR, "Stargate: wrong Delta param");
batched = _batched;
swapDeltaBP = _swapDeltaBP;
lpDeltaBP = _lpDeltaBP;
defaultSwapMode = _defaultSwapMode;
defaultLPMode = _defaultLPMode;
emit DeltaParamUpdated(_batched, _swapDeltaBP, _lpDeltaBP, _defaultSwapMode, _defaultLPMode);
}
function callDelta(bool _fullMode) external onlyRouter {
_delta(_fullMode);
}
function activateChainPath(uint16 _dstChainId, uint256 _dstPoolId) external onlyRouter {
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
require(cp.ready == false, "Stargate: chainPath is already active");
// this func will only be called once
cp.ready = true;
}
function withdrawProtocolFeeBalance(address _to) external onlyRouter {
if (protocolFeeBalance > 0) {
uint256 amountOfLD = amountSDtoLD(protocolFeeBalance);
protocolFeeBalance = 0;
_safeTransfer(token, _to, amountOfLD);
emit WithdrawProtocolFeeBalance(_to, amountOfLD);
}
}
function withdrawMintFeeBalance(address _to) external onlyRouter {
if (mintFeeBalance > 0) {
uint256 amountOfLD = amountSDtoLD(mintFeeBalance);
mintFeeBalance = 0;
_safeTransfer(token, _to, amountOfLD);
emit WithdrawMintFeeBalance(_to, amountOfLD);
}
}
//---------------------------------------------------------------------------
// INTERNAL
// Conversion Helpers
//---------------------------------------------------------------------------
function amountLPtoLD(uint256 _amountLP) external view returns (uint256) {
return amountSDtoLD(_amountLPtoSD(_amountLP));
}
function _amountLPtoSD(uint256 _amountLP) internal view returns (uint256) {
require(totalSupply > 0, "Stargate: cant convert LPtoSD when totalSupply == 0");
return _amountLP.mul(totalLiquidity).div(totalSupply);
}
function _amountSDtoLP(uint256 _amountSD) internal view returns (uint256) {
require(totalLiquidity > 0, "Stargate: cant convert SDtoLP when totalLiq == 0");
return _amountSD.mul(totalSupply).div(totalLiquidity);
}
function amountSDtoLD(uint256 _amount) internal view returns (uint256) {
return _amount.mul(convertRate);
}
function amountLDtoSD(uint256 _amount) internal view returns (uint256) {
return _amount.div(convertRate);
}
function getAndCheckCP(uint16 _dstChainId, uint256 _dstPoolId) internal view returns (ChainPath storage) {
require(chainPaths.length > 0, "Stargate: no chainpaths exist");
ChainPath storage cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
require(cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId, "Stargate: local chainPath does not exist");
return cp;
}
function getChainPath(uint16 _dstChainId, uint256 _dstPoolId) external view returns (ChainPath memory) {
ChainPath memory cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
require(cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId, "Stargate: local chainPath does not exist");
return cp;
}
function _burnLocal(address _from, uint256 _amountLP) internal returns (uint256) {
require(totalSupply > 0, "Stargate: cant burn when totalSupply == 0");
uint256 amountOfLPTokens = balanceOf[_from];
require(amountOfLPTokens >= _amountLP, "Stargate: not enough LP tokens to burn");
uint256 amountSD = _amountLP.mul(totalLiquidity).div(totalSupply);
//subtract totalLiquidity accordingly
totalLiquidity = totalLiquidity.sub(amountSD);
_burn(_from, _amountLP);
emit Burn(_from, _amountLP, amountSD);
return amountSD;
}
function _delta(bool fullMode) internal {
if (deltaCredit > 0 && totalWeight > 0) {
uint256 cpLength = chainPaths.length;
uint256[] memory deficit = new uint256[](cpLength);
uint256 totalDeficit = 0;
// algorithm steps 6-9: calculate the total and the amounts required to get to balance state
for (uint256 i = 0; i < cpLength; ++i) {
ChainPath storage cp = chainPaths[i];
// (liquidity * (weight/totalWeight)) - (lkb+credits)
uint256 balLiq = totalLiquidity.mul(cp.weight).div(totalWeight);
uint256 currLiq = cp.lkb.add(cp.credits);
if (balLiq > currLiq) {
// save gas since we know balLiq > currLiq and we know deficit[i] > 0
deficit[i] = balLiq - currLiq;
totalDeficit = totalDeficit.add(deficit[i]);
}
}
// indicates how much delta credit is distributed
uint256 spent;
// handle credits with 2 tranches. the [ < totalDeficit] [excessCredit]
// run full Delta, allocate all credits
if (totalDeficit == 0) {
// only fullMode delta will allocate excess credits
if (fullMode && deltaCredit > 0) {
// credit ChainPath by weights
for (uint256 i = 0; i < cpLength; ++i) {
ChainPath storage cp = chainPaths[i];
// credits = credits + toBalanceChange + remaining allocation based on weight
uint256 amtToCredit = deltaCredit.mul(cp.weight).div(totalWeight);
spent = spent.add(amtToCredit);
cp.credits = cp.credits.add(amtToCredit);
}
} // else do nth
} else if (totalDeficit <= deltaCredit) {
if (fullMode) {
// algorithm step 13: calculate amount to disperse to bring to balance state or as close as possible
uint256 excessCredit = deltaCredit - totalDeficit;
// algorithm steps 14-16: calculate credits
for (uint256 i = 0; i < cpLength; ++i) {
if (deficit[i] > 0) {
ChainPath storage cp = chainPaths[i];
// credits = credits + deficit + remaining allocation based on weight
uint256 amtToCredit = deficit[i].add(excessCredit.mul(cp.weight).div(totalWeight));
spent = spent.add(amtToCredit);
cp.credits = cp.credits.add(amtToCredit);
}
}
} else {
// totalDeficit <= deltaCredit but not running fullMode
// credit chainPaths as is if any deficit, not using all deltaCredit
for (uint256 i = 0; i < cpLength; ++i) {
if (deficit[i] > 0) {
ChainPath storage cp = chainPaths[i];
uint256 amtToCredit = deficit[i];
spent = spent.add(amtToCredit);
cp.credits = cp.credits.add(amtToCredit);
}
}
}
} else {
// totalDeficit > deltaCredit, fullMode or not, normalize the deficit by deltaCredit
for (uint256 i = 0; i < cpLength; ++i) {
if (deficit[i] > 0) {
ChainPath storage cp = chainPaths[i];
uint256 proportionalDeficit = deficit[i].mul(deltaCredit).div(totalDeficit);
spent = spent.add(proportionalDeficit);
cp.credits = cp.credits.add(proportionalDeficit);
}
}
}
// deduct the amount of credit sent
deltaCredit = deltaCredit.sub(spent);
}
}
function _mintLocal(
address _to,
uint256 _amountLD,
bool _feesEnabled,
bool _creditDelta
) internal returns (uint256 amountSD) {
require(totalWeight > 0, "Stargate: No ChainPaths exist");
amountSD = amountLDtoSD(_amountLD);
uint256 mintFeeSD = 0;
if (_feesEnabled) {
mintFeeSD = amountSD.mul(mintFeeBP).div(BP_DENOMINATOR);
amountSD = amountSD.sub(mintFeeSD);
mintFeeBalance = mintFeeBalance.add(mintFeeSD);
}
if (_creditDelta) {
deltaCredit = deltaCredit.add(amountSD);
}
uint256 amountLPTokens = amountSD;
if (totalSupply != 0) {
amountLPTokens = amountSD.mul(totalSupply).div(totalLiquidity);
}
totalLiquidity = totalLiquidity.add(amountSD);
_mint(_to, amountLPTokens);
emit Mint(_to, amountLPTokens, amountSD, mintFeeSD);
// add to credits and call delta. short circuit to save gas
if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
_delta(defaultLPMode);
}
}
function _safeTransfer(
address _token,
address _to,
uint256 _value
) private {
(bool success, bytes memory data) = _token.call(abi.encodeWithSelector(SELECTOR, _to, _value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "Stargate: TRANSFER_FAILED");
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
// libraries
import "@openzeppelin/contracts/math/SafeMath.sol";
contract LPTokenERC20 {
using SafeMath for uint256;
//---------------------------------------------------------------------------
// CONSTANTS
string public name;
string public symbol;
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
// set in constructor
bytes32 public DOMAIN_SEPARATOR;
//---------------------------------------------------------------------------
// VARIABLES
uint256 public decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
mapping(address => uint256) public nonces;
//---------------------------------------------------------------------------
// EVENTS
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
constructor(string memory _name, string memory _symbol) {
name = _name;
symbol = _symbol;
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes("1")),
chainId,
address(this)
)
);
}
function _mint(address to, uint256 value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint256 value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(
address owner,
address spender,
uint256 value
) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(
address from,
address to,
uint256 value
) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint256 value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint256 value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool) {
if (allowance[from][msg.sender] != uint256(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(deadline >= block.timestamp, "Bridge: EXPIRED");
bytes32 digest = keccak256(
abi.encodePacked(
"\\x19\\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, "Bridge: INVALID_SIGNATURE");
_approve(owner, spender, value);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.7.6;
pragma abicoder v2;
import "../Pool.sol";
interface IStargateFeeLibrary {
function getFees(
uint256 _srcPoolId,
uint256 _dstPoolId,
uint16 _dstChainId,
address _from,
uint256 _amountSD
) external returns (Pool.SwapObj memory s);
function getVersion() external view returns (string memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <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 GSN 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 payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
File 4 of 7: StargateEthVault
// Copyright (C) 2015, 2016, 2017 Dapphub
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.7.6;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./interfaces/IStargateEthVault.sol";
// This contract always UNWRAPS the erc20 for native gas token on transfer + transferFrom.
// If you wish to disable the transfer auto-unwrap, you can specify _to addresses with `setNoUnwrapTo`
contract StargateEthVault is IStargateEthVault, Ownable, ReentrancyGuard {
string public constant name = "Stargate Ether Vault";
string public constant symbol = "SGETH";
uint8 public constant decimals = 18;
uint256 public totalSupply;
event Approval(address indexed src, address indexed guy, uint wad);
event Transfer(address indexed src, address indexed dst, uint wad);
event Deposit(address indexed dst, uint wad);
event Withdrawal(address indexed src, uint wad);
event TransferNative(address indexed src, address indexed dst, uint wad);
mapping (address => uint) public balanceOf;
mapping (address => mapping (address => uint)) public allowance;
mapping (address => bool) public noUnwrapTo;
// if you do NOT wish to unwrap eth on transfers TO certain addresses
function setNoUnwrapTo(address _addr) external onlyOwner {
noUnwrapTo[_addr] = true;
}
function deposit() public payable override {
balanceOf[msg.sender] += msg.value;
totalSupply += msg.value;
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint wad) external override {
require(balanceOf[msg.sender] >= wad);
balanceOf[msg.sender] -= wad;
msg.sender.transfer(wad);
totalSupply -= wad;
emit Withdrawal(msg.sender, wad);
}
function approve(address guy, uint wad) external override returns (bool) {
allowance[msg.sender][guy] = wad;
emit Approval(msg.sender, guy, wad);
return true;
}
function transfer(address dst, uint wad) external override returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad) public override nonReentrant returns (bool) {
require(balanceOf[src] >= wad);
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
require(allowance[src][msg.sender] >= wad);
allowance[src][msg.sender] -= wad;
}
// always decrement the src (payer) address
balanceOf[src] -= wad;
if(noUnwrapTo[dst]){
// we do *not* unwrap
balanceOf[dst] += wad;
emit Transfer(src, dst, wad);
} else {
// unwrap and send native gas token
totalSupply -= wad; // if its getting unwrapped, decrement the totalSupply
(bool success, ) = dst.call{value: wad}("");
require(success, "SGETH: failed to transfer");
emit TransferNative(src, dst, wad);
}
return true;
}
function renounceOwnership() public override onlyOwner {}
receive() external payable {
deposit();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
pragma solidity 0.7.6;
interface IStargateEthVault {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint) external;
function approve(address guy, uint wad) external returns (bool);
function transferFrom(address src, address dst, uint wad) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <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 GSN 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 payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
File 5 of 7: MPTValidator01
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
import "./utility/LayerZeroPacket.sol";
import "./utility/UltraLightNodeEVMDecoder.sol";
import "../interfaces/IValidationLibraryHelperV2.sol";
import "../interfaces/ILayerZeroValidationLibrary.sol";
interface IStargate {
// Stargate objects for abi encoding / decoding
struct SwapObj {
uint amount;
uint eqFee;
uint eqReward;
uint lpFee;
uint protocolFee;
uint lkbRemove;
}
struct CreditObj {
uint credits;
uint idealBalance;
}
}
contract MPTValidator01 is ILayerZeroValidationLibrary, IValidationLibraryHelperV2 {
using RLPDecode for RLPDecode.RLPItem;
using RLPDecode for RLPDecode.Iterator;
uint8 public proofType = 1;
uint8 public utilsVersion = 4;
bytes32 public constant PACKET_SIGNATURE = 0xe9bded5f24a4168e4f3bf44e00298c993b22376aad8c58c7dda9718a54cbea82;
address public immutable stargateBridgeAddress;
address public immutable stargateTokenAddress;
constructor(address _stargateBridgeAddress, address _stargateTokenAddress) {
stargateBridgeAddress = _stargateBridgeAddress;
stargateTokenAddress = _stargateTokenAddress;
}
function validateProof(bytes32 _receiptsRoot, bytes calldata _transactionProof, uint _remoteAddressSize) external view override returns (LayerZeroPacket.Packet memory packet) {
require(_remoteAddressSize > 0, "ProofLib: invalid address size");
(bytes[] memory proof, uint[] memory receiptSlotIndex, uint logIndex) = abi.decode(_transactionProof, (bytes[], uint[], uint));
ULNLog memory log = _getVerifiedLog(_receiptsRoot, receiptSlotIndex, logIndex, proof);
require(log.topicZeroSig == PACKET_SIGNATURE, "ProofLib: packet not recognized"); //data
packet = LayerZeroPacket.getPacketV2(log.data, _remoteAddressSize, log.contractAddress);
if (packet.dstAddress == stargateBridgeAddress) packet.payload = _secureStgPayload(packet.payload);
if (packet.dstAddress == stargateTokenAddress) packet.payload = _secureStgTokenPayload(packet.payload);
return packet;
}
function _secureStgTokenPayload(bytes memory _payload) internal pure returns (bytes memory) {
(bytes memory toAddressBytes, uint qty) = abi.decode(_payload, (bytes, uint));
address toAddress = address(0);
if (toAddressBytes.length > 0) {
assembly {
toAddress := mload(add(toAddressBytes, 20))
}
}
if (toAddress == address(0)) {
address deadAddress = address(0x000000000000000000000000000000000000dEaD);
bytes memory newToAddressBytes = abi.encodePacked(deadAddress);
return abi.encode(newToAddressBytes, qty);
}
// default to return the original payload
return _payload;
}
function _secureStgPayload(bytes memory _payload) internal view returns (bytes memory) {
// functionType is uint8 even though the encoding will take up the side of uint256
uint8 functionType;
assembly {
functionType := mload(add(_payload, 32))
}
// TYPE_SWAP_REMOTE == 1 && only if the payload has a payload
// only swapRemote inside of stargate can call sgReceive on an user supplied to address
// thus we do not care about the other type functions even if the toAddress is overly long.
if (functionType == 1) {
// decode the _payload with its types
(, uint srcPoolId, uint dstPoolId, uint dstGasForCall, IStargate.CreditObj memory c, IStargate.SwapObj memory s, bytes memory toAddressBytes, bytes memory contractCallPayload) = abi.decode(_payload, (uint8, uint, uint, uint, IStargate.CreditObj, IStargate.SwapObj, bytes, bytes));
// if contractCallPayload.length > 0 need to check if the to address is a contract or not
if (contractCallPayload.length > 0) {
// otherwise, need to check if the payload can be delivered to the toAddress
address toAddress = address(0);
if (toAddressBytes.length > 0) {
assembly {
toAddress := mload(add(toAddressBytes, 20))
}
}
// check if the toAddress is a contract. We are not concerned about addresses that pretend to be wallets. because worst case we just delete their payload if being malicious
// we can guarantee that if a size > 0, then the contract is definitely a contract address in this context
uint size;
assembly {
size := extcodesize(toAddress)
}
if (size == 0) {
// size == 0 indicates its not a contract, payload wont be delivered
// secure the _payload to make sure funds can be delivered to the toAddress
bytes memory newToAddressBytes = abi.encodePacked(toAddress);
bytes memory securePayload = abi.encode(functionType, srcPoolId, dstPoolId, dstGasForCall, c, s, newToAddressBytes, bytes(""));
return securePayload;
}
}
}
// default to return the original payload
return _payload;
}
function secureStgTokenPayload(bytes memory _payload) external pure returns (bytes memory) {
return _secureStgTokenPayload(_payload);
}
function secureStgPayload(bytes memory _payload) external view returns (bytes memory) {
return _secureStgPayload(_payload);
}
function _getVerifiedLog(bytes32 hashRoot, uint[] memory paths, uint logIndex, bytes[] memory proof) internal pure returns (ULNLog memory) {
require(paths.length == proof.length, "ProofLib: invalid proof size");
require(proof.length > 0, "ProofLib: proof size must > 0");
RLPDecode.RLPItem memory item;
bytes memory proofBytes;
for (uint i = 0; i < proof.length; i++) {
proofBytes = proof[i];
require(hashRoot == keccak256(proofBytes), "ProofLib: invalid hashlink");
item = RLPDecode.toRlpItem(proofBytes).safeGetItemByIndex(paths[i]);
if (i < proof.length - 1) hashRoot = bytes32(item.toUint());
}
// burning status + gasUsed + logBloom
RLPDecode.RLPItem memory logItem = item.typeOffset().safeGetItemByIndex(3);
RLPDecode.Iterator memory it = logItem.safeGetItemByIndex(logIndex).iterator();
ULNLog memory log;
log.contractAddress = bytes32(it.next().toUint());
log.topicZeroSig = bytes32(it.next().safeGetItemByIndex(0).toUint());
log.data = it.next().toBytes();
return log;
}
function getUtilsVersion() external view override returns (uint8) {
return utilsVersion;
}
function getProofType() external view override returns (uint8) {
return proofType;
}
function getVerifyLog(bytes32 hashRoot, uint[] memory receiptSlotIndex, uint logIndex, bytes[] memory proof) external pure override returns (ULNLog memory) {
return _getVerifiedLog(hashRoot, receiptSlotIndex, logIndex, proof);
}
function getPacket(bytes memory data, uint sizeOfSrcAddress, bytes32 ulnAddress) external pure override returns (LayerZeroPacket.Packet memory) {
return LayerZeroPacket.getPacketV2(data, sizeOfSrcAddress, ulnAddress);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
import "./Buffer.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
library LayerZeroPacket {
using Buffer for Buffer.buffer;
using SafeMath for uint;
struct Packet {
uint16 srcChainId;
uint16 dstChainId;
uint64 nonce;
address dstAddress;
bytes srcAddress;
bytes32 ulnAddress;
bytes payload;
}
function getPacket(
bytes memory data,
uint16 srcChain,
uint sizeOfSrcAddress,
bytes32 ulnAddress
) internal pure returns (LayerZeroPacket.Packet memory) {
uint16 dstChainId;
address dstAddress;
uint size;
uint64 nonce;
// The log consists of the destination chain id and then a bytes payload
// 0--------------------------------------------31
// 0 | total bytes size
// 32 | destination chain id
// 64 | bytes offset
// 96 | bytes array size
// 128 | payload
assembly {
dstChainId := mload(add(data, 32))
size := mload(add(data, 96)) /// size of the byte array
nonce := mload(add(data, 104)) // offset to convert to uint64 128 is index -24
dstAddress := mload(add(data, sub(add(128, sizeOfSrcAddress), 4))) // offset to convert to address 12 -8
}
Buffer.buffer memory srcAddressBuffer;
srcAddressBuffer.init(sizeOfSrcAddress);
srcAddressBuffer.writeRawBytes(0, data, 136, sizeOfSrcAddress); // 128 + 8
uint payloadSize = size.sub(28).sub(sizeOfSrcAddress);
Buffer.buffer memory payloadBuffer;
payloadBuffer.init(payloadSize);
payloadBuffer.writeRawBytes(0, data, sizeOfSrcAddress.add(156), payloadSize); // 148 + 8
return LayerZeroPacket.Packet(srcChain, dstChainId, nonce, dstAddress, srcAddressBuffer.buf, ulnAddress, payloadBuffer.buf);
}
function getPacketV2(
bytes memory data,
uint sizeOfSrcAddress,
bytes32 ulnAddress
) internal pure returns (LayerZeroPacket.Packet memory) {
// packet def: abi.encodePacked(nonce, srcChain, srcAddress, dstChain, dstAddress, payload);
// data def: abi.encode(packet) = offset(32) + length(32) + packet
// if from EVM
// 0 - 31 0 - 31 | total bytes size
// 32 - 63 32 - 63 | location
// 64 - 95 64 - 95 | size of the packet
// 96 - 103 96 - 103 | nonce
// 104 - 105 104 - 105 | srcChainId
// 106 - P 106 - 125 | srcAddress, where P = 106 + sizeOfSrcAddress - 1,
// P+1 - P+2 126 - 127 | dstChainId
// P+3 - P+22 128 - 147 | dstAddress
// P+23 - END 148 - END | payload
// decode the packet
uint256 realSize;
uint64 nonce;
uint16 srcChain;
uint16 dstChain;
address dstAddress;
assembly {
realSize := mload(add(data, 64))
nonce := mload(add(data, 72)) // 104 - 32
srcChain := mload(add(data, 74)) // 106 - 32
dstChain := mload(add(data, add(76, sizeOfSrcAddress))) // P + 3 - 32 = 105 + size + 3 - 32 = 76 + size
dstAddress := mload(add(data, add(96, sizeOfSrcAddress))) // P + 23 - 32 = 105 + size + 23 - 32 = 96 + size
}
require(srcChain != 0, "LayerZeroPacket: invalid packet");
Buffer.buffer memory srcAddressBuffer;
srcAddressBuffer.init(sizeOfSrcAddress);
srcAddressBuffer.writeRawBytes(0, data, 106, sizeOfSrcAddress);
uint nonPayloadSize = sizeOfSrcAddress.add(32);// 2 + 2 + 8 + 20, 32 + 20 = 52 if sizeOfSrcAddress == 20
uint payloadSize = realSize.sub(nonPayloadSize);
Buffer.buffer memory payloadBuffer;
payloadBuffer.init(payloadSize);
payloadBuffer.writeRawBytes(0, data, nonPayloadSize.add(96), payloadSize);
return LayerZeroPacket.Packet(srcChain, dstChain, nonce, dstAddress, srcAddressBuffer.buf, ulnAddress, payloadBuffer.buf);
}
function getPacketV3(
bytes memory data,
uint sizeOfSrcAddress,
bytes32 ulnAddress
) internal pure returns (LayerZeroPacket.Packet memory) {
// data def: abi.encodePacked(nonce, srcChain, srcAddress, dstChain, dstAddress, payload);
// if from EVM
// 0 - 31 0 - 31 | total bytes size
// 32 - 39 32 - 39 | nonce
// 40 - 41 40 - 41 | srcChainId
// 42 - P 42 - 61 | srcAddress, where P = 41 + sizeOfSrcAddress,
// P+1 - P+2 62 - 63 | dstChainId
// P+3 - P+22 64 - 83 | dstAddress
// P+23 - END 84 - END | payload
// decode the packet
uint256 realSize = data.length;
uint nonPayloadSize = sizeOfSrcAddress.add(32);// 2 + 2 + 8 + 20, 32 + 20 = 52 if sizeOfSrcAddress == 20
require(realSize >= nonPayloadSize, "LayerZeroPacket: invalid packet");
uint payloadSize = realSize - nonPayloadSize;
uint64 nonce;
uint16 srcChain;
uint16 dstChain;
address dstAddress;
assembly {
nonce := mload(add(data, 8)) // 40 - 32
srcChain := mload(add(data, 10)) // 42 - 32
dstChain := mload(add(data, add(12, sizeOfSrcAddress))) // P + 3 - 32 = 41 + size + 3 - 32 = 12 + size
dstAddress := mload(add(data, add(32, sizeOfSrcAddress))) // P + 23 - 32 = 41 + size + 23 - 32 = 32 + size
}
require(srcChain != 0, "LayerZeroPacket: invalid packet");
Buffer.buffer memory srcAddressBuffer;
srcAddressBuffer.init(sizeOfSrcAddress);
srcAddressBuffer.writeRawBytes(0, data, 42, sizeOfSrcAddress);
Buffer.buffer memory payloadBuffer;
if (payloadSize > 0) {
payloadBuffer.init(payloadSize);
payloadBuffer.writeRawBytes(0, data, nonPayloadSize.add(32), payloadSize);
}
return LayerZeroPacket.Packet(srcChain, dstChain, nonce, dstAddress, srcAddressBuffer.buf, ulnAddress, payloadBuffer.buf);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.7.0;
pragma abicoder v2;
import "./RLPDecode.sol";
library UltraLightNodeEVMDecoder {
using RLPDecode for RLPDecode.RLPItem;
using RLPDecode for RLPDecode.Iterator;
struct Log {
address contractAddress;
bytes32 topicZero;
bytes data;
}
function getReceiptLog(bytes memory data, uint logIndex) internal pure returns (Log memory) {
RLPDecode.Iterator memory it = RLPDecode.toRlpItem(data).iterator();
uint idx;
while (it.hasNext()) {
if (idx == 3) {
return toReceiptLog(it.next().getItemByIndex(logIndex).toRlpBytes());
} else it.next();
idx++;
}
revert("no log index in receipt");
}
function toReceiptLog(bytes memory data) internal pure returns (Log memory) {
RLPDecode.Iterator memory it = RLPDecode.toRlpItem(data).iterator();
Log memory log;
uint idx;
while (it.hasNext()) {
if (idx == 0) {
log.contractAddress = it.next().toAddress();
} else if (idx == 1) {
RLPDecode.RLPItem memory item = it.next().getItemByIndex(0);
log.topicZero = bytes32(item.toUint());
} else if (idx == 2) log.data = it.next().toBytes();
else it.next();
idx++;
}
return log;
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.0;
pragma abicoder v2;
import "../proof/utility/LayerZeroPacket.sol";
interface IValidationLibraryHelperV2 {
struct ULNLog {
bytes32 contractAddress;
bytes32 topicZeroSig;
bytes data;
}
function getVerifyLog(bytes32 hashRoot, uint[] calldata receiptSlotIndex, uint logIndex, bytes[] calldata proof) external pure returns (ULNLog memory);
function getPacket(bytes calldata data, uint sizeOfSrcAddress, bytes32 ulnAddress) external pure returns (LayerZeroPacket.Packet memory);
function getUtilsVersion() external view returns (uint8);
function getProofType() external view returns (uint8);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.0;
pragma abicoder v2;
import "../proof/utility/LayerZeroPacket.sol";
interface ILayerZeroValidationLibrary {
function validateProof(bytes32 blockData, bytes calldata _data, uint _remoteAddressSize) external returns (LayerZeroPacket.Packet memory packet);
}
// SPDX-License-Identifier: BUSL-1.1
// https://github.com/ensdomains/buffer
pragma solidity ^0.7.0;
/**
* @dev A library for working with mutable byte buffers in Solidity.
*
* Byte buffers are mutable and expandable, and provide a variety of primitives
* for writing to them. At any time you can fetch a bytes object containing the
* current contents of the buffer. The bytes object should not be stored between
* operations, as it may change due to resizing of the buffer.
*/
library Buffer {
/**
* @dev Represents a mutable buffer. Buffers have a current value (buf) and
* a capacity. The capacity may be longer than the current value, in
* which case it can be extended without the need to allocate more memory.
*/
struct buffer {
bytes buf;
uint capacity;
}
/**
* @dev Initializes a buffer with an initial capacity.a co
* @param buf The buffer to initialize.
* @param capacity The number of bytes of space to allocate the buffer.
* @return The buffer, for chaining.
*/
function init(buffer memory buf, uint capacity) internal pure returns (buffer memory) {
if (capacity % 32 != 0) {
capacity += 32 - (capacity % 32);
}
// Allocate space for the buffer data
buf.capacity = capacity;
assembly {
let ptr := mload(0x40)
mstore(buf, ptr)
mstore(ptr, 0)
mstore(0x40, add(32, add(ptr, capacity)))
}
return buf;
}
/**
* @dev Writes a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param off The start offset to write to.
* @param rawData The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function writeRawBytes(
buffer memory buf,
uint off,
bytes memory rawData,
uint offData,
uint len
) internal pure returns (buffer memory) {
if (off + len > buf.capacity) {
resize(buf, max(buf.capacity, len + off) * 2);
}
uint dest;
uint src;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Start address = buffer address + offset + sizeof(buffer length)
dest := add(add(bufptr, 32), off)
// Update buffer length if we're extending it
if gt(add(len, off), buflen) {
mstore(bufptr, add(len, off))
}
src := add(rawData, offData)
}
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
uint mask = 256**(32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
return buf;
}
/**
* @dev Writes a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param off The start offset to write to.
* @param data The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns (buffer memory) {
require(len <= data.length);
if (off + len > buf.capacity) {
resize(buf, max(buf.capacity, len + off) * 2);
}
uint dest;
uint src;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Start address = buffer address + offset + sizeof(buffer length)
dest := add(add(bufptr, 32), off)
// Update buffer length if we're extending it
if gt(add(len, off), buflen) {
mstore(bufptr, add(len, off))
}
src := add(data, 32)
}
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
uint mask = 256**(32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
return buf;
}
function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, data, data.length);
}
function resize(buffer memory buf, uint capacity) private pure {
bytes memory oldbuf = buf.buf;
init(buf, capacity);
append(buf, oldbuf);
}
function max(uint a, uint b) private pure returns (uint) {
if (a > b) {
return a;
}
return b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: BUSL-1.1
// https://github.com/hamdiallam/solidity-rlp
pragma solidity ^0.7.0;
library RLPDecode {
uint8 constant STRING_SHORT_START = 0x80;
uint8 constant STRING_LONG_START = 0xb8;
uint8 constant LIST_SHORT_START = 0xc0;
uint8 constant LIST_LONG_START = 0xf8;
uint8 constant WORD_SIZE = 32;
struct RLPItem {
uint len;
uint memPtr;
}
struct Iterator {
RLPItem item; // Item that's being iterated over.
uint nextPtr; // Position of the next item in the list.
}
/*
* @dev Returns the next element in the iteration. Reverts if it has not next element.
* @param self The iterator.
* @return The next element in the iteration.
*/
function next(Iterator memory self) internal pure returns (RLPItem memory) {
require(hasNext(self), "RLPDecoder iterator has no next");
uint ptr = self.nextPtr;
uint itemLength = _itemLength(ptr);
self.nextPtr = ptr + itemLength;
return RLPItem(itemLength, ptr);
}
/*
* @dev Returns true if the iteration has more elements.
* @param self The iterator.
* @return true if the iteration has more elements.
*/
function hasNext(Iterator memory self) internal pure returns (bool) {
RLPItem memory item = self.item;
return self.nextPtr < item.memPtr + item.len;
}
/*
* @param item RLP encoded bytes
*/
function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
uint memPtr;
assembly {
memPtr := add(item, 0x20)
}
// offset the pointer if the first byte
uint8 byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
uint len = item.length;
if (len > 0 && byte0 < LIST_SHORT_START) {
assembly {
memPtr := add(memPtr, 0x01)
}
len -= 1;
}
return RLPItem(len, memPtr);
}
/*
* @dev Create an iterator. Reverts if item is not a list.
* @param self The RLP item.
* @return An 'Iterator' over the item.
*/
function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
require(isList(self), "RLPDecoder iterator is not list");
uint ptr = self.memPtr + _payloadOffset(self.memPtr);
return Iterator(self, ptr);
}
/*
* @param item RLP encoded bytes
*/
function rlpLen(RLPItem memory item) internal pure returns (uint) {
return item.len;
}
/*
* @param item RLP encoded bytes
*/
function payloadLen(RLPItem memory item) internal pure returns (uint) {
uint offset = _payloadOffset(item.memPtr);
require(item.len >= offset, "RLPDecoder: invalid uint RLP item offset size");
return item.len - offset;
}
/*
* @param item RLP encoded list in bytes
*/
function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
require(isList(item), "RLPDecoder iterator is not a list");
uint items = numItems(item);
RLPItem[] memory result = new RLPItem[](items);
uint memPtr = item.memPtr + _payloadOffset(item.memPtr);
uint dataLen;
for (uint i = 0; i < items; i++) {
dataLen = _itemLength(memPtr);
result[i] = RLPItem(dataLen, memPtr);
memPtr = memPtr + dataLen;
}
return result;
}
/*
* @param get the RLP item by index. save gas.
*/
function getItemByIndex(RLPItem memory item, uint idx) internal pure returns (RLPItem memory) {
require(isList(item), "RLPDecoder iterator is not a list");
uint memPtr = item.memPtr + _payloadOffset(item.memPtr);
uint dataLen;
for (uint i = 0; i < idx; i++) {
dataLen = _itemLength(memPtr);
memPtr = memPtr + dataLen;
}
dataLen = _itemLength(memPtr);
return RLPItem(dataLen, memPtr);
}
/*
* @param get the RLP item by index. save gas.
*/
function safeGetItemByIndex(RLPItem memory item, uint idx) internal pure returns (RLPItem memory) {
require(isList(item), "RLPDecoder iterator is not a list");
require(idx < numItems(item), "RLP item out of bounds");
uint endPtr = item.memPtr + item.len;
uint memPtr = item.memPtr + _payloadOffset(item.memPtr);
uint dataLen;
for (uint i = 0; i < idx; i++) {
dataLen = _itemLength(memPtr);
memPtr = memPtr + dataLen;
}
dataLen = _itemLength(memPtr);
require(memPtr + dataLen <= endPtr, "RLP item overflow");
return RLPItem(dataLen, memPtr);
}
/*
* @param offset the receipt bytes item
*/
function typeOffset(RLPItem memory item) internal pure returns (RLPItem memory) {
uint offset = _payloadOffset(item.memPtr);
uint8 byte0;
uint memPtr = item.memPtr;
uint len = item.len;
assembly {
memPtr := add(memPtr, offset)
byte0 := byte(0, mload(memPtr))
}
if (len >0 && byte0 < LIST_SHORT_START) {
assembly {
memPtr := add(memPtr, 0x01)
}
len -= 1;
}
return RLPItem(len, memPtr);
}
// @return indicator whether encoded payload is a list. negate this function call for isData.
function isList(RLPItem memory item) internal pure returns (bool) {
if (item.len == 0) return false;
uint8 byte0;
uint memPtr = item.memPtr;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < LIST_SHORT_START) return false;
return true;
}
/** RLPItem conversions into data types **/
// @returns raw rlp encoding in bytes
function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
bytes memory result = new bytes(item.len);
if (result.length == 0) return result;
uint ptr;
assembly {
ptr := add(0x20, result)
}
copy(item.memPtr, ptr, item.len);
return result;
}
// any non-zero byte except "0x80" is considered true
function toBoolean(RLPItem memory item) internal pure returns (bool) {
require(item.len == 1, "RLPDecoder toBoolean invalid length");
uint result;
uint memPtr = item.memPtr;
assembly {
result := byte(0, mload(memPtr))
}
// SEE Github Issue #5.
// Summary: Most commonly used RLP libraries (i.e Geth) will encode
// "0" as "0x80" instead of as "0". We handle this edge case explicitly
// here.
if (result == 0 || result == STRING_SHORT_START) {
return false;
} else {
return true;
}
}
function toAddress(RLPItem memory item) internal pure returns (address) {
// 1 byte for the length prefix
require(item.len == 21, "RLPDecoder toAddress invalid length");
return address(toUint(item));
}
function toUint(RLPItem memory item) internal pure returns (uint) {
require(item.len > 0 && item.len <= 33, "RLPDecoder toUint invalid length");
uint offset = _payloadOffset(item.memPtr);
require(item.len >= offset, "RLPDecoder: invalid RLP item offset size");
uint len = item.len - offset;
uint result;
uint memPtr = item.memPtr + offset;
assembly {
result := mload(memPtr)
// shift to the correct location if necessary
if lt(len, 32) {
result := div(result, exp(256, sub(32, len)))
}
}
return result;
}
// enforces 32 byte length
function toUintStrict(RLPItem memory item) internal pure returns (uint) {
// one byte prefix
require(item.len == 33, "RLPDecoder toUintStrict invalid length");
uint result;
uint memPtr = item.memPtr + 1;
assembly {
result := mload(memPtr)
}
return result;
}
function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
require(item.len > 0, "RLPDecoder toBytes invalid length");
uint offset = _payloadOffset(item.memPtr);
require(item.len >= offset, "RLPDecoder: invalid RLP item offset size");
uint len = item.len - offset; // data length
bytes memory result = new bytes(len);
uint destPtr;
assembly {
destPtr := add(0x20, result)
}
copy(item.memPtr + offset, destPtr, len);
return result;
}
/*
* Private Helpers
*/
// @return number of payload items inside an encoded list.
function numItems(RLPItem memory item) internal pure returns (uint) {
if (item.len == 0) return 0;
uint count = 0;
uint currPtr = item.memPtr + _payloadOffset(item.memPtr);
uint endPtr = item.memPtr + item.len;
while (currPtr < endPtr) {
currPtr = currPtr + _itemLength(currPtr); // skip over an item
count++;
}
return count;
}
// @return entire rlp item byte length
function _itemLength(uint memPtr) private pure returns (uint) {
uint itemLen;
uint byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) itemLen = 1;
else if (byte0 < STRING_LONG_START) itemLen = byte0 - STRING_SHORT_START + 1;
else if (byte0 < LIST_SHORT_START) {
assembly {
let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
memPtr := add(memPtr, 1) // skip over the first byte
/* 32 byte word size */
let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
itemLen := add(dataLen, add(byteLen, 1))
}
} else if (byte0 < LIST_LONG_START) {
itemLen = byte0 - LIST_SHORT_START + 1;
} else {
assembly {
let byteLen := sub(byte0, 0xf7)
memPtr := add(memPtr, 1)
let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
itemLen := add(dataLen, add(byteLen, 1))
}
}
return itemLen;
}
// @return number of bytes until the data
function _payloadOffset(uint memPtr) private pure returns (uint) {
uint byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) return 0;
else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) return 1;
else if (byte0 < LIST_SHORT_START)
// being explicit
return byte0 - (STRING_LONG_START - 1) + 1;
else return byte0 - (LIST_LONG_START - 1) + 1;
}
/*
* @param src Pointer to source
* @param dest Pointer to destination
* @param len Amount of memory to copy from the source
*/
function copy(
uint src,
uint dest,
uint len
) private pure {
if (len == 0) return;
// copy as many word sizes as possible
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
src += WORD_SIZE;
dest += WORD_SIZE;
}
// left over bytes. Mask is used to remove unwanted bytes from the word
uint mask = 256**(WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask)) // zero out src
let destpart := and(mload(dest), mask) // retrieve the bytes
mstore(dest, or(destpart, srcpart))
}
}
}
File 6 of 7: Endpoint
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
import "./interfaces/ILayerZeroReceiver.sol";
import "./interfaces/ILayerZeroEndpoint.sol";
import "./interfaces/ILayerZeroMessagingLibrary.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Endpoint is Ownable, ILayerZeroEndpoint {
uint16 public immutable chainId;
// installed libraries and reserved versions
uint16 public constant BLOCK_VERSION = 65535;
uint16 public constant DEFAULT_VERSION = 0;
uint16 public latestVersion;
mapping(uint16 => ILayerZeroMessagingLibrary) public libraryLookup; // version -> ILayerZeroEndpointLibrary
// default send/receive libraries
uint16 public defaultSendVersion;
uint16 public defaultReceiveVersion;
ILayerZeroMessagingLibrary public defaultSendLibrary;
address public defaultReceiveLibraryAddress;
struct LibraryConfig {
uint16 sendVersion;
uint16 receiveVersion;
address receiveLibraryAddress;
ILayerZeroMessagingLibrary sendLibrary;
}
struct StoredPayload {
uint64 payloadLength;
address dstAddress;
bytes32 payloadHash;
}
// user app config = [uaAddress]
mapping(address => LibraryConfig) public uaConfigLookup;
// inboundNonce = [srcChainId][srcAddress].
mapping(uint16 => mapping(bytes => uint64)) public inboundNonce;
// outboundNonce = [dstChainId][srcAddress].
mapping(uint16 => mapping(address => uint64)) public outboundNonce;
// storedPayload = [srcChainId][srcAddress]
mapping(uint16 => mapping(bytes => StoredPayload)) public storedPayload;
// library versioning events
event NewLibraryVersionAdded(uint16 version);
event DefaultSendVersionSet(uint16 version);
event DefaultReceiveVersionSet(uint16 version);
event UaSendVersionSet(address ua, uint16 version);
event UaReceiveVersionSet(address ua, uint16 version);
event UaForceResumeReceive(uint16 chainId, bytes srcAddress);
// payload events
event PayloadCleared(uint16 srcChainId, bytes srcAddress, uint64 nonce, address dstAddress);
event PayloadStored(uint16 srcChainId, bytes srcAddress, address dstAddress, uint64 nonce, bytes payload, bytes reason);
constructor(uint16 _chainId) {
chainId = _chainId;
}
//---------------------------------------------------------------------------
// send and receive nonreentrant lock
uint8 internal constant _NOT_ENTERED = 1;
uint8 internal constant _ENTERED = 2;
uint8 internal _send_entered_state = 1;
uint8 internal _receive_entered_state = 1;
modifier sendNonReentrant() {
require(_send_entered_state == _NOT_ENTERED, "LayerZero: no send reentrancy");
_send_entered_state = _ENTERED;
_;
_send_entered_state = _NOT_ENTERED;
}
modifier receiveNonReentrant() {
require(_receive_entered_state == _NOT_ENTERED, "LayerZero: no receive reentrancy");
_receive_entered_state = _ENTERED;
_;
_receive_entered_state = _NOT_ENTERED;
}
// BLOCK_VERSION is also a valid version
modifier validVersion(uint16 _version) {
require(_version <= latestVersion || _version == BLOCK_VERSION, "LayerZero: invalid messaging library version");
_;
}
//---------------------------------------------------------------------------
// User Application Calls - Endpoint Interface
function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable override sendNonReentrant {
LibraryConfig storage uaConfig = uaConfigLookup[msg.sender];
uint64 nonce = ++outboundNonce[_dstChainId][msg.sender];
_getSendLibrary(uaConfig).send{value: msg.value}(msg.sender, nonce, _dstChainId, _destination, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);
}
//---------------------------------------------------------------------------
// authenticated Library (msg.sender) Calls to pass through Endpoint to UA (dstAddress)
function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external override receiveNonReentrant {
// assert and increment the nonce. no message shuffling
require(_nonce == ++inboundNonce[_srcChainId][_srcAddress], "LayerZero: wrong nonce");
LibraryConfig storage uaConfig = uaConfigLookup[_dstAddress];
// authentication to prevent cross-version message validation
// protects against a malicious library from passing arbitrary data
if (uaConfig.receiveVersion == DEFAULT_VERSION) {
require(defaultReceiveLibraryAddress == msg.sender, "LayerZero: invalid default library");
} else {
require(uaConfig.receiveLibraryAddress == msg.sender, "LayerZero: invalid library");
}
// block if any message blocking
StoredPayload storage sp = storedPayload[_srcChainId][_srcAddress];
require(sp.payloadHash == bytes32(0), "LayerZero: in message blocking");
try ILayerZeroReceiver(_dstAddress).lzReceive{gas: _gasLimit}(_srcChainId, _srcAddress, _nonce, _payload) {
// success, do nothing, end of the message delivery
} catch (bytes memory reason) {
// revert nonce if any uncaught errors/exceptions if the ua chooses the blocking mode
storedPayload[_srcChainId][_srcAddress] = StoredPayload(uint64(_payload.length), _dstAddress, keccak256(_payload));
emit PayloadStored(_srcChainId, _srcAddress, _dstAddress, _nonce, _payload, reason);
}
}
function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external override receiveNonReentrant {
StoredPayload storage sp = storedPayload[_srcChainId][_srcAddress];
require(sp.payloadHash != bytes32(0), "LayerZero: no stored payload");
require(_payload.length == sp.payloadLength && keccak256(_payload) == sp.payloadHash, "LayerZero: invalid payload");
address dstAddress = sp.dstAddress;
// empty the storedPayload
sp.payloadLength = 0;
sp.dstAddress = address(0);
sp.payloadHash = bytes32(0);
uint64 nonce = inboundNonce[_srcChainId][_srcAddress];
ILayerZeroReceiver(dstAddress).lzReceive(_srcChainId, _srcAddress, nonce, _payload);
emit PayloadCleared(_srcChainId, _srcAddress, nonce, dstAddress);
}
//---------------------------------------------------------------------------
// Owner Calls, only new library version upgrade (3 steps)
// note libraryLookup[0] = 0x0, no library implementation
// LIBRARY UPGRADE step 1: set _newLayerZeroLibraryAddress be the new version
function newVersion(address _newLayerZeroLibraryAddress) external onlyOwner {
require(_newLayerZeroLibraryAddress != address(0x0), "LayerZero: new version cannot be zero address");
require(latestVersion < 65535, "LayerZero: can not add new messaging library");
latestVersion++;
libraryLookup[latestVersion] = ILayerZeroMessagingLibrary(_newLayerZeroLibraryAddress);
emit NewLibraryVersionAdded(latestVersion);
}
// LIBRARY UPGRADE step 2: stop sending messages from the old version
function setDefaultSendVersion(uint16 _newDefaultSendVersion) external onlyOwner validVersion(_newDefaultSendVersion) {
require(_newDefaultSendVersion != DEFAULT_VERSION, "LayerZero: default send version must > 0");
defaultSendVersion = _newDefaultSendVersion;
defaultSendLibrary = libraryLookup[defaultSendVersion];
emit DefaultSendVersionSet(_newDefaultSendVersion);
}
// LIBRARY UPGRADE step 3: stop receiving messages from the old version
function setDefaultReceiveVersion(uint16 _newDefaultReceiveVersion) external onlyOwner validVersion(_newDefaultReceiveVersion) {
require(_newDefaultReceiveVersion != DEFAULT_VERSION, "LayerZero: default receive version must > 0");
defaultReceiveVersion = _newDefaultReceiveVersion;
defaultReceiveLibraryAddress = address(libraryLookup[defaultReceiveVersion]);
emit DefaultReceiveVersionSet(_newDefaultReceiveVersion);
}
//---------------------------------------------------------------------------
// User Application Calls - UA set/get Interface
function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external override validVersion(_version) {
if (_version == DEFAULT_VERSION) {
require(defaultSendVersion == defaultReceiveVersion, "LayerZero: can not set Config during DEFAULT migration");
_version = defaultSendVersion;
}
require(_version != BLOCK_VERSION, "LayerZero: can not set config for BLOCK_VERSION");
libraryLookup[_version].setConfig(_chainId, msg.sender, _configType, _config);
}
// Migration step 1: set the send version
// Define what library the UA points too
function setSendVersion(uint16 _newVersion) external override validVersion(_newVersion) {
// write into config
LibraryConfig storage uaConfig = uaConfigLookup[msg.sender];
uaConfig.sendVersion = _newVersion;
// the libraryLookup[BLOCK_VERSION || DEFAULT_VERSION] = 0x0
uaConfig.sendLibrary = libraryLookup[_newVersion];
emit UaSendVersionSet(msg.sender, _newVersion);
}
// Migration step 2: set the receive version
// after all messages sent from the old version are received
// the UA can now safely switch to the new receive version
// it is the UA's responsibility make sure all messages from the old version are processed
function setReceiveVersion(uint16 _newVersion) external override validVersion(_newVersion) {
// write into config
LibraryConfig storage uaConfig = uaConfigLookup[msg.sender];
uaConfig.receiveVersion = _newVersion;
// the libraryLookup[BLOCK_VERSION || DEFAULT_VERSION] = 0x0
uaConfig.receiveLibraryAddress = address(libraryLookup[_newVersion]);
emit UaReceiveVersionSet(msg.sender, _newVersion);
}
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override {
StoredPayload storage sp = storedPayload[_srcChainId][_srcAddress];
// revert if no messages are cached. safeguard malicious UA behaviour
require(sp.payloadHash != bytes32(0), "LayerZero: no stored payload");
require(sp.dstAddress == msg.sender, "LayerZero: invalid caller");
// empty the storedPayload
sp.payloadLength = 0;
sp.dstAddress = address(0);
sp.payloadHash = bytes32(0);
// emit the event with the new nonce
emit UaForceResumeReceive(_srcChainId, _srcAddress);
}
//---------------------------------------------------------------------------
// view helper function
function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParams) external view override returns (uint nativeFee, uint zroFee) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
ILayerZeroMessagingLibrary lib = uaConfig.sendVersion == DEFAULT_VERSION ? defaultSendLibrary : uaConfig.sendLibrary;
return lib.estimateFees(_dstChainId, _userApplication, _payload, _payInZRO, _adapterParams);
}
function _getSendLibrary(LibraryConfig storage uaConfig) internal view returns (ILayerZeroMessagingLibrary) {
if (uaConfig.sendVersion == DEFAULT_VERSION) {
// check if the in send-blocking upgrade
require(defaultSendVersion != BLOCK_VERSION, "LayerZero: default in BLOCK_VERSION");
return defaultSendLibrary;
} else {
// check if the in send-blocking upgrade
require(uaConfig.sendVersion != BLOCK_VERSION, "LayerZero: in BLOCK_VERSION");
return uaConfig.sendLibrary;
}
}
function getSendLibraryAddress(address _userApplication) external view override returns (address sendLibraryAddress) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
uint16 sendVersion = uaConfig.sendVersion;
require(sendVersion != BLOCK_VERSION, "LayerZero: send version is BLOCK_VERSION");
if (sendVersion == DEFAULT_VERSION) {
require(defaultSendVersion != BLOCK_VERSION, "LayerZero: send version (default) is BLOCK_VERSION");
sendLibraryAddress = address(defaultSendLibrary);
} else {
sendLibraryAddress = address(uaConfig.sendLibrary);
}
}
function getReceiveLibraryAddress(address _userApplication) external view override returns (address receiveLibraryAddress) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
uint16 receiveVersion = uaConfig.receiveVersion;
require(receiveVersion != BLOCK_VERSION, "LayerZero: receive version is BLOCK_VERSION");
if (receiveVersion == DEFAULT_VERSION) {
require(defaultReceiveVersion != BLOCK_VERSION, "LayerZero: receive version (default) is BLOCK_VERSION");
receiveLibraryAddress = defaultReceiveLibraryAddress;
} else {
receiveLibraryAddress = uaConfig.receiveLibraryAddress;
}
}
function isSendingPayload() external view override returns (bool) {
return _send_entered_state == _ENTERED;
}
function isReceivingPayload() external view override returns (bool) {
return _receive_entered_state == _ENTERED;
}
function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view override returns (uint64) {
return inboundNonce[_srcChainId][_srcAddress];
}
function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view override returns (uint64) {
return outboundNonce[_dstChainId][_srcAddress];
}
function getChainId() external view override returns (uint16) {
return chainId;
}
function getSendVersion(address _userApplication) external view override returns (uint16) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
return uaConfig.sendVersion == DEFAULT_VERSION ? defaultSendVersion : uaConfig.sendVersion;
}
function getReceiveVersion(address _userApplication) external view override returns (uint16) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
return uaConfig.receiveVersion == DEFAULT_VERSION ? defaultReceiveVersion : uaConfig.receiveVersion;
}
function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view override validVersion(_version) returns (bytes memory) {
if (_version == DEFAULT_VERSION) {
require(defaultSendVersion == defaultReceiveVersion, "LayerZero: no DEFAULT config while migration");
_version = defaultSendVersion;
}
require(_version != BLOCK_VERSION, "LayerZero: can not get config for BLOCK_VERSION");
return libraryLookup[_version].getConfig(_chainId, _userApplication, _configType);
}
function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view override returns (bool) {
StoredPayload storage sp = storedPayload[_srcChainId][_srcAddress];
return sp.payloadHash != bytes32(0);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface ILayerZeroReceiver {
// @notice LayerZero endpoint will invoke this function to deliver the message on the destination
// @param _srcChainId - the source endpoint identifier
// @param _srcAddress - the source sending contract address from the source chain
// @param _nonce - the ordered message nonce
// @param _payload - the signed payload is the UA bytes has encoded to be sent
function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./ILayerZeroUserApplicationConfig.sol";
interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
// @notice send a LayerZero message to the specified address at a LayerZero endpoint.
// @param _dstChainId - the destination chain identifier
// @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
// @param _payload - a custom bytes payload to send to the destination contract
// @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
// @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
// @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
// @notice used by the messaging library to publish verified payload
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source contract (as bytes) at the source chain
// @param _dstAddress - the address on destination chain
// @param _nonce - the unbound message ordering nonce
// @param _gasLimit - the gas limit for external contract execution
// @param _payload - verified payload to send to the destination contract
function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;
// @notice get the inboundNonce of a receiver from a source chain which could be EVM or non-EVM chain
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);
// @notice get the outboundNonce from this source chain which, consequently, is always an EVM
// @param _srcAddress - the source chain contract address
function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);
// @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
// @param _dstChainId - the destination chain identifier
// @param _userApplication - the user app address on this EVM chain
// @param _payload - the custom message to send over LayerZero
// @param _payInZRO - if false, user app pays the protocol fee in native token
// @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);
// @notice get this Endpoint's immutable source identifier
function getChainId() external view returns (uint16);
// @notice the interface to retry failed message on this Endpoint destination
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
// @param _payload - the payload to be retried
function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;
// @notice query if any STORED payload (message blocking) at the endpoint.
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);
// @notice query if the _libraryAddress is valid for sending msgs.
// @param _userApplication - the user app address on this EVM chain
function getSendLibraryAddress(address _userApplication) external view returns (address);
// @notice query if the _libraryAddress is valid for receiving msgs.
// @param _userApplication - the user app address on this EVM chain
function getReceiveLibraryAddress(address _userApplication) external view returns (address);
// @notice query if the non-reentrancy guard for send() is on
// @return true if the guard is on. false otherwise
function isSendingPayload() external view returns (bool);
// @notice query if the non-reentrancy guard for receive() is on
// @return true if the guard is on. false otherwise
function isReceivingPayload() external view returns (bool);
// @notice get the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _userApplication - the contract address of the user application
// @param _configType - type of configuration. every messaging library has its own convention.
function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);
// @notice get the send() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getSendVersion(address _userApplication) external view returns (uint16);
// @notice get the lzReceive() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getReceiveVersion(address _userApplication) external view returns (uint16);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.0;
import "./ILayerZeroUserApplicationConfig.sol";
interface ILayerZeroMessagingLibrary {
// send(), messages will be inflight.
function send(address _userApplication, uint64 _lastNonce, uint16 _chainId, bytes calldata _destination, bytes calldata _payload, address payable refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
// estimate native fee at the send side
function estimateFees(uint16 _chainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);
//---------------------------------------------------------------------------
// setConfig / getConfig are User Application (UA) functions to specify Oracle, Relayer, blockConfirmations, libraryVersion
function setConfig(uint16 _chainId, address _userApplication, uint _configType, bytes calldata _config) external;
function getConfig(uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface ILayerZeroUserApplicationConfig {
// @notice set the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _configType - type of configuration. every messaging library has its own convention.
// @param _config - configuration in the bytes. can encode arbitrary content.
function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;
// @notice set the send() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setSendVersion(uint16 _version) external;
// @notice set the lzReceive() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setReceiveVersion(uint16 _version) external;
// @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
// @param _srcChainId - the chainId of the source chain
// @param _srcAddress - the contract address of the source contract at the source chain
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <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 GSN 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 payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
File 7 of 7: Bridge
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
// imports
import "@openzeppelin/contracts/access/Ownable.sol";
import "./Pool.sol";
import "./Router.sol";
// interfaces
import "@layerzerolabs/contracts/contracts/interfaces/ILayerZeroReceiver.sol";
import "@layerzerolabs/contracts/contracts/interfaces/ILayerZeroEndpoint.sol";
import "@layerzerolabs/contracts/contracts/interfaces/ILayerZeroUserApplicationConfig.sol";
// libraries
import "@openzeppelin/contracts/math/SafeMath.sol";
contract Bridge is Ownable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {
using SafeMath for uint256;
//---------------------------------------------------------------------------
// CONSTANTS
uint8 internal constant TYPE_SWAP_REMOTE = 1;
uint8 internal constant TYPE_ADD_LIQUIDITY = 2;
uint8 internal constant TYPE_REDEEM_LOCAL_CALL_BACK = 3;
uint8 internal constant TYPE_WITHDRAW_REMOTE = 4;
//---------------------------------------------------------------------------
// VARIABLES
ILayerZeroEndpoint public immutable layerZeroEndpoint;
mapping(uint16 => bytes) public bridgeLookup;
mapping(uint16 => mapping(uint8 => uint256)) public gasLookup;
Router public immutable router;
bool public useLayerZeroToken;
//---------------------------------------------------------------------------
// EVENTS
event SendMsg(uint8 msgType, uint64 nonce);
//---------------------------------------------------------------------------
// MODIFIERS
modifier onlyRouter() {
require(msg.sender == address(router), "Stargate: caller must be Router.");
_;
}
constructor(address _layerZeroEndpoint, address _router) {
require(_layerZeroEndpoint != address(0x0), "Stargate: _layerZeroEndpoint cannot be 0x0");
require(_router != address(0x0), "Stargate: _router cannot be 0x0");
layerZeroEndpoint = ILayerZeroEndpoint(_layerZeroEndpoint);
router = Router(_router);
}
//---------------------------------------------------------------------------
// EXTERNAL functions
function lzReceive(
uint16 _srcChainId,
bytes memory _srcAddress,
uint64 _nonce,
bytes memory _payload
) external override {
require(msg.sender == address(layerZeroEndpoint), "Stargate: only LayerZero endpoint can call lzReceive");
require(
_srcAddress.length == bridgeLookup[_srcChainId].length && keccak256(_srcAddress) == keccak256(bridgeLookup[_srcChainId]),
"Stargate: bridge does not match"
);
uint8 functionType;
assembly {
functionType := mload(add(_payload, 32))
}
if (functionType == TYPE_SWAP_REMOTE) {
(
,
uint256 srcPoolId,
uint256 dstPoolId,
uint256 dstGasForCall,
Pool.CreditObj memory c,
Pool.SwapObj memory s,
bytes memory to,
bytes memory payload
) = abi.decode(_payload, (uint8, uint256, uint256, uint256, Pool.CreditObj, Pool.SwapObj, bytes, bytes));
address toAddress;
assembly {
toAddress := mload(add(to, 20))
}
router.creditChainPath(_srcChainId, srcPoolId, dstPoolId, c);
router.swapRemote(_srcChainId, _srcAddress, _nonce, srcPoolId, dstPoolId, dstGasForCall, toAddress, s, payload);
} else if (functionType == TYPE_ADD_LIQUIDITY) {
(, uint256 srcPoolId, uint256 dstPoolId, Pool.CreditObj memory c) = abi.decode(_payload, (uint8, uint256, uint256, Pool.CreditObj));
router.creditChainPath(_srcChainId, srcPoolId, dstPoolId, c);
} else if (functionType == TYPE_REDEEM_LOCAL_CALL_BACK) {
(, uint256 srcPoolId, uint256 dstPoolId, Pool.CreditObj memory c, uint256 amountSD, uint256 mintAmountSD, bytes memory to) = abi
.decode(_payload, (uint8, uint256, uint256, Pool.CreditObj, uint256, uint256, bytes));
address toAddress;
assembly {
toAddress := mload(add(to, 20))
}
router.creditChainPath(_srcChainId, srcPoolId, dstPoolId, c);
router.redeemLocalCallback(_srcChainId, _srcAddress, _nonce, srcPoolId, dstPoolId, toAddress, amountSD, mintAmountSD);
} else if (functionType == TYPE_WITHDRAW_REMOTE) {
(, uint256 srcPoolId, uint256 dstPoolId, Pool.CreditObj memory c, uint256 amountSD, bytes memory to) = abi.decode(
_payload,
(uint8, uint256, uint256, Pool.CreditObj, uint256, bytes)
);
router.creditChainPath(_srcChainId, srcPoolId, dstPoolId, c);
router.redeemLocalCheckOnRemote(_srcChainId, _srcAddress, _nonce, srcPoolId, dstPoolId, amountSD, to);
}
}
//---------------------------------------------------------------------------
// LOCAL CHAIN FUNCTIONS
function swap(
uint16 _chainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
Pool.CreditObj memory _c,
Pool.SwapObj memory _s,
IStargateRouter.lzTxObj memory _lzTxParams,
bytes calldata _to,
bytes calldata _payload
) external payable onlyRouter {
bytes memory payload = abi.encode(TYPE_SWAP_REMOTE, _srcPoolId, _dstPoolId, _lzTxParams.dstGasForCall, _c, _s, _to, _payload);
_call(_chainId, TYPE_SWAP_REMOTE, _refundAddress, _lzTxParams, payload);
}
function redeemLocalCallback(
uint16 _chainId,
address payable _refundAddress,
Pool.CreditObj memory _c,
IStargateRouter.lzTxObj memory _lzTxParams,
bytes memory _payload
) external payable onlyRouter {
bytes memory payload;
{
(, uint256 srcPoolId, uint256 dstPoolId, uint256 amountSD, uint256 mintAmountSD, bytes memory to) = abi.decode(
_payload,
(uint8, uint256, uint256, uint256, uint256, bytes)
);
// swap dst and src because we are headed back
payload = abi.encode(TYPE_REDEEM_LOCAL_CALL_BACK, dstPoolId, srcPoolId, _c, amountSD, mintAmountSD, to);
}
_call(_chainId, TYPE_REDEEM_LOCAL_CALL_BACK, _refundAddress, _lzTxParams, payload);
}
function redeemLocal(
uint16 _chainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
Pool.CreditObj memory _c,
uint256 _amountSD,
bytes calldata _to,
IStargateRouter.lzTxObj memory _lzTxParams
) external payable onlyRouter {
bytes memory payload = abi.encode(TYPE_WITHDRAW_REMOTE, _srcPoolId, _dstPoolId, _c, _amountSD, _to);
_call(_chainId, TYPE_WITHDRAW_REMOTE, _refundAddress, _lzTxParams, payload);
}
function sendCredits(
uint16 _chainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
Pool.CreditObj memory _c
) external payable onlyRouter {
bytes memory payload = abi.encode(TYPE_ADD_LIQUIDITY, _srcPoolId, _dstPoolId, _c);
IStargateRouter.lzTxObj memory lzTxObj = IStargateRouter.lzTxObj(0, 0, "0x");
_call(_chainId, TYPE_ADD_LIQUIDITY, _refundAddress, lzTxObj, payload);
}
function quoteLayerZeroFee(
uint16 _chainId,
uint8 _functionType,
bytes calldata _toAddress,
bytes calldata _transferAndCallPayload,
IStargateRouter.lzTxObj memory _lzTxParams
) external view returns (uint256, uint256) {
bytes memory payload = "";
Pool.CreditObj memory c = Pool.CreditObj(1, 1);
if (_functionType == TYPE_SWAP_REMOTE) {
Pool.SwapObj memory s = Pool.SwapObj(1, 1, 1, 1, 1, 1);
payload = abi.encode(TYPE_SWAP_REMOTE, 0, 0, 0, c, s, _toAddress, _transferAndCallPayload);
} else if (_functionType == TYPE_ADD_LIQUIDITY) {
payload = abi.encode(TYPE_ADD_LIQUIDITY, 0, 0, c);
} else if (_functionType == TYPE_REDEEM_LOCAL_CALL_BACK) {
payload = abi.encode(TYPE_REDEEM_LOCAL_CALL_BACK, 0, 0, c, 0, 0, _toAddress);
} else if (_functionType == TYPE_WITHDRAW_REMOTE) {
payload = abi.encode(TYPE_WITHDRAW_REMOTE, 0, 0, c, 0, _toAddress);
} else {
revert("Stargate: unsupported function type");
}
bytes memory lzTxParamBuilt = _txParamBuilder(_chainId, _functionType, _lzTxParams);
return layerZeroEndpoint.estimateFees(_chainId, address(this), payload, useLayerZeroToken, lzTxParamBuilt);
}
//---------------------------------------------------------------------------
// dao functions
function setBridge(uint16 _chainId, bytes calldata _bridgeAddress) external onlyOwner {
require(bridgeLookup[_chainId].length == 0, "Stargate: Bridge already set!");
bridgeLookup[_chainId] = _bridgeAddress;
}
function setGasAmount(
uint16 _chainId,
uint8 _functionType,
uint256 _gasAmount
) external onlyOwner {
require(_functionType >= 1 && _functionType <= 4, "Stargate: invalid _functionType");
gasLookup[_chainId][_functionType] = _gasAmount;
}
function approveTokenSpender(
address token,
address spender,
uint256 amount
) external onlyOwner {
IERC20(token).approve(spender, amount);
}
function setUseLayerZeroToken(bool enable) external onlyOwner {
useLayerZeroToken = enable;
}
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {
layerZeroEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
}
//---------------------------------------------------------------------------
// generic config for user Application
function setConfig(
uint16 _version,
uint16 _chainId,
uint256 _configType,
bytes calldata _config
) external override onlyOwner {
layerZeroEndpoint.setConfig(_version, _chainId, _configType, _config);
}
function setSendVersion(uint16 version) external override onlyOwner {
layerZeroEndpoint.setSendVersion(version);
}
function setReceiveVersion(uint16 version) external override onlyOwner {
layerZeroEndpoint.setReceiveVersion(version);
}
//---------------------------------------------------------------------------
// INTERNAL functions
function txParamBuilderType1(uint256 _gasAmount) internal pure returns (bytes memory) {
uint16 txType = 1;
return abi.encodePacked(txType, _gasAmount);
}
function txParamBuilderType2(
uint256 _gasAmount,
uint256 _dstNativeAmount,
bytes memory _dstNativeAddr
) internal pure returns (bytes memory) {
uint16 txType = 2;
return abi.encodePacked(txType, _gasAmount, _dstNativeAmount, _dstNativeAddr);
}
function _txParamBuilder(
uint16 _chainId,
uint8 _type,
IStargateRouter.lzTxObj memory _lzTxParams
) internal view returns (bytes memory) {
bytes memory lzTxParam;
address dstNativeAddr;
{
bytes memory dstNativeAddrBytes = _lzTxParams.dstNativeAddr;
assembly {
dstNativeAddr := mload(add(dstNativeAddrBytes, 20))
}
}
uint256 totalGas = gasLookup[_chainId][_type].add(_lzTxParams.dstGasForCall);
if (_lzTxParams.dstNativeAmount > 0 && dstNativeAddr != address(0x0)) {
lzTxParam = txParamBuilderType2(totalGas, _lzTxParams.dstNativeAmount, _lzTxParams.dstNativeAddr);
} else {
lzTxParam = txParamBuilderType1(totalGas);
}
return lzTxParam;
}
function _call(
uint16 _chainId,
uint8 _type,
address payable _refundAddress,
IStargateRouter.lzTxObj memory _lzTxParams,
bytes memory _payload
) internal {
bytes memory lzTxParamBuilt = _txParamBuilder(_chainId, _type, _lzTxParams);
uint64 nextNonce = layerZeroEndpoint.getOutboundNonce(_chainId, address(this)) + 1;
layerZeroEndpoint.send{value: msg.value}(_chainId, bridgeLookup[_chainId], _payload, _refundAddress, address(this), lzTxParamBuilt);
emit SendMsg(_type, nextNonce);
}
function renounceOwnership() public override onlyOwner {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
// imports
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./LPTokenERC20.sol";
import "./interfaces/IStargateFeeLibrary.sol";
// libraries
import "@openzeppelin/contracts/math/SafeMath.sol";
/// Pool contracts on other chains and managed by the Stargate protocol.
contract Pool is LPTokenERC20, ReentrancyGuard {
using SafeMath for uint256;
//---------------------------------------------------------------------------
// CONSTANTS
bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));
uint256 public constant BP_DENOMINATOR = 10000;
//---------------------------------------------------------------------------
// STRUCTS
struct ChainPath {
bool ready; // indicate if the counter chainPath has been created.
uint16 dstChainId;
uint256 dstPoolId;
uint256 weight;
uint256 balance;
uint256 lkb;
uint256 credits;
uint256 idealBalance;
}
struct SwapObj {
uint256 amount;
uint256 eqFee;
uint256 eqReward;
uint256 lpFee;
uint256 protocolFee;
uint256 lkbRemove;
}
struct CreditObj {
uint256 credits;
uint256 idealBalance;
}
//---------------------------------------------------------------------------
// VARIABLES
// chainPath
ChainPath[] public chainPaths; // list of connected chains with shared pools
mapping(uint16 => mapping(uint256 => uint256)) public chainPathIndexLookup; // lookup for chainPath by chainId => poolId =>index
// metadata
uint256 public immutable poolId; // shared id between chains to represent same pool
uint256 public sharedDecimals; // the shared decimals (lowest common decimals between chains)
uint256 public localDecimals; // the decimals for the token
uint256 public immutable convertRate; // the decimals for the token
address public immutable token; // the token for the pool
address public immutable router; // the token for the pool
bool public stopSwap; // flag to stop swapping in extreme cases
// Fee and Liquidity
uint256 public totalLiquidity; // the total amount of tokens added on this side of the chain (fees + deposits - withdrawals)
uint256 public totalWeight; // total weight for pool percentages
uint256 public mintFeeBP; // fee basis points for the mint/deposit
uint256 public protocolFeeBalance; // fee balance created from dao fee
uint256 public mintFeeBalance; // fee balance created from mint fee
uint256 public eqFeePool; // pool rewards in Shared Decimal format. indicate the total budget for reverse swap incentive
address public feeLibrary; // address for retrieving fee params for swaps
// Delta related
uint256 public deltaCredit; // credits accumulated from txn
bool public batched; // flag to indicate if we want batch processing.
bool public defaultSwapMode; // flag for the default mode for swap
bool public defaultLPMode; // flag for the default mode for lp
uint256 public swapDeltaBP; // basis points of poolCredits to activate Delta in swap
uint256 public lpDeltaBP; // basis points of poolCredits to activate Delta in liquidity events
//---------------------------------------------------------------------------
// EVENTS
event Mint(address to, uint256 amountLP, uint256 amountSD, uint256 mintFeeAmountSD);
event Burn(address from, uint256 amountLP, uint256 amountSD);
event RedeemLocalCallback(address _to, uint256 _amountSD, uint256 _amountToMintSD);
event Swap(
uint16 chainId,
uint256 dstPoolId,
address from,
uint256 amountSD,
uint256 eqReward,
uint256 eqFee,
uint256 protocolFee,
uint256 lpFee
);
event SendCredits(uint16 dstChainId, uint256 dstPoolId, uint256 credits, uint256 idealBalance);
event RedeemRemote(uint16 chainId, uint256 dstPoolId, address from, uint256 amountLP, uint256 amountSD);
event RedeemLocal(address from, uint256 amountLP, uint256 amountSD, uint16 chainId, uint256 dstPoolId, bytes to);
event InstantRedeemLocal(address from, uint256 amountLP, uint256 amountSD, address to);
event CreditChainPath(uint16 chainId, uint256 srcPoolId, uint256 amountSD, uint256 idealBalance);
event SwapRemote(address to, uint256 amountSD, uint256 protocolFee, uint256 dstFee);
event WithdrawRemote(uint16 srcChainId, uint256 srcPoolId, uint256 swapAmount, uint256 mintAmount);
event ChainPathUpdate(uint16 dstChainId, uint256 dstPoolId, uint256 weight);
event FeesUpdated(uint256 mintFeeBP);
event FeeLibraryUpdated(address feeLibraryAddr);
event StopSwapUpdated(bool swapStop);
event WithdrawProtocolFeeBalance(address to, uint256 amountSD);
event WithdrawMintFeeBalance(address to, uint256 amountSD);
event DeltaParamUpdated(bool batched, uint256 swapDeltaBP, uint256 lpDeltaBP, bool defaultSwapMode, bool defaultLPMode);
//---------------------------------------------------------------------------
// MODIFIERS
modifier onlyRouter() {
require(msg.sender == router, "Stargate: only the router can call this method");
_;
}
constructor(
uint256 _poolId,
address _router,
address _token,
uint256 _sharedDecimals,
uint256 _localDecimals,
address _feeLibrary,
string memory _name,
string memory _symbol
) LPTokenERC20(_name, _symbol) {
require(_token != address(0x0), "Stargate: _token cannot be 0x0");
require(_router != address(0x0), "Stargate: _router cannot be 0x0");
poolId = _poolId;
router = _router;
token = _token;
sharedDecimals = _sharedDecimals;
decimals = uint8(_sharedDecimals);
localDecimals = _localDecimals;
convertRate = 10**(uint256(localDecimals).sub(sharedDecimals));
totalWeight = 0;
feeLibrary = _feeLibrary;
//delta algo related
batched = false;
defaultSwapMode = true;
defaultLPMode = true;
}
function getChainPathsLength() public view returns (uint256) {
return chainPaths.length;
}
//---------------------------------------------------------------------------
// LOCAL CHAIN FUNCTIONS
function mint(address _to, uint256 _amountLD) external nonReentrant onlyRouter returns (uint256) {
return _mintLocal(_to, _amountLD, true, true);
}
// Local Remote
// ------- ---------
// swap -> swapRemote
function swap(
uint16 _dstChainId,
uint256 _dstPoolId,
address _from,
uint256 _amountLD,
uint256 _minAmountLD,
bool newLiquidity
) external nonReentrant onlyRouter returns (SwapObj memory) {
require(!stopSwap, "Stargate: swap func stopped");
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
require(cp.ready == true, "Stargate: counter chainPath is not ready");
uint256 amountSD = amountLDtoSD(_amountLD);
uint256 minAmountSD = amountLDtoSD(_minAmountLD);
// request fee params from library
SwapObj memory s = IStargateFeeLibrary(feeLibrary).getFees(poolId, _dstPoolId, _dstChainId, _from, amountSD);
// equilibrium fee and reward. note eqFee/eqReward are separated from swap liquidity
eqFeePool = eqFeePool.sub(s.eqReward);
// update the new amount the user gets minus the fees
s.amount = amountSD.sub(s.eqFee).sub(s.protocolFee).sub(s.lpFee);
// users will also get the eqReward
require(s.amount.add(s.eqReward) >= minAmountSD, "Stargate: slippage too high");
// behaviours
// - protocolFee: booked, stayed and withdrawn at remote.
// - eqFee: booked, stayed and withdrawn at remote.
// - lpFee: booked and stayed at remote, can be withdrawn anywhere
s.lkbRemove = amountSD.sub(s.lpFee).add(s.eqReward);
// check for transfer solvency.
require(cp.balance >= s.lkbRemove, "Stargate: dst balance too low");
cp.balance = cp.balance.sub(s.lkbRemove);
if (newLiquidity) {
deltaCredit = deltaCredit.add(amountSD).add(s.eqReward);
} else if (s.eqReward > 0) {
deltaCredit = deltaCredit.add(s.eqReward);
}
// distribute credits on condition.
if (!batched || deltaCredit >= totalLiquidity.mul(swapDeltaBP).div(BP_DENOMINATOR)) {
_delta(defaultSwapMode);
}
emit Swap(_dstChainId, _dstPoolId, _from, s.amount, s.eqReward, s.eqFee, s.protocolFee, s.lpFee);
return s;
}
// Local Remote
// ------- ---------
// sendCredits -> creditChainPath
function sendCredits(uint16 _dstChainId, uint256 _dstPoolId) external nonReentrant onlyRouter returns (CreditObj memory c) {
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
require(cp.ready == true, "Stargate: counter chainPath is not ready");
cp.lkb = cp.lkb.add(cp.credits);
c.idealBalance = totalLiquidity.mul(cp.weight).div(totalWeight);
c.credits = cp.credits;
cp.credits = 0;
emit SendCredits(_dstChainId, _dstPoolId, c.credits, c.idealBalance);
}
// Local Remote
// ------- ---------
// redeemRemote -> swapRemote
function redeemRemote(
uint16 _dstChainId,
uint256 _dstPoolId,
address _from,
uint256 _amountLP
) external nonReentrant onlyRouter {
require(_from != address(0x0), "Stargate: _from cannot be 0x0");
uint256 amountSD = _burnLocal(_from, _amountLP);
//run Delta
if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
_delta(defaultLPMode);
}
uint256 amountLD = amountSDtoLD(amountSD);
emit RedeemRemote(_dstChainId, _dstPoolId, _from, _amountLP, amountLD);
}
function instantRedeemLocal(
address _from,
uint256 _amountLP,
address _to
) external nonReentrant onlyRouter returns (uint256 amountSD) {
require(_from != address(0x0), "Stargate: _from cannot be 0x0");
uint256 _deltaCredit = deltaCredit; // sload optimization.
uint256 _capAmountLP = _amountSDtoLP(_deltaCredit);
if (_amountLP > _capAmountLP) _amountLP = _capAmountLP;
amountSD = _burnLocal(_from, _amountLP);
deltaCredit = _deltaCredit.sub(amountSD);
uint256 amountLD = amountSDtoLD(amountSD);
_safeTransfer(token, _to, amountLD);
emit InstantRedeemLocal(_from, _amountLP, amountSD, _to);
}
// Local Remote
// ------- ---------
// redeemLocal -> redeemLocalCheckOnRemote
// redeemLocalCallback <-
function redeemLocal(
address _from,
uint256 _amountLP,
uint16 _dstChainId,
uint256 _dstPoolId,
bytes calldata _to
) external nonReentrant onlyRouter returns (uint256 amountSD) {
require(_from != address(0x0), "Stargate: _from cannot be 0x0");
// safeguard.
require(chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]].ready == true, "Stargate: counter chainPath is not ready");
amountSD = _burnLocal(_from, _amountLP);
// run Delta
if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
_delta(false);
}
emit RedeemLocal(_from, _amountLP, amountSD, _dstChainId, _dstPoolId, _to);
}
//---------------------------------------------------------------------------
// REMOTE CHAIN FUNCTIONS
// Local Remote
// ------- ---------
// sendCredits -> creditChainPath
function creditChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
CreditObj memory _c
) external nonReentrant onlyRouter {
ChainPath storage cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
cp.balance = cp.balance.add(_c.credits);
if (cp.idealBalance != _c.idealBalance) {
cp.idealBalance = _c.idealBalance;
}
emit CreditChainPath(_dstChainId, _dstPoolId, _c.credits, _c.idealBalance);
}
// Local Remote
// ------- ---------
// swap -> swapRemote
function swapRemote(
uint16 _srcChainId,
uint256 _srcPoolId,
address _to,
SwapObj memory _s
) external nonReentrant onlyRouter returns (uint256 amountLD) {
// booking lpFee
totalLiquidity = totalLiquidity.add(_s.lpFee);
// booking eqFee
eqFeePool = eqFeePool.add(_s.eqFee);
// booking stargateFee
protocolFeeBalance = protocolFeeBalance.add(_s.protocolFee);
// update LKB
uint256 chainPathIndex = chainPathIndexLookup[_srcChainId][_srcPoolId];
chainPaths[chainPathIndex].lkb = chainPaths[chainPathIndex].lkb.sub(_s.lkbRemove);
// user receives the amount + the srcReward
amountLD = amountSDtoLD(_s.amount.add(_s.eqReward));
_safeTransfer(token, _to, amountLD);
emit SwapRemote(_to, _s.amount.add(_s.eqReward), _s.protocolFee, _s.eqFee);
}
// Local Remote
// ------- ---------
// redeemLocal -> redeemLocalCheckOnRemote
// redeemLocalCallback <-
function redeemLocalCallback(
uint16 _srcChainId,
uint256 _srcPoolId,
address _to,
uint256 _amountSD,
uint256 _amountToMintSD
) external nonReentrant onlyRouter {
if (_amountToMintSD > 0) {
_mintLocal(_to, amountSDtoLD(_amountToMintSD), false, false);
}
ChainPath storage cp = getAndCheckCP(_srcChainId, _srcPoolId);
cp.lkb = cp.lkb.sub(_amountSD);
uint256 amountLD = amountSDtoLD(_amountSD);
_safeTransfer(token, _to, amountLD);
emit RedeemLocalCallback(_to, _amountSD, _amountToMintSD);
}
// Local Remote
// ------- ---------
// redeemLocal(amount) -> redeemLocalCheckOnRemote
// redeemLocalCallback <-
function redeemLocalCheckOnRemote(
uint16 _srcChainId,
uint256 _srcPoolId,
uint256 _amountSD
) external nonReentrant onlyRouter returns (uint256 swapAmount, uint256 mintAmount) {
ChainPath storage cp = getAndCheckCP(_srcChainId, _srcPoolId);
if (_amountSD > cp.balance) {
mintAmount = _amountSD - cp.balance;
swapAmount = cp.balance;
cp.balance = 0;
} else {
cp.balance = cp.balance.sub(_amountSD);
swapAmount = _amountSD;
mintAmount = 0;
}
emit WithdrawRemote(_srcChainId, _srcPoolId, swapAmount, mintAmount);
}
//---------------------------------------------------------------------------
// DAO Calls
function createChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
uint256 _weight
) external onlyRouter {
for (uint256 i = 0; i < chainPaths.length; ++i) {
ChainPath memory cp = chainPaths[i];
bool exists = cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId;
require(!exists, "Stargate: cant createChainPath of existing dstChainId and _dstPoolId");
}
totalWeight = totalWeight.add(_weight);
chainPathIndexLookup[_dstChainId][_dstPoolId] = chainPaths.length;
chainPaths.push(ChainPath(false, _dstChainId, _dstPoolId, _weight, 0, 0, 0, 0));
emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
}
function setWeightForChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
uint16 _weight
) external onlyRouter {
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
totalWeight = totalWeight.sub(cp.weight).add(_weight);
cp.weight = _weight;
emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
}
function setFee(uint256 _mintFeeBP) external onlyRouter {
require(_mintFeeBP <= BP_DENOMINATOR, "Bridge: cum fees > 100%");
mintFeeBP = _mintFeeBP;
emit FeesUpdated(mintFeeBP);
}
function setFeeLibrary(address _feeLibraryAddr) external onlyRouter {
require(_feeLibraryAddr != address(0x0), "Stargate: fee library cant be 0x0");
feeLibrary = _feeLibraryAddr;
emit FeeLibraryUpdated(_feeLibraryAddr);
}
function setSwapStop(bool _swapStop) external onlyRouter {
stopSwap = _swapStop;
emit StopSwapUpdated(_swapStop);
}
function setDeltaParam(
bool _batched,
uint256 _swapDeltaBP,
uint256 _lpDeltaBP,
bool _defaultSwapMode,
bool _defaultLPMode
) external onlyRouter {
require(_swapDeltaBP <= BP_DENOMINATOR && _lpDeltaBP <= BP_DENOMINATOR, "Stargate: wrong Delta param");
batched = _batched;
swapDeltaBP = _swapDeltaBP;
lpDeltaBP = _lpDeltaBP;
defaultSwapMode = _defaultSwapMode;
defaultLPMode = _defaultLPMode;
emit DeltaParamUpdated(_batched, _swapDeltaBP, _lpDeltaBP, _defaultSwapMode, _defaultLPMode);
}
function callDelta(bool _fullMode) external onlyRouter {
_delta(_fullMode);
}
function activateChainPath(uint16 _dstChainId, uint256 _dstPoolId) external onlyRouter {
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
require(cp.ready == false, "Stargate: chainPath is already active");
// this func will only be called once
cp.ready = true;
}
function withdrawProtocolFeeBalance(address _to) external onlyRouter {
if (protocolFeeBalance > 0) {
uint256 amountOfLD = amountSDtoLD(protocolFeeBalance);
protocolFeeBalance = 0;
_safeTransfer(token, _to, amountOfLD);
emit WithdrawProtocolFeeBalance(_to, amountOfLD);
}
}
function withdrawMintFeeBalance(address _to) external onlyRouter {
if (mintFeeBalance > 0) {
uint256 amountOfLD = amountSDtoLD(mintFeeBalance);
mintFeeBalance = 0;
_safeTransfer(token, _to, amountOfLD);
emit WithdrawMintFeeBalance(_to, amountOfLD);
}
}
//---------------------------------------------------------------------------
// INTERNAL
// Conversion Helpers
//---------------------------------------------------------------------------
function amountLPtoLD(uint256 _amountLP) external view returns (uint256) {
return amountSDtoLD(_amountLPtoSD(_amountLP));
}
function _amountLPtoSD(uint256 _amountLP) internal view returns (uint256) {
require(totalSupply > 0, "Stargate: cant convert LPtoSD when totalSupply == 0");
return _amountLP.mul(totalLiquidity).div(totalSupply);
}
function _amountSDtoLP(uint256 _amountSD) internal view returns (uint256) {
require(totalLiquidity > 0, "Stargate: cant convert SDtoLP when totalLiq == 0");
return _amountSD.mul(totalSupply).div(totalLiquidity);
}
function amountSDtoLD(uint256 _amount) internal view returns (uint256) {
return _amount.mul(convertRate);
}
function amountLDtoSD(uint256 _amount) internal view returns (uint256) {
return _amount.div(convertRate);
}
function getAndCheckCP(uint16 _dstChainId, uint256 _dstPoolId) internal view returns (ChainPath storage) {
require(chainPaths.length > 0, "Stargate: no chainpaths exist");
ChainPath storage cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
require(cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId, "Stargate: local chainPath does not exist");
return cp;
}
function getChainPath(uint16 _dstChainId, uint256 _dstPoolId) external view returns (ChainPath memory) {
ChainPath memory cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
require(cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId, "Stargate: local chainPath does not exist");
return cp;
}
function _burnLocal(address _from, uint256 _amountLP) internal returns (uint256) {
require(totalSupply > 0, "Stargate: cant burn when totalSupply == 0");
uint256 amountOfLPTokens = balanceOf[_from];
require(amountOfLPTokens >= _amountLP, "Stargate: not enough LP tokens to burn");
uint256 amountSD = _amountLP.mul(totalLiquidity).div(totalSupply);
//subtract totalLiquidity accordingly
totalLiquidity = totalLiquidity.sub(amountSD);
_burn(_from, _amountLP);
emit Burn(_from, _amountLP, amountSD);
return amountSD;
}
function _delta(bool fullMode) internal {
if (deltaCredit > 0 && totalWeight > 0) {
uint256 cpLength = chainPaths.length;
uint256[] memory deficit = new uint256[](cpLength);
uint256 totalDeficit = 0;
// algorithm steps 6-9: calculate the total and the amounts required to get to balance state
for (uint256 i = 0; i < cpLength; ++i) {
ChainPath storage cp = chainPaths[i];
// (liquidity * (weight/totalWeight)) - (lkb+credits)
uint256 balLiq = totalLiquidity.mul(cp.weight).div(totalWeight);
uint256 currLiq = cp.lkb.add(cp.credits);
if (balLiq > currLiq) {
// save gas since we know balLiq > currLiq and we know deficit[i] > 0
deficit[i] = balLiq - currLiq;
totalDeficit = totalDeficit.add(deficit[i]);
}
}
// indicates how much delta credit is distributed
uint256 spent;
// handle credits with 2 tranches. the [ < totalDeficit] [excessCredit]
// run full Delta, allocate all credits
if (totalDeficit == 0) {
// only fullMode delta will allocate excess credits
if (fullMode && deltaCredit > 0) {
// credit ChainPath by weights
for (uint256 i = 0; i < cpLength; ++i) {
ChainPath storage cp = chainPaths[i];
// credits = credits + toBalanceChange + remaining allocation based on weight
uint256 amtToCredit = deltaCredit.mul(cp.weight).div(totalWeight);
spent = spent.add(amtToCredit);
cp.credits = cp.credits.add(amtToCredit);
}
} // else do nth
} else if (totalDeficit <= deltaCredit) {
if (fullMode) {
// algorithm step 13: calculate amount to disperse to bring to balance state or as close as possible
uint256 excessCredit = deltaCredit - totalDeficit;
// algorithm steps 14-16: calculate credits
for (uint256 i = 0; i < cpLength; ++i) {
if (deficit[i] > 0) {
ChainPath storage cp = chainPaths[i];
// credits = credits + deficit + remaining allocation based on weight
uint256 amtToCredit = deficit[i].add(excessCredit.mul(cp.weight).div(totalWeight));
spent = spent.add(amtToCredit);
cp.credits = cp.credits.add(amtToCredit);
}
}
} else {
// totalDeficit <= deltaCredit but not running fullMode
// credit chainPaths as is if any deficit, not using all deltaCredit
for (uint256 i = 0; i < cpLength; ++i) {
if (deficit[i] > 0) {
ChainPath storage cp = chainPaths[i];
uint256 amtToCredit = deficit[i];
spent = spent.add(amtToCredit);
cp.credits = cp.credits.add(amtToCredit);
}
}
}
} else {
// totalDeficit > deltaCredit, fullMode or not, normalize the deficit by deltaCredit
for (uint256 i = 0; i < cpLength; ++i) {
if (deficit[i] > 0) {
ChainPath storage cp = chainPaths[i];
uint256 proportionalDeficit = deficit[i].mul(deltaCredit).div(totalDeficit);
spent = spent.add(proportionalDeficit);
cp.credits = cp.credits.add(proportionalDeficit);
}
}
}
// deduct the amount of credit sent
deltaCredit = deltaCredit.sub(spent);
}
}
function _mintLocal(
address _to,
uint256 _amountLD,
bool _feesEnabled,
bool _creditDelta
) internal returns (uint256 amountSD) {
require(totalWeight > 0, "Stargate: No ChainPaths exist");
amountSD = amountLDtoSD(_amountLD);
uint256 mintFeeSD = 0;
if (_feesEnabled) {
mintFeeSD = amountSD.mul(mintFeeBP).div(BP_DENOMINATOR);
amountSD = amountSD.sub(mintFeeSD);
mintFeeBalance = mintFeeBalance.add(mintFeeSD);
}
if (_creditDelta) {
deltaCredit = deltaCredit.add(amountSD);
}
uint256 amountLPTokens = amountSD;
if (totalSupply != 0) {
amountLPTokens = amountSD.mul(totalSupply).div(totalLiquidity);
}
totalLiquidity = totalLiquidity.add(amountSD);
_mint(_to, amountLPTokens);
emit Mint(_to, amountLPTokens, amountSD, mintFeeSD);
// add to credits and call delta. short circuit to save gas
if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
_delta(defaultLPMode);
}
}
function _safeTransfer(
address _token,
address _to,
uint256 _value
) private {
(bool success, bytes memory data) = _token.call(abi.encodeWithSelector(SELECTOR, _to, _value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "Stargate: TRANSFER_FAILED");
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
// imports
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./Factory.sol";
import "./Pool.sol";
import "./Bridge.sol";
// interfaces
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/IStargateRouter.sol";
import "./interfaces/IStargateReceiver.sol";
// libraries
import "@openzeppelin/contracts/math/SafeMath.sol";
contract Router is IStargateRouter, Ownable, ReentrancyGuard {
using SafeMath for uint256;
//---------------------------------------------------------------------------
// CONSTANTS
uint8 internal constant TYPE_REDEEM_LOCAL_RESPONSE = 1;
uint8 internal constant TYPE_REDEEM_LOCAL_CALLBACK_RETRY = 2;
uint8 internal constant TYPE_SWAP_REMOTE_RETRY = 3;
//---------------------------------------------------------------------------
// STRUCTS
struct CachedSwap {
address token;
uint256 amountLD;
address to;
bytes payload;
}
//---------------------------------------------------------------------------
// VARIABLES
Factory public factory; // used for creating pools
address public protocolFeeOwner; // can call methods to pull Stargate fees collected in pools
address public mintFeeOwner; // can call methods to pull mint fees collected in pools
Bridge public bridge;
mapping(uint16 => mapping(bytes => mapping(uint256 => bytes))) public revertLookup; //[chainId][srcAddress][nonce]
mapping(uint16 => mapping(bytes => mapping(uint256 => CachedSwap))) public cachedSwapLookup; //[chainId][srcAddress][nonce]
//---------------------------------------------------------------------------
// EVENTS
event Revert(uint8 bridgeFunctionType, uint16 chainId, bytes srcAddress, uint256 nonce);
event CachedSwapSaved(uint16 chainId, bytes srcAddress, uint256 nonce, address token, uint256 amountLD, address to, bytes payload, bytes reason);
event RevertRedeemLocal(uint16 srcChainId, uint256 _srcPoolId, uint256 _dstPoolId, bytes to, uint256 redeemAmountSD, uint256 mintAmountSD, uint256 indexed nonce, bytes indexed srcAddress);
event RedeemLocalCallback(uint16 srcChainId, bytes indexed srcAddress, uint256 indexed nonce, uint256 srcPoolId, uint256 dstPoolId, address to, uint256 amountSD, uint256 mintAmountSD);
//---------------------------------------------------------------------------
// MODIFIERS
modifier onlyBridge() {
require(msg.sender == address(bridge), "Bridge: caller must be Bridge.");
_;
}
constructor() {}
function setBridgeAndFactory(Bridge _bridge, Factory _factory) external onlyOwner {
require(address(bridge) == address(0x0) && address(factory) == address(0x0), "Stargate: bridge and factory already initialized"); // 1 time only
require(address(_bridge) != address(0x0), "Stargate: bridge cant be 0x0");
require(address(_factory) != address(0x0), "Stargate: factory cant be 0x0");
bridge = _bridge;
factory = _factory;
}
//---------------------------------------------------------------------------
// VIEWS
function _getPool(uint256 _poolId) internal view returns (Pool pool) {
pool = factory.getPool(_poolId);
require(address(pool) != address(0x0), "Stargate: Pool does not exist");
}
//---------------------------------------------------------------------------
// INTERNAL
function _safeTransferFrom(
address token,
address from,
address to,
uint256 value
) private {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "Stargate: TRANSFER_FROM_FAILED");
}
//---------------------------------------------------------------------------
// LOCAL CHAIN FUNCTIONS
function addLiquidity(
uint256 _poolId,
uint256 _amountLD,
address _to
) external override nonReentrant {
Pool pool = _getPool(_poolId);
uint256 convertRate = pool.convertRate();
_amountLD = _amountLD.div(convertRate).mul(convertRate);
_safeTransferFrom(pool.token(), msg.sender, address(pool), _amountLD);
pool.mint(_to, _amountLD);
}
function swap(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLD,
uint256 _minAmountLD,
lzTxObj memory _lzTxParams,
bytes calldata _to,
bytes calldata _payload
) external payable override nonReentrant {
require(_amountLD > 0, "Stargate: cannot swap 0");
require(_refundAddress != address(0x0), "Stargate: _refundAddress cannot be 0x0");
Pool.SwapObj memory s;
Pool.CreditObj memory c;
{
Pool pool = _getPool(_srcPoolId);
{
uint256 convertRate = pool.convertRate();
_amountLD = _amountLD.div(convertRate).mul(convertRate);
}
s = pool.swap(_dstChainId, _dstPoolId, msg.sender, _amountLD, _minAmountLD, true);
_safeTransferFrom(pool.token(), msg.sender, address(pool), _amountLD);
c = pool.sendCredits(_dstChainId, _dstPoolId);
}
bridge.swap{value: msg.value}(_dstChainId, _srcPoolId, _dstPoolId, _refundAddress, c, s, _lzTxParams, _to, _payload);
}
function redeemRemote(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
uint256 _minAmountLD,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external payable override nonReentrant {
require(_refundAddress != address(0x0), "Stargate: _refundAddress cannot be 0x0");
require(_amountLP > 0, "Stargate: not enough lp to redeemRemote");
Pool.SwapObj memory s;
Pool.CreditObj memory c;
{
Pool pool = _getPool(_srcPoolId);
uint256 amountLD = pool.amountLPtoLD(_amountLP);
// perform a swap with no liquidity
s = pool.swap(_dstChainId, _dstPoolId, msg.sender, amountLD, _minAmountLD, false);
pool.redeemRemote(_dstChainId, _dstPoolId, msg.sender, _amountLP);
c = pool.sendCredits(_dstChainId, _dstPoolId);
}
// equal to a swap, with no payload ("0x") no dstGasForCall 0
bridge.swap{value: msg.value}(_dstChainId, _srcPoolId, _dstPoolId, _refundAddress, c, s, _lzTxParams, _to, "");
}
function instantRedeemLocal(
uint16 _srcPoolId,
uint256 _amountLP,
address _to
) external override nonReentrant returns (uint256 amountSD) {
require(_amountLP > 0, "Stargate: not enough lp to redeem");
Pool pool = _getPool(_srcPoolId);
amountSD = pool.instantRedeemLocal(msg.sender, _amountLP, _to);
}
function redeemLocal(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external payable override nonReentrant {
require(_refundAddress != address(0x0), "Stargate: _refundAddress cannot be 0x0");
Pool pool = _getPool(_srcPoolId);
require(_amountLP > 0, "Stargate: not enough lp to redeem");
uint256 amountSD = pool.redeemLocal(msg.sender, _amountLP, _dstChainId, _dstPoolId, _to);
require(amountSD > 0, "Stargate: not enough lp to redeem with amountSD");
Pool.CreditObj memory c = pool.sendCredits(_dstChainId, _dstPoolId);
bridge.redeemLocal{value: msg.value}(_dstChainId, _srcPoolId, _dstPoolId, _refundAddress, c, amountSD, _to, _lzTxParams);
}
function sendCredits(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress
) external payable override nonReentrant {
require(_refundAddress != address(0x0), "Stargate: _refundAddress cannot be 0x0");
Pool pool = _getPool(_srcPoolId);
Pool.CreditObj memory c = pool.sendCredits(_dstChainId, _dstPoolId);
bridge.sendCredits{value: msg.value}(_dstChainId, _srcPoolId, _dstPoolId, _refundAddress, c);
}
function quoteLayerZeroFee(
uint16 _dstChainId,
uint8 _functionType,
bytes calldata _toAddress,
bytes calldata _transferAndCallPayload,
Router.lzTxObj memory _lzTxParams
) external view override returns (uint256, uint256) {
return bridge.quoteLayerZeroFee(_dstChainId, _functionType, _toAddress, _transferAndCallPayload, _lzTxParams);
}
function revertRedeemLocal(
uint16 _dstChainId,
bytes calldata _srcAddress,
uint256 _nonce,
address payable _refundAddress,
lzTxObj memory _lzTxParams
) external payable {
require(_refundAddress != address(0x0), "Stargate: _refundAddress cannot be 0x0");
bytes memory payload = revertLookup[_dstChainId][_srcAddress][_nonce];
require(payload.length > 0, "Stargate: no retry revert");
{
uint8 functionType;
assembly {
functionType := mload(add(payload, 32))
}
require(functionType == TYPE_REDEEM_LOCAL_RESPONSE, "Stargate: invalid function type");
}
// empty it
revertLookup[_dstChainId][_srcAddress][_nonce] = "";
uint256 srcPoolId;
uint256 dstPoolId;
assembly {
srcPoolId := mload(add(payload, 64))
dstPoolId := mload(add(payload, 96))
}
Pool.CreditObj memory c;
{
Pool pool = _getPool(dstPoolId);
c = pool.sendCredits(_dstChainId, srcPoolId);
}
bridge.redeemLocalCallback{value: msg.value}(_dstChainId, _refundAddress, c, _lzTxParams, payload);
}
function retryRevert(
uint16 _srcChainId,
bytes calldata _srcAddress,
uint256 _nonce
) external payable {
bytes memory payload = revertLookup[_srcChainId][_srcAddress][_nonce];
require(payload.length > 0, "Stargate: no retry revert");
// empty it
revertLookup[_srcChainId][_srcAddress][_nonce] = "";
uint8 functionType;
assembly {
functionType := mload(add(payload, 32))
}
if (functionType == TYPE_REDEEM_LOCAL_CALLBACK_RETRY) {
(, uint256 srcPoolId, uint256 dstPoolId, address to, uint256 amountSD, uint256 mintAmountSD) = abi.decode(
payload,
(uint8, uint256, uint256, address, uint256, uint256)
);
_redeemLocalCallback(_srcChainId, _srcAddress, _nonce, srcPoolId, dstPoolId, to, amountSD, mintAmountSD);
}
// for retrying the swapRemote. if it fails again, retry
else if (functionType == TYPE_SWAP_REMOTE_RETRY) {
(, uint256 srcPoolId, uint256 dstPoolId, uint256 dstGasForCall, address to, Pool.SwapObj memory s, bytes memory p) = abi.decode(
payload,
(uint8, uint256, uint256, uint256, address, Pool.SwapObj, bytes)
);
_swapRemote(_srcChainId, _srcAddress, _nonce, srcPoolId, dstPoolId, dstGasForCall, to, s, p);
} else {
revert("Stargate: invalid function type");
}
}
function clearCachedSwap(
uint16 _srcChainId,
bytes calldata _srcAddress,
uint256 _nonce
) external {
CachedSwap memory cs = cachedSwapLookup[_srcChainId][_srcAddress][_nonce];
require(cs.to != address(0x0), "Stargate: cache already cleared");
// clear the data
cachedSwapLookup[_srcChainId][_srcAddress][_nonce] = CachedSwap(address(0x0), 0, address(0x0), "");
IStargateReceiver(cs.to).sgReceive(_srcChainId, _srcAddress, _nonce, cs.token, cs.amountLD, cs.payload);
}
function creditChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
uint256 _srcPoolId,
Pool.CreditObj memory _c
) external onlyBridge {
Pool pool = _getPool(_srcPoolId);
pool.creditChainPath(_dstChainId, _dstPoolId, _c);
}
//---------------------------------------------------------------------------
// REMOTE CHAIN FUNCTIONS
function redeemLocalCheckOnRemote(
uint16 _srcChainId,
bytes memory _srcAddress,
uint256 _nonce,
uint256 _srcPoolId,
uint256 _dstPoolId,
uint256 _amountSD,
bytes calldata _to
) external onlyBridge {
Pool pool = _getPool(_dstPoolId);
try pool.redeemLocalCheckOnRemote(_srcChainId, _srcPoolId, _amountSD) returns (uint256 redeemAmountSD, uint256 mintAmountSD) {
revertLookup[_srcChainId][_srcAddress][_nonce] = abi.encode(
TYPE_REDEEM_LOCAL_RESPONSE,
_srcPoolId,
_dstPoolId,
redeemAmountSD,
mintAmountSD,
_to
);
emit RevertRedeemLocal(_srcChainId, _srcPoolId, _dstPoolId, _to, redeemAmountSD, mintAmountSD, _nonce, _srcAddress);
} catch {
// if the func fail, return [swapAmount: 0, mintAMount: _amountSD]
// swapAmount represents the amount of chainPath balance deducted on the remote side, which because the above tx failed, should be 0
// mintAmount is the full amount of tokens the user attempted to redeem on the src side, which gets converted back into the lp amount
revertLookup[_srcChainId][_srcAddress][_nonce] = abi.encode(TYPE_REDEEM_LOCAL_RESPONSE, _srcPoolId, _dstPoolId, 0, _amountSD, _to);
emit Revert(TYPE_REDEEM_LOCAL_RESPONSE, _srcChainId, _srcAddress, _nonce);
}
}
function redeemLocalCallback(
uint16 _srcChainId,
bytes memory _srcAddress,
uint256 _nonce,
uint256 _srcPoolId,
uint256 _dstPoolId,
address _to,
uint256 _amountSD,
uint256 _mintAmountSD
) external onlyBridge {
_redeemLocalCallback(_srcChainId, _srcAddress, _nonce, _srcPoolId, _dstPoolId, _to, _amountSD, _mintAmountSD);
}
function _redeemLocalCallback(
uint16 _srcChainId,
bytes memory _srcAddress,
uint256 _nonce,
uint256 _srcPoolId,
uint256 _dstPoolId,
address _to,
uint256 _amountSD,
uint256 _mintAmountSD
) internal {
Pool pool = _getPool(_dstPoolId);
try pool.redeemLocalCallback(_srcChainId, _srcPoolId, _to, _amountSD, _mintAmountSD) {} catch {
revertLookup[_srcChainId][_srcAddress][_nonce] = abi.encode(
TYPE_REDEEM_LOCAL_CALLBACK_RETRY,
_srcPoolId,
_dstPoolId,
_to,
_amountSD,
_mintAmountSD
);
emit Revert(TYPE_REDEEM_LOCAL_CALLBACK_RETRY, _srcChainId, _srcAddress, _nonce);
}
emit RedeemLocalCallback(_srcChainId, _srcAddress, _nonce, _srcPoolId, _dstPoolId, _to, _amountSD, _mintAmountSD);
}
function swapRemote(
uint16 _srcChainId,
bytes memory _srcAddress,
uint256 _nonce,
uint256 _srcPoolId,
uint256 _dstPoolId,
uint256 _dstGasForCall,
address _to,
Pool.SwapObj memory _s,
bytes memory _payload
) external onlyBridge {
_swapRemote(_srcChainId, _srcAddress, _nonce, _srcPoolId, _dstPoolId, _dstGasForCall, _to, _s, _payload);
}
function _swapRemote(
uint16 _srcChainId,
bytes memory _srcAddress,
uint256 _nonce,
uint256 _srcPoolId,
uint256 _dstPoolId,
uint256 _dstGasForCall,
address _to,
Pool.SwapObj memory _s,
bytes memory _payload
) internal {
Pool pool = _getPool(_dstPoolId);
// first try catch the swap remote
try pool.swapRemote(_srcChainId, _srcPoolId, _to, _s) returns (uint256 amountLD) {
if (_payload.length > 0) {
// then try catch the external contract call
try IStargateReceiver(_to).sgReceive{gas: _dstGasForCall}(_srcChainId, _srcAddress, _nonce, pool.token(), amountLD, _payload) {
// do nothing
} catch (bytes memory reason) {
cachedSwapLookup[_srcChainId][_srcAddress][_nonce] = CachedSwap(pool.token(), amountLD, _to, _payload);
emit CachedSwapSaved(_srcChainId, _srcAddress, _nonce, pool.token(), amountLD, _to, _payload, reason);
}
}
} catch {
revertLookup[_srcChainId][_srcAddress][_nonce] = abi.encode(
TYPE_SWAP_REMOTE_RETRY,
_srcPoolId,
_dstPoolId,
_dstGasForCall,
_to,
_s,
_payload
);
emit Revert(TYPE_SWAP_REMOTE_RETRY, _srcChainId, _srcAddress, _nonce);
}
}
//---------------------------------------------------------------------------
// DAO Calls
function createPool(
uint256 _poolId,
address _token,
uint8 _sharedDecimals,
uint8 _localDecimals,
string memory _name,
string memory _symbol
) external onlyOwner returns (address) {
require(_token != address(0x0), "Stargate: _token cannot be 0x0");
return factory.createPool(_poolId, _token, _sharedDecimals, _localDecimals, _name, _symbol);
}
function createChainPath(
uint256 _poolId,
uint16 _dstChainId,
uint256 _dstPoolId,
uint256 _weight
) external onlyOwner {
Pool pool = _getPool(_poolId);
pool.createChainPath(_dstChainId, _dstPoolId, _weight);
}
function activateChainPath(
uint256 _poolId,
uint16 _dstChainId,
uint256 _dstPoolId
) external onlyOwner {
Pool pool = _getPool(_poolId);
pool.activateChainPath(_dstChainId, _dstPoolId);
}
function setWeightForChainPath(
uint256 _poolId,
uint16 _dstChainId,
uint256 _dstPoolId,
uint16 _weight
) external onlyOwner {
Pool pool = _getPool(_poolId);
pool.setWeightForChainPath(_dstChainId, _dstPoolId, _weight);
}
function setProtocolFeeOwner(address _owner) external onlyOwner {
require(_owner != address(0x0), "Stargate: _owner cannot be 0x0");
protocolFeeOwner = _owner;
}
function setMintFeeOwner(address _owner) external onlyOwner {
require(_owner != address(0x0), "Stargate: _owner cannot be 0x0");
mintFeeOwner = _owner;
}
function setFees(uint256 _poolId, uint256 _mintFeeBP) external onlyOwner {
Pool pool = _getPool(_poolId);
pool.setFee(_mintFeeBP);
}
function setFeeLibrary(uint256 _poolId, address _feeLibraryAddr) external onlyOwner {
Pool pool = _getPool(_poolId);
pool.setFeeLibrary(_feeLibraryAddr);
}
function setSwapStop(uint256 _poolId, bool _swapStop) external onlyOwner {
Pool pool = _getPool(_poolId);
pool.setSwapStop(_swapStop);
}
function setDeltaParam(
uint256 _poolId,
bool _batched,
uint256 _swapDeltaBP,
uint256 _lpDeltaBP,
bool _defaultSwapMode,
bool _defaultLPMode
) external onlyOwner {
Pool pool = _getPool(_poolId);
pool.setDeltaParam(_batched, _swapDeltaBP, _lpDeltaBP, _defaultSwapMode, _defaultLPMode);
}
function callDelta(uint256 _poolId, bool _fullMode) external {
Pool pool = _getPool(_poolId);
pool.callDelta(_fullMode);
}
function withdrawMintFee(uint256 _poolId, address _to) external {
require(mintFeeOwner == msg.sender, "Stargate: only mintFeeOwner");
Pool pool = _getPool(_poolId);
pool.withdrawMintFeeBalance(_to);
}
function withdrawProtocolFee(uint256 _poolId, address _to) external {
require(protocolFeeOwner == msg.sender, "Stargate: only protocolFeeOwner");
Pool pool = _getPool(_poolId);
pool.withdrawProtocolFeeBalance(_to);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface ILayerZeroReceiver {
// @notice LayerZero endpoint will invoke this function to deliver the message on the destination
// @param _srcChainId - the source endpoint identifier
// @param _srcAddress - the source sending contract address from the source chain
// @param _nonce - the ordered message nonce
// @param _payload - the signed payload is the UA bytes has encoded to be sent
function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./ILayerZeroUserApplicationConfig.sol";
interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
// @notice send a LayerZero message to the specified address at a LayerZero endpoint.
// @param _dstChainId - the destination chain identifier
// @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
// @param _payload - a custom bytes payload to send to the destination contract
// @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
// @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
// @param _adapterParams - parameters for custom functionality. ie: pay for a specified destination gasAmount, or receive airdropped native gas from the relayer on destination
function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
// @notice used by the messaging library to publish verified payload
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source contract (as bytes) at the source chain
// @param _dstAddress - the address on destination chain
// @param _nonce - the unbound message ordering nonce
// @param _gasLimit - the gas limit for external contract execution
// @param _payload - verified payload to send to the destination contract
function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;
// @notice get the inboundNonce of a receiver from a source chain which could be EVM or non-EVM chain
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);
// @notice get the outboundNonce from this source chain which, consequently, is always an EVM
// @param _srcAddress - the source chain contract address
function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);
// @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
// @param _dstChainId - the destination chain identifier
// @param _userApplication - the user app address on this EVM chain
// @param _payload - the custom message to send over LayerZero
// @param _payInZRO - if false, user app pays the protocol fee in native token
// @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);
// @notice get this Endpoint's immutable source identifier
function getChainId() external view returns (uint16);
// @notice the interface to retry failed message on this Endpoint destination
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
// @param _payload - the payload to be retried
function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;
// @notice query if any STORED payload (message blocking) at the endpoint.
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);
// @notice query if the _libraryAddress is valid for sending msgs.
// @param _userApplication - the user app address on this EVM chain
function getSendLibraryAddress(address _userApplication) external view returns (address);
// @notice query if the _libraryAddress is valid for receiving msgs.
// @param _userApplication - the user app address on this EVM chain
function getReceiveLibraryAddress(address _userApplication) external view returns (address);
// @notice query if the non-reentrancy guard for send() is on
// @return true if the guard is on. false otherwise
function isSendingPayload() external view returns (bool);
// @notice query if the non-reentrancy guard for receive() is on
// @return true if the guard is on. false otherwise
function isReceivingPayload() external view returns (bool);
// @notice get the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _userApplication - the contract address of the user application
// @param _configType - type of configuration. every messaging library has its own convention.
function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);
// @notice get the send() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getSendVersion(address _userApplication) external view returns (uint16);
// @notice get the lzReceive() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getReceiveVersion(address _userApplication) external view returns (uint16);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface ILayerZeroUserApplicationConfig {
// @notice set the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _configType - type of configuration. every messaging library has its own convention.
// @param _config - configuration in the bytes. can encode arbitrary content.
function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;
// @notice set the send() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setSendVersion(uint16 _version) external;
// @notice set the lzReceive() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setReceiveVersion(uint16 _version) external;
// @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
// @param _srcChainId - the chainId of the source chain
// @param _srcAddress - the contract address of the source contract at the source chain
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <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 GSN 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 payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
// libraries
import "@openzeppelin/contracts/math/SafeMath.sol";
contract LPTokenERC20 {
using SafeMath for uint256;
//---------------------------------------------------------------------------
// CONSTANTS
string public name;
string public symbol;
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
// set in constructor
bytes32 public DOMAIN_SEPARATOR;
//---------------------------------------------------------------------------
// VARIABLES
uint256 public decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
mapping(address => uint256) public nonces;
//---------------------------------------------------------------------------
// EVENTS
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
constructor(string memory _name, string memory _symbol) {
name = _name;
symbol = _symbol;
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes("1")),
chainId,
address(this)
)
);
}
function _mint(address to, uint256 value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint256 value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(
address owner,
address spender,
uint256 value
) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(
address from,
address to,
uint256 value
) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint256 value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint256 value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool) {
if (allowance[from][msg.sender] != uint256(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(deadline >= block.timestamp, "Bridge: EXPIRED");
bytes32 digest = keccak256(
abi.encodePacked(
"\\x19\\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, "Bridge: INVALID_SIGNATURE");
_approve(owner, spender, value);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.7.6;
pragma abicoder v2;
import "../Pool.sol";
interface IStargateFeeLibrary {
function getFees(
uint256 _srcPoolId,
uint256 _dstPoolId,
uint16 _dstChainId,
address _from,
uint256 _amountSD
) external returns (Pool.SwapObj memory s);
function getVersion() external view returns (string memory);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./Pool.sol";
contract Factory is Ownable {
using SafeMath for uint256;
//---------------------------------------------------------------------------
// VARIABLES
mapping(uint256 => Pool) public getPool; // poolId -> PoolInfo
address[] public allPools;
address public immutable router;
address public defaultFeeLibrary; // address for retrieving fee params for swaps
//---------------------------------------------------------------------------
// MODIFIERS
modifier onlyRouter() {
require(msg.sender == router, "Stargate: caller must be Router.");
_;
}
constructor(address _router) {
require(_router != address(0x0), "Stargate: _router cant be 0x0"); // 1 time only
router = _router;
}
function setDefaultFeeLibrary(address _defaultFeeLibrary) external onlyOwner {
require(_defaultFeeLibrary != address(0x0), "Stargate: fee library cant be 0x0");
defaultFeeLibrary = _defaultFeeLibrary;
}
function allPoolsLength() external view returns (uint256) {
return allPools.length;
}
function createPool(
uint256 _poolId,
address _token,
uint8 _sharedDecimals,
uint8 _localDecimals,
string memory _name,
string memory _symbol
) public onlyRouter returns (address poolAddress) {
require(address(getPool[_poolId]) == address(0x0), "Stargate: Pool already created");
Pool pool = new Pool(_poolId, router, _token, _sharedDecimals, _localDecimals, defaultFeeLibrary, _name, _symbol);
getPool[_poolId] = pool;
poolAddress = address(pool);
allPools.push(poolAddress);
}
function renounceOwnership() public override onlyOwner {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
interface IStargateRouter {
struct lzTxObj {
uint256 dstGasForCall;
uint256 dstNativeAmount;
bytes dstNativeAddr;
}
function addLiquidity(
uint256 _poolId,
uint256 _amountLD,
address _to
) external;
function swap(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLD,
uint256 _minAmountLD,
lzTxObj memory _lzTxParams,
bytes calldata _to,
bytes calldata _payload
) external payable;
function redeemRemote(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
uint256 _minAmountLD,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external payable;
function instantRedeemLocal(
uint16 _srcPoolId,
uint256 _amountLP,
address _to
) external returns (uint256);
function redeemLocal(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external payable;
function sendCredits(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress
) external payable;
function quoteLayerZeroFee(
uint16 _dstChainId,
uint8 _functionType,
bytes calldata _toAddress,
bytes calldata _transferAndCallPayload,
lzTxObj memory _lzTxParams
) external view returns (uint256, uint256);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
interface IStargateReceiver {
function sgReceive(
uint16 _chainId,
bytes memory _srcAddress,
uint256 _nonce,
address _token,
uint256 amountLD,
bytes memory payload
) external;
}