Bridge.sol 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // SPDX-License-Identifier: BUSL-1.1
  2. pragma solidity 0.7.6;
  3. pragma abicoder v2;
  4. // imports
  5. import "@openzeppelin/contracts/access/Ownable.sol";
  6. import "./Pool.sol";
  7. import "./Router.sol";
  8. // libraries
  9. import "@openzeppelin/contracts/math/SafeMath.sol";
  10. import "./interfaces/ILayerZeroReceiver.sol";
  11. import "./interfaces/ILayerZeroEndpoint.sol";
  12. import "./interfaces/ILayerZeroUserApplicationConfig.sol";
  13. contract Bridge is Ownable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {
  14. using SafeMath for uint256;
  15. //---------------------------------------------------------------------------
  16. // CONSTANTS
  17. uint8 internal constant TYPE_SWAP_REMOTE = 1;
  18. uint8 internal constant TYPE_ADD_LIQUIDITY = 2;
  19. uint8 internal constant TYPE_REDEEM_LOCAL_CALL_BACK = 3;
  20. uint8 internal constant TYPE_WITHDRAW_REMOTE = 4;
  21. //---------------------------------------------------------------------------
  22. // VARIABLES
  23. ILayerZeroEndpoint public immutable layerZeroEndpoint;
  24. mapping(uint16 => bytes) public bridgeLookup;
  25. mapping(uint16 => mapping(uint8 => uint256)) public gasLookup;
  26. Router public immutable router;
  27. bool public useLayerZeroToken;
  28. //---------------------------------------------------------------------------
  29. // EVENTS
  30. event SendMsg(uint8 msgType, uint64 nonce);
  31. //---------------------------------------------------------------------------
  32. // MODIFIERS
  33. modifier onlyRouter() {
  34. require(msg.sender == address(router), "Mirrorgate: caller must be Router.");
  35. _;
  36. }
  37. constructor(address _layerZeroEndpoint, address _router) {
  38. require(_layerZeroEndpoint != address(0x0), "Mirrorgate: _layerZeroEndpoint cannot be 0x0");
  39. require(_router != address(0x0), "Mirrorgate: _router cannot be 0x0");
  40. layerZeroEndpoint = ILayerZeroEndpoint(_layerZeroEndpoint);
  41. router = Router(_router);
  42. }
  43. //---------------------------------------------------------------------------
  44. // EXTERNAL functions
  45. function lzReceive(
  46. uint16 _srcChainId,
  47. bytes memory _srcAddress,
  48. uint64 _nonce,
  49. bytes memory _payload
  50. ) external override {
  51. require(msg.sender == address(layerZeroEndpoint), "Mirrorgate: only LayerZero endpoint can call lzReceive");
  52. require(
  53. _srcAddress.length == bridgeLookup[_srcChainId].length && keccak256(_srcAddress) == keccak256(bridgeLookup[_srcChainId]),
  54. "Mirrorgate: bridge does not match"
  55. );
  56. uint8 functionType;
  57. assembly {
  58. functionType := mload(add(_payload, 32))
  59. }
  60. if (functionType == TYPE_SWAP_REMOTE) {
  61. (
  62. ,
  63. uint256 srcPoolId,
  64. uint256 dstPoolId,
  65. uint256 dstGasForCall,
  66. Pool.CreditObj memory c,
  67. Pool.SwapObj memory s,
  68. bytes memory to,
  69. bytes memory payload
  70. ) = abi.decode(_payload, (uint8, uint256, uint256, uint256, Pool.CreditObj, Pool.SwapObj, bytes, bytes));
  71. address toAddress;
  72. assembly {
  73. toAddress := mload(add(to, 20))
  74. }
  75. router.creditChainPath(_srcChainId, srcPoolId, dstPoolId, c);
  76. router.swapRemote(_srcChainId, _srcAddress, _nonce, srcPoolId, dstPoolId, dstGasForCall, toAddress, s, payload);
  77. } else if (functionType == TYPE_ADD_LIQUIDITY) {
  78. (, uint256 srcPoolId, uint256 dstPoolId, Pool.CreditObj memory c) = abi.decode(_payload, (uint8, uint256, uint256, Pool.CreditObj));
  79. router.creditChainPath(_srcChainId, srcPoolId, dstPoolId, c);
  80. } else if (functionType == TYPE_REDEEM_LOCAL_CALL_BACK) {
  81. (, uint256 srcPoolId, uint256 dstPoolId, Pool.CreditObj memory c, uint256 amountSD, uint256 mintAmountSD, bytes memory to) = abi
  82. .decode(_payload, (uint8, uint256, uint256, Pool.CreditObj, uint256, uint256, bytes));
  83. address toAddress;
  84. assembly {
  85. toAddress := mload(add(to, 20))
  86. }
  87. router.creditChainPath(_srcChainId, srcPoolId, dstPoolId, c);
  88. router.redeemLocalCallback(_srcChainId, _srcAddress, _nonce, srcPoolId, dstPoolId, toAddress, amountSD, mintAmountSD);
  89. } else if (functionType == TYPE_WITHDRAW_REMOTE) {
  90. (, uint256 srcPoolId, uint256 dstPoolId, Pool.CreditObj memory c, uint256 amountSD, bytes memory to) = abi.decode(
  91. _payload,
  92. (uint8, uint256, uint256, Pool.CreditObj, uint256, bytes)
  93. );
  94. router.creditChainPath(_srcChainId, srcPoolId, dstPoolId, c);
  95. router.redeemLocalCheckOnRemote(_srcChainId, _srcAddress, _nonce, srcPoolId, dstPoolId, amountSD, to);
  96. }
  97. }
  98. //---------------------------------------------------------------------------
  99. // LOCAL CHAIN FUNCTIONS
  100. function swap(
  101. uint16 _chainId,
  102. uint256 _srcPoolId,
  103. uint256 _dstPoolId,
  104. address payable _refundAddress,
  105. Pool.CreditObj memory _c,
  106. Pool.SwapObj memory _s,
  107. IMirrorgateRouter.lzTxObj memory _lzTxParams,
  108. bytes calldata _to,
  109. bytes calldata _payload
  110. ) external payable onlyRouter {
  111. bytes memory payload = abi.encode(TYPE_SWAP_REMOTE, _srcPoolId, _dstPoolId, _lzTxParams.dstGasForCall, _c, _s, _to, _payload);
  112. _call(_chainId, TYPE_SWAP_REMOTE, _refundAddress, _lzTxParams, payload);
  113. }
  114. function redeemLocalCallback(
  115. uint16 _chainId,
  116. address payable _refundAddress,
  117. Pool.CreditObj memory _c,
  118. IMirrorgateRouter.lzTxObj memory _lzTxParams,
  119. bytes memory _payload
  120. ) external payable onlyRouter {
  121. bytes memory payload;
  122. {
  123. (, uint256 srcPoolId, uint256 dstPoolId, uint256 amountSD, uint256 mintAmountSD, bytes memory to) = abi.decode(
  124. _payload,
  125. (uint8, uint256, uint256, uint256, uint256, bytes)
  126. );
  127. // swap dst and src because we are headed back
  128. payload = abi.encode(TYPE_REDEEM_LOCAL_CALL_BACK, dstPoolId, srcPoolId, _c, amountSD, mintAmountSD, to);
  129. }
  130. _call(_chainId, TYPE_REDEEM_LOCAL_CALL_BACK, _refundAddress, _lzTxParams, payload);
  131. }
  132. function redeemLocal(
  133. uint16 _chainId,
  134. uint256 _srcPoolId,
  135. uint256 _dstPoolId,
  136. address payable _refundAddress,
  137. Pool.CreditObj memory _c,
  138. uint256 _amountSD,
  139. bytes calldata _to,
  140. IMirrorgateRouter.lzTxObj memory _lzTxParams
  141. ) external payable onlyRouter {
  142. bytes memory payload = abi.encode(TYPE_WITHDRAW_REMOTE, _srcPoolId, _dstPoolId, _c, _amountSD, _to);
  143. _call(_chainId, TYPE_WITHDRAW_REMOTE, _refundAddress, _lzTxParams, payload);
  144. }
  145. function sendCredits(
  146. uint16 _chainId,
  147. uint256 _srcPoolId,
  148. uint256 _dstPoolId,
  149. address payable _refundAddress,
  150. Pool.CreditObj memory _c
  151. ) external payable onlyRouter {
  152. bytes memory payload = abi.encode(TYPE_ADD_LIQUIDITY, _srcPoolId, _dstPoolId, _c);
  153. IMirrorgateRouter.lzTxObj memory lzTxObj = IMirrorgateRouter.lzTxObj(0, 0, "0x");
  154. _call(_chainId, TYPE_ADD_LIQUIDITY, _refundAddress, lzTxObj, payload);
  155. }
  156. function quoteLayerZeroFee(
  157. uint16 _chainId,
  158. uint8 _functionType,
  159. bytes calldata _toAddress,
  160. bytes calldata _transferAndCallPayload,
  161. IMirrorgateRouter.lzTxObj memory _lzTxParams
  162. ) external view returns (uint256, uint256) {
  163. bytes memory payload = "";
  164. Pool.CreditObj memory c = Pool.CreditObj(1, 1);
  165. if (_functionType == TYPE_SWAP_REMOTE) {
  166. Pool.SwapObj memory s = Pool.SwapObj(1, 1, 1, 1, 1, 1);
  167. payload = abi.encode(TYPE_SWAP_REMOTE, 0, 0, 0, c, s, _toAddress, _transferAndCallPayload);
  168. } else if (_functionType == TYPE_ADD_LIQUIDITY) {
  169. payload = abi.encode(TYPE_ADD_LIQUIDITY, 0, 0, c);
  170. } else if (_functionType == TYPE_REDEEM_LOCAL_CALL_BACK) {
  171. payload = abi.encode(TYPE_REDEEM_LOCAL_CALL_BACK, 0, 0, c, 0, 0, _toAddress);
  172. } else if (_functionType == TYPE_WITHDRAW_REMOTE) {
  173. payload = abi.encode(TYPE_WITHDRAW_REMOTE, 0, 0, c, 0, _toAddress);
  174. } else {
  175. revert("Mirrorgate: unsupported function type");
  176. }
  177. bytes memory lzTxParamBuilt = _txParamBuilder(_chainId, _functionType, _lzTxParams);
  178. return layerZeroEndpoint.estimateFees(_chainId, address(this), payload, useLayerZeroToken, lzTxParamBuilt);
  179. }
  180. //---------------------------------------------------------------------------
  181. // dao functions
  182. function setBridge(uint16 _chainId, bytes calldata _bridgeAddress) external onlyOwner {
  183. require(bridgeLookup[_chainId].length == 0, "Mirrorgate: Bridge already set!");
  184. bridgeLookup[_chainId] = _bridgeAddress;
  185. }
  186. function setGasAmount(
  187. uint16 _chainId,
  188. uint8 _functionType,
  189. uint256 _gasAmount
  190. ) external onlyOwner {
  191. require(_functionType >= 1 && _functionType <= 4, "Mirrorgate: invalid _functionType");
  192. gasLookup[_chainId][_functionType] = _gasAmount;
  193. }
  194. function approveTokenSpender(
  195. address token,
  196. address spender,
  197. uint256 amount
  198. ) external onlyOwner {
  199. IERC20(token).approve(spender, amount);
  200. }
  201. function setUseLayerZeroToken(bool enable) external onlyOwner {
  202. useLayerZeroToken = enable;
  203. }
  204. function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {
  205. layerZeroEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
  206. }
  207. //---------------------------------------------------------------------------
  208. // generic config for user Application
  209. function setConfig(
  210. uint16 _version,
  211. uint16 _chainId,
  212. uint256 _configType,
  213. bytes calldata _config
  214. ) external override onlyOwner {
  215. layerZeroEndpoint.setConfig(_version, _chainId, _configType, _config);
  216. }
  217. function setSendVersion(uint16 version) external override onlyOwner {
  218. layerZeroEndpoint.setSendVersion(version);
  219. }
  220. function setReceiveVersion(uint16 version) external override onlyOwner {
  221. layerZeroEndpoint.setReceiveVersion(version);
  222. }
  223. //---------------------------------------------------------------------------
  224. // INTERNAL functions
  225. function txParamBuilderType1(uint256 _gasAmount) internal pure returns (bytes memory) {
  226. uint16 txType = 1;
  227. return abi.encodePacked(txType, _gasAmount);
  228. }
  229. function txParamBuilderType2(
  230. uint256 _gasAmount,
  231. uint256 _dstNativeAmount,
  232. bytes memory _dstNativeAddr
  233. ) internal pure returns (bytes memory) {
  234. uint16 txType = 2;
  235. return abi.encodePacked(txType, _gasAmount, _dstNativeAmount, _dstNativeAddr);
  236. }
  237. function _txParamBuilder(
  238. uint16 _chainId,
  239. uint8 _type,
  240. IMirrorgateRouter.lzTxObj memory _lzTxParams
  241. ) internal view returns (bytes memory) {
  242. bytes memory lzTxParam;
  243. address dstNativeAddr;
  244. {
  245. bytes memory dstNativeAddrBytes = _lzTxParams.dstNativeAddr;
  246. assembly {
  247. dstNativeAddr := mload(add(dstNativeAddrBytes, 20))
  248. }
  249. }
  250. uint256 totalGas = gasLookup[_chainId][_type].add(_lzTxParams.dstGasForCall);
  251. if (_lzTxParams.dstNativeAmount > 0 && dstNativeAddr != address(0x0)) {
  252. lzTxParam = txParamBuilderType2(totalGas, _lzTxParams.dstNativeAmount, _lzTxParams.dstNativeAddr);
  253. } else {
  254. lzTxParam = txParamBuilderType1(totalGas);
  255. }
  256. return lzTxParam;
  257. }
  258. function _call(
  259. uint16 _chainId,
  260. uint8 _type,
  261. address payable _refundAddress,
  262. IMirrorgateRouter.lzTxObj memory _lzTxParams,
  263. bytes memory _payload
  264. ) internal {
  265. bytes memory lzTxParamBuilt = _txParamBuilder(_chainId, _type, _lzTxParams);
  266. uint64 nextNonce = layerZeroEndpoint.getOutboundNonce(_chainId, address(this)) + 1;
  267. layerZeroEndpoint.send{value: msg.value}(_chainId, bridgeLookup[_chainId], _payload, _refundAddress, address(this), lzTxParamBuilt);
  268. emit SendMsg(_type, nextNonce);
  269. }
  270. function renounceOwnership() public override onlyOwner {}
  271. }