MirrorgateFeeLibraryV02.sol 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // SPDX-License-Identifier: BUSL-1.1
  2. pragma solidity 0.7.6;
  3. pragma abicoder v2;
  4. import "../interfaces/IMirrorgateFeeLibrary.sol";
  5. import "../Pool.sol";
  6. import "../Factory.sol";
  7. import "@openzeppelin/contracts/math/SafeMath.sol";
  8. import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
  9. contract MirrorgateFeeLibraryV02 is IMirrorgateFeeLibrary, Ownable, ReentrancyGuard {
  10. using SafeMath for uint256;
  11. //---------------------------------------------------------------------------
  12. // VARIABLES
  13. // equilibrium func params. all in BPs * 10 ^ 2, i.e. 1 % = 10 ^ 6 units
  14. uint256 public constant DENOMINATOR = 1e18;
  15. uint256 public constant DELTA_1 = 6000 * 1e14;
  16. uint256 public constant DELTA_2 = 500 * 1e14;
  17. uint256 public constant LAMBDA_1 = 40 * 1e14;
  18. uint256 public constant LAMBDA_2 = 9960 * 1e14;
  19. uint256 public constant LP_FEE = 45 * 1e13;
  20. uint256 public constant PROTOCOL_FEE = 15 * 1e13;
  21. uint256 public constant PROTOCOL_SUBSIDY = 3 * 1e13;
  22. Factory public immutable factory;
  23. constructor(address _factory) {
  24. require(_factory != address(0x0), "FeeLibrary: Factory cannot be 0x0");
  25. factory = Factory(_factory);
  26. }
  27. function getFees(
  28. uint256 _srcPoolId,
  29. uint256 _dstPoolId,
  30. uint16 _dstChainId,
  31. address, /*_from*/
  32. uint256 _amountSD
  33. ) external view override returns (Pool.SwapObj memory s) {
  34. // calculate the protocol fee
  35. s.protocolFee = _amountSD.mul(PROTOCOL_FEE).div(DENOMINATOR);
  36. // calculate the equilibrium Fee
  37. Pool pool = factory.getPool(_srcPoolId);
  38. Pool.ChainPath memory chainPath = pool.getChainPath(_dstChainId, _dstPoolId);
  39. // calculate the equilibrium fee
  40. (uint256 eqFee, uint256 protocolSubsidy) = _getEquilibriumFee(chainPath.idealBalance, chainPath.balance, _amountSD);
  41. s.eqFee = eqFee;
  42. s.protocolFee = s.protocolFee.sub(protocolSubsidy);
  43. // calculate the equilibrium reward
  44. address tokenAddress = pool.token();
  45. uint256 currentAssetSD = IERC20(tokenAddress).balanceOf(address(pool)).div(pool.convertRate());
  46. uint256 lpAsset = pool.totalLiquidity();
  47. if (lpAsset > currentAssetSD) {
  48. // in deficit
  49. uint256 poolDeficit = lpAsset.sub(currentAssetSD);
  50. uint256 rewardPoolSize = pool.eqFeePool();
  51. // reward capped at rewardPoolSize
  52. uint256 eqRewards = rewardPoolSize.mul(_amountSD).div(poolDeficit);
  53. if (eqRewards > rewardPoolSize) {
  54. eqRewards = rewardPoolSize;
  55. }
  56. s.eqReward = eqRewards;
  57. }
  58. // calculate the LP fee.
  59. s.lpFee = _amountSD.mul(LP_FEE).div(DENOMINATOR);
  60. return s;
  61. }
  62. function getEquilibriumFee(
  63. uint256 idealBalance,
  64. uint256 beforeBalance,
  65. uint256 amountSD
  66. ) external pure returns (uint256, uint256) {
  67. return _getEquilibriumFee(idealBalance, beforeBalance, amountSD);
  68. }
  69. function getTrapezoidArea(
  70. uint256 lambda,
  71. uint256 yOffset,
  72. uint256 xUpperBound,
  73. uint256 xLowerBound,
  74. uint256 xStart,
  75. uint256 xEnd
  76. ) external pure returns (uint256) {
  77. return _getTrapezoidArea(lambda, yOffset, xUpperBound, xLowerBound, xStart, xEnd);
  78. }
  79. function _getEquilibriumFee(
  80. uint256 idealBalance,
  81. uint256 beforeBalance,
  82. uint256 amountSD
  83. ) internal pure returns (uint256, uint256) {
  84. require(beforeBalance >= amountSD, "Mirrorgate: not enough balance");
  85. uint256 afterBalance = beforeBalance.sub(amountSD);
  86. uint256 safeZoneMax = idealBalance.mul(DELTA_1).div(DENOMINATOR);
  87. uint256 safeZoneMin = idealBalance.mul(DELTA_2).div(DENOMINATOR);
  88. uint256 eqFee = 0;
  89. uint256 protocolSubsidy = 0;
  90. if (afterBalance >= safeZoneMax) {
  91. // no fee zone, protocol subsidize it.
  92. eqFee = amountSD.mul(PROTOCOL_SUBSIDY).div(DENOMINATOR);
  93. protocolSubsidy = eqFee;
  94. } else if (afterBalance >= safeZoneMin) {
  95. // safe zone
  96. uint256 proxyBeforeBalance = beforeBalance < safeZoneMax ? beforeBalance : safeZoneMax;
  97. eqFee = _getTrapezoidArea(LAMBDA_1, 0, safeZoneMax, safeZoneMin, proxyBeforeBalance, afterBalance);
  98. } else {
  99. // danger zone
  100. if (beforeBalance >= safeZoneMin) {
  101. // across 2 or 3 zones
  102. // part 1
  103. uint256 proxyBeforeBalance = beforeBalance < safeZoneMax ? beforeBalance : safeZoneMax;
  104. eqFee = eqFee.add(_getTrapezoidArea(LAMBDA_1, 0, safeZoneMax, safeZoneMin, proxyBeforeBalance, safeZoneMin));
  105. // part 2
  106. eqFee = eqFee.add(_getTrapezoidArea(LAMBDA_2, LAMBDA_1, safeZoneMin, 0, safeZoneMin, afterBalance));
  107. } else {
  108. // only in danger zone
  109. // part 2 only
  110. eqFee = eqFee.add(_getTrapezoidArea(LAMBDA_2, LAMBDA_1, safeZoneMin, 0, beforeBalance, afterBalance));
  111. }
  112. }
  113. return (eqFee, protocolSubsidy);
  114. }
  115. function _getTrapezoidArea(
  116. uint256 lambda,
  117. uint256 yOffset,
  118. uint256 xUpperBound,
  119. uint256 xLowerBound,
  120. uint256 xStart,
  121. uint256 xEnd
  122. ) internal pure returns (uint256) {
  123. require(xEnd >= xLowerBound && xStart <= xUpperBound, "Mirrorgate: balance out of bound");
  124. uint256 xBoundWidth = xUpperBound.sub(xLowerBound);
  125. // xStartDrift = xUpperBound.sub(xStart);
  126. uint256 yStart = xUpperBound.sub(xStart).mul(lambda).div(xBoundWidth).add(yOffset);
  127. // xEndDrift = xUpperBound.sub(xEnd)
  128. uint256 yEnd = xUpperBound.sub(xEnd).mul(lambda).div(xBoundWidth).add(yOffset);
  129. // compute the area
  130. uint256 deltaX = xStart.sub(xEnd);
  131. return yStart.add(yEnd).mul(deltaX).div(2).div(DENOMINATOR);
  132. }
  133. function getVersion() external pure override returns (string memory) {
  134. return "2.0.0";
  135. }
  136. }