Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added maxGasPrice setting to SanityRates, and updated to solidity 6 #1053

Merged
merged 7 commits into from
Aug 14, 2020
7 changes: 7 additions & 0 deletions contracts/sol6/IKyberSanity.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma solidity 0.6.6;

import "./IERC20.sol";

interface IKyberSanity {
function getSanityRate(IERC20 src, IERC20 dest) external view returns (uint256);
}
97 changes: 97 additions & 0 deletions contracts/sol6/SanityRatesGasPrice.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
pragma solidity 0.6.6;

import "./IKyberSanity.sol";
import "./utils/Utils5.sol";
import "./utils/Withdrawable3.sol";

/**
* @title SanityRatesGasPrice contract
* The contract provides the following functionality:
* - setting reasonable diff
* - setting max gas price criteria for a trade
* - setting sanity rates
* - getting sanity rates
*
* This allows FPR managers to protect their price updates from
* front runners by setting the maxGasPriceWei param. But it mainly
* protects reserves from (1) bugs in the conversion rate logic or
* from (2) hacks into the conversion rate system. If there are large
* inconsistencies between the sanity rates and the actual rates,
* then trades involving the reserve will be disabled.
*/

contract SanityRatesGasPrice is IKyberSanity, Withdrawable3, Utils5 {
struct SanityData {
uint128 tokenRate;
uint128 reasonableDiffInBps;
}

mapping(address => SanityData) public sanityData;
uint256 public maxGasPriceWei;

event SanityMaxGasPriceSet(uint256 maxGasPrice);

constructor(address _admin, uint256 _maxGasPriceWei) public Withdrawable3(_admin) {
setGasPrice(_maxGasPriceWei);
manhlx3006 marked this conversation as resolved.
Show resolved Hide resolved
}

/// @dev set reasonableDiffInBps of a token to MAX_RATE to avoid handling the
/// price feed for this token
function setReasonableDiff(IERC20[] calldata srcs, uint256[] calldata diff)
external
onlyAdmin
{
require(srcs.length == diff.length, "srcs,diff length mismatch");
for (uint256 i = 0; i < srcs.length; i++) {
require(
diff[i] <= BPS || diff[i] == MAX_RATE,
"Diff must be <= 10000 BPS or == MAX_RATE"
);
sanityData[address(srcs[i])].reasonableDiffInBps = uint128(diff[i]);
}
}

function setMaxGasPriceWei(uint256 _maxGasPriceWei) external onlyOperator {
setGasPrice(_maxGasPriceWei);
emit SanityMaxGasPriceSet(maxGasPriceWei);
}

function setSanityRates(IERC20[] calldata srcs, uint256[] calldata rates)
external
onlyOperator
{
require(srcs.length == rates.length, "srcs,rates length mismatch");

for (uint256 i = 0; i < srcs.length; i++) {
require(rates[i] > 0 && rates[i] <= MAX_RATE, "rate must be > 0 and <= MAX_RATE");
sanityData[address(srcs[i])].tokenRate = uint128(rates[i]);
}
}

function getSanityRate(IERC20 src, IERC20 dest) external override view returns (uint256 rate) {
SanityData memory data;

if (src != ETH_TOKEN_ADDRESS && dest != ETH_TOKEN_ADDRESS) return 0;
if (tx.gasprice > maxGasPriceWei) return 0;

uint128 reasonableDiffInBps;
if (src == ETH_TOKEN_ADDRESS) {
data = sanityData[address(dest)];
reasonableDiffInBps = data.reasonableDiffInBps;
rate = data.tokenRate > 0 ? (PRECISION * PRECISION) / data.tokenRate : 0;
} else {
data = sanityData[address(src)];
reasonableDiffInBps = data.reasonableDiffInBps;
rate = data.tokenRate;
}

if (reasonableDiffInBps == MAX_RATE) return MAX_RATE;

return (rate * (BPS + data.reasonableDiffInBps)) / BPS;
}

function setGasPrice(uint256 _maxGasPriceWei) internal {
require(_maxGasPriceWei > 0, "maxGasPriceWei must be > 0");
maxGasPriceWei = _maxGasPriceWei;
}
}
14 changes: 14 additions & 0 deletions contracts/sol6/mock/MockReserve.sol
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
pragma solidity 0.6.6;

import "../IKyberReserve.sol";
import "../IKyberSanity.sol";
import "../utils/Utils5.sol";
import "../utils/zeppelin/SafeERC20.sol";


contract MockReserve is IKyberReserve, Utils5 {
using SafeERC20 for IERC20;

IKyberSanity public sanityRatesContract;
mapping(address => uint256) public buyTokenRates;
mapping(address => uint256) public sellTokenRates;

receive() external payable {}

function setContracts(
IKyberSanity _sanityRates
) public {
sanityRatesContract = _sanityRates;
}

function setRate(
IERC20 token,
uint256 buyRate,
Expand Down Expand Up @@ -90,6 +98,12 @@ contract MockReserve is IKyberReserve, Utils5 {
if (dest != ETH_TOKEN_ADDRESS && dest.balanceOf(address(this)) < destAmount) {
return 0;
}

if (address(sanityRatesContract) != address(0)) {
uint sanityRate = sanityRatesContract.getSanityRate(src, dest);
if (rate > sanityRate) return 0;
}

return rate;
}
}
Loading