Skip to content

Commit

Permalink
feat: update Broker + TradingLimits to 0.8 and make G$ changes
Browse files Browse the repository at this point in the history
  • Loading branch information
philbow61 committed Oct 6, 2024
1 parent 6f8b5b7 commit 3135626
Show file tree
Hide file tree
Showing 14 changed files with 407 additions and 107 deletions.
81 changes: 81 additions & 0 deletions contracts/common/IERC20MintableBurnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
pragma solidity ^0.8.0;
//TODO: check if this is latest impl of openzeppelin or any other impl

/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see {ERC20Detailed}.
*/
interface IERC20MintableBurnable {
/**
* @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);

function mint(address account, uint256 amount) external;

function burn(uint256 amount) external;

/**
* @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);
}
83 changes: 83 additions & 0 deletions contracts/common/SafeERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
pragma solidity ^0.8.0;

import { IERC20MintableBurnable as IERC20 } from "contracts/common/IERC20MintableBurnable.sol";
import { Address } from "openzeppelin-contracts-next/contracts/utils/Address.sol";
//TODO: merge with lattest impl of openzeppelin
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;

function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}

function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}

function safeMint(IERC20 token, address account, uint256 amount) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.mint.selector, account, amount));
}

function safeBurn(IERC20 token, uint256 amount) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.burn.selector, amount));
}

function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}

function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}

function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) - value;
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}

/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.

// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
require(address(token).isContract(), "SafeERC20: call to non-contract");

// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");

if (returndata.length > 0) {
// Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
1 change: 0 additions & 1 deletion contracts/import.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,3 @@ import "celo/contracts/common/Freezer.sol";
import "celo/contracts/stability/SortedOracles.sol";
import "test/utils/harnesses/WithThresholdHarness.sol";
import "test/utils/harnesses/WithCooldownHarness.sol";
import "test/utils/harnesses/TradingLimitsHarness.sol";
27 changes: 16 additions & 11 deletions contracts/interfaces/IBroker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,34 +121,39 @@ interface IBroker {
/**
* @notice Allows the contract to be upgradable via the proxy.
* @param _exchangeProviders The addresses of the ExchangeProvider contracts.
* @param _reserve The address of the Reserve contract.
* @param _reserves The address of the Reserve contract.
*/
function initialize(address[] calldata _exchangeProviders, address _reserve) external;
function initialize(address[] calldata _exchangeProviders, address[] calldata _reserves) external;

/// @notice IOwnable:
function transferOwnership(address newOwner) external;
//TODO: Bogdan added these to the interface but when upgrading to 0.8.18,
// This is causing a compilation error. because they are defined in Ownable.sol as well.
// only way of fixing this is to remove them from the interface. or have the explicit
// implementation in the contract and add a override(IBroker, Ownable) to the functions.

//function renounceOwnership() external;

function renounceOwnership() external;
//function owner() external view returns (address);

function owner() external view returns (address);
/// @notice IOwnable:
//function transferOwnership(address newOwner) external;

/// @notice Getters:
function reserve() external view returns (address);
//function reserve() external view returns (address);

function isExchangeProvider(address exchangeProvider) external view returns (bool);

/// @notice Setters:
function addExchangeProvider(address exchangeProvider) external returns (uint256 index);
function addExchangeProvider(address exchangeProvider, address reserve) external returns (uint256 index);

function removeExchangeProvider(address exchangeProvider, uint256 index) external;

function setReserve(address _reserve) external;
function setReserves(address[] calldata _exchangeProviders, address[] calldata _reserves) external;

function configureTradingLimit(bytes32 exchangeId, address token, ITradingLimits.Config calldata config) external;

function tradingLimitsConfig(bytes32 id) external view returns (ITradingLimits.Config memory);
// function tradingLimitsConfig(bytes32 id) external view returns (ITradingLimits.Config memory);

function tradingLimitsState(bytes32 id) external view returns (ITradingLimits.State memory);
// function tradingLimitsState(bytes32 id) external view returns (ITradingLimits.State memory);

function exchangeProviders(uint256 i) external view returns (address);
}
11 changes: 6 additions & 5 deletions contracts/interfaces/IBrokerAdmin.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;
pragma solidity >=0.5.13 <0.8.19;

/*
* @title Broker Admin Interface
Expand Down Expand Up @@ -38,11 +38,12 @@ interface IBrokerAdmin {
* @param exchangeProvider The address of the ExchangeProvider to add.
* @return index The index where the ExchangeProvider was inserted.
*/
function addExchangeProvider(address exchangeProvider) external returns (uint256 index);
function addExchangeProvider(address exchangeProvider, address reserve) external returns (uint256 index);

/**
* @notice Set the Mento reserve address.
* @param reserve The Mento reserve address.
* @notice Set the reserves for the exchange providers.
* @param _exchangeProviders The addresses of the ExchangeProvider contracts.
* @param _reserves The addresses of the Reserve contracts.
*/
function setReserve(address reserve) external;
function setReserves(address[] calldata _exchangeProviders, address[] calldata _reserves) external;
}
10 changes: 7 additions & 3 deletions contracts/libraries/TradingLimits.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;
pragma solidity 0.8.18;
pragma experimental ABIEncoderV2;

import { ITradingLimits } from "contracts/interfaces/ITradingLimits.sol";
Expand Down Expand Up @@ -44,7 +44,7 @@ library TradingLimits {
uint8 private constant L0 = 1; // 0b001 Limit0
uint8 private constant L1 = 2; // 0b010 Limit1
uint8 private constant LG = 4; // 0b100 LimitGlobal
int48 private constant MAX_INT48 = int48(uint48(-1) / 2);
int48 private constant MAX_INT48 = type(int48).max;

/**
* @notice Validate a trading limit configuration.
Expand Down Expand Up @@ -129,7 +129,11 @@ library TradingLimits {
) internal view returns (ITradingLimits.State memory) {
int256 _deltaFlowUnits = _deltaFlow / int256((10 ** uint256(decimals)));
require(_deltaFlowUnits <= MAX_INT48, "dFlow too large");
int48 deltaFlowUnits = _deltaFlowUnits == 0 ? 1 : int48(_deltaFlowUnits);

int48 deltaFlowUnits = int48(_deltaFlowUnits);
if (deltaFlowUnits == 0) {
deltaFlowUnits = _deltaFlow > 0 ? int48(1) : int48(-1);
}

if (config.flags & L0 > 0) {
if (block.timestamp > self.lastUpdated0 + config.timestep0) {
Expand Down
Loading

0 comments on commit 3135626

Please sign in to comment.