@0x/contracts-utils
: Roll back additions to LibFractions
.
`@0x/contracts-dev-utils`: Add `D18` library for working with base-10, 18-digit decimals. `@0x/contracts-dev-utils`: Use `D18` library instead of `LibFractions` in `LibDydxBalance`.
This commit is contained in:
parent
9b3781abf1
commit
865a253eb5
@ -22,6 +22,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Add `DydxBridge` order validation",
|
"note": "Add `DydxBridge` order validation",
|
||||||
"pr": 2466
|
"pr": 2466
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add `D18` library for working with base-10, 18-precision decimals",
|
||||||
|
"pr": 2466
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timestamp": 1581204851
|
"timestamp": 1581204851
|
||||||
|
@ -375,7 +375,7 @@ contract AssetBalance is
|
|||||||
(, , address bridgeAddress, ) = LibAssetData.decodeERC20BridgeAssetData(order.makerAssetData);
|
(, , address bridgeAddress, ) = LibAssetData.decodeERC20BridgeAssetData(order.makerAssetData);
|
||||||
if (bridgeAddress == dydxBridgeAddress) {
|
if (bridgeAddress == dydxBridgeAddress) {
|
||||||
return (
|
return (
|
||||||
LibDydxBalance.getDydxMakerBalance(order, dydxBridgeAddress),
|
LibDydxBalance.getDydxMakerBalance(order, _getDydxAddress()),
|
||||||
_MAX_UINT256
|
_MAX_UINT256
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
239
contracts/dev-utils/contracts/src/D18.sol
Normal file
239
contracts/dev-utils/contracts/src/D18.sol
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.16;
|
||||||
|
|
||||||
|
|
||||||
|
/// @dev A library for working with 18 digit, base 10 decimals.
|
||||||
|
library D18 {
|
||||||
|
|
||||||
|
/// @dev Decimal places for dydx value quantities.
|
||||||
|
uint256 private constant PRECISION = 18;
|
||||||
|
/// @dev 1.0 in base-18 decimal.
|
||||||
|
int256 private constant DECIMAL_ONE = int256(10 ** PRECISION);
|
||||||
|
/// @dev Minimum signed integer value.
|
||||||
|
int256 private constant MIN_INT256_VALUE = int256(0x8000000000000000000000000000000000000000000000000000000000000000);
|
||||||
|
|
||||||
|
/// @dev Return `1.0`
|
||||||
|
function one()
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
r = DECIMAL_ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Add two decimals.
|
||||||
|
function add(int256 a, int256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
r = _add(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Add two decimals.
|
||||||
|
function add(uint256 a, int256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(int256(a) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _add(int256(a), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Add two decimals.
|
||||||
|
function add(uint256 a, uint256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(int256(a) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
require(int256(b) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _add(int256(a), int256(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Subract two decimals.
|
||||||
|
function sub(int256 a, int256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
r = _add(a, -b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Subract two decimals.
|
||||||
|
function sub(uint256 a, int256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(int256(a) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _add(int256(a), -b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Subract two decimals.
|
||||||
|
function sub(uint256 a, uint256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(int256(a) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
require(int256(b) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _add(int256(a), -int256(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Multiply two decimals.
|
||||||
|
function mul(int256 a, int256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
r = _div(_mul(a, b), DECIMAL_ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Multiply two decimals.
|
||||||
|
function mul(uint256 a, int256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(int256(a) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _div(_mul(int256(a), b), DECIMAL_ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Multiply two decimals.
|
||||||
|
function mul(int256 a, uint256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(int256(b) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _div(_mul(a, int256(b)), DECIMAL_ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Multiply two decimals.
|
||||||
|
function mul(uint256 a, uint256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(int256(a) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
require(int256(b) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _div(_mul(int256(a), int256(b)), DECIMAL_ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Divide two decimals.
|
||||||
|
function div(int256 a, int256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(a != MIN_INT256_VALUE || b != -1, "D18/DECIMAL_MUL_OVERFLOW");
|
||||||
|
r = _div(_mul(a, DECIMAL_ONE), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Divide two decimals.
|
||||||
|
function div(uint256 a, int256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(int256(a) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _div(_mul(int256(a), DECIMAL_ONE), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Divide two decimals.
|
||||||
|
function div(int256 a, uint256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(int256(b) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _div(_mul(a, DECIMAL_ONE), int256(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Divide two decimals.
|
||||||
|
function div(uint256 a, uint256 b)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(uint256(a) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
require(uint256(b) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = _div(_mul(int256(a), DECIMAL_ONE), int256(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Safely convert an unsigned integer into a signed integer.
|
||||||
|
function toSigned(uint256 a)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(uint256(a) >= 0, "D18/DECIMAL_VALUE_TOO_BIG");
|
||||||
|
r = int256(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Clip a signed value to be positive.
|
||||||
|
function clip(int256 a)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
r = a < 0 ? 0 : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Safely multiply two signed integers.
|
||||||
|
function _mul(int256 a, int256 b)
|
||||||
|
private
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
if (a == 0 || b == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
r = a * b;
|
||||||
|
require(r / a == b && r / b == a, "D18/DECIMAL_MUL_OVERFLOW");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Safely divide two signed integers.
|
||||||
|
function _div(int256 a, int256 b)
|
||||||
|
private
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
require(b != 0, "D18/DECIMAL_DIVISION_BY_ZERO");
|
||||||
|
require(a != MIN_INT256_VALUE || b != -1, "D18/DECIMAL_MUL_OVERFLOW");
|
||||||
|
r = a / b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Safely add two signed integers.
|
||||||
|
function _add(int256 a, int256 b)
|
||||||
|
private
|
||||||
|
pure
|
||||||
|
returns (int256 r)
|
||||||
|
{
|
||||||
|
r = a + b;
|
||||||
|
require(
|
||||||
|
!((a < 0 && b < 0 && r > a) || (a > 0 && b > 0 && r < a)),
|
||||||
|
"D18/DECIMAL_MUL_OVERFLOW"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,30 +23,16 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
|||||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydxBridge.sol";
|
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydxBridge.sol";
|
||||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydx.sol";
|
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydx.sol";
|
||||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibFractions.sol";
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||||
import "./LibAssetData.sol";
|
import "./LibAssetData.sol";
|
||||||
|
import "./D18.sol";
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable separate-by-one-line-in-contract
|
|
||||||
library LibDydxBalance {
|
library LibDydxBalance {
|
||||||
|
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
using LibSafeMath for uint256;
|
|
||||||
|
|
||||||
/// @dev Decimal places for dydx value quantities.
|
|
||||||
uint256 private constant DYDX_UNITS_DECIMALS = 18;
|
|
||||||
/// @dev Base units for dydx value quantities.
|
|
||||||
uint256 private constant DYDX_UNITS_BASE = 10 ** DYDX_UNITS_DECIMALS;
|
|
||||||
|
|
||||||
/// @dev A fraction/rate.
|
|
||||||
struct Fraction {
|
|
||||||
uint256 n;
|
|
||||||
uint256 d;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Structure that holds all pertinent info needed to perform a balance
|
/// @dev Structure that holds all pertinent info needed to perform a balance
|
||||||
/// check.
|
/// check.
|
||||||
@ -82,7 +68,7 @@ library LibDydxBalance {
|
|||||||
}
|
}
|
||||||
// If the rate we withdraw maker tokens is < 1, the asset proxy will
|
// If the rate we withdraw maker tokens is < 1, the asset proxy will
|
||||||
// throw because we will always transfer less maker tokens than asked.
|
// throw because we will always transfer less maker tokens than asked.
|
||||||
if (_ltf(_getMakerTokenWithdrawRate(info), Fraction(1, 1))) {
|
if (_getMakerTokenWithdrawRate(info) < D18.one()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// The maker balance is the smaller of:
|
// The maker balance is the smaller of:
|
||||||
@ -153,7 +139,7 @@ library LibDydxBalance {
|
|||||||
function _getMakerTokenWithdrawRate(BalanceCheckInfo memory info)
|
function _getMakerTokenWithdrawRate(BalanceCheckInfo memory info)
|
||||||
internal
|
internal
|
||||||
pure
|
pure
|
||||||
returns (Fraction memory makerTokenWithdrawRate)
|
returns (int256 makerTokenWithdrawRate)
|
||||||
{
|
{
|
||||||
// The last action is always a withdraw for the maker token.
|
// The last action is always a withdraw for the maker token.
|
||||||
IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1];
|
IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1];
|
||||||
@ -169,7 +155,7 @@ library LibDydxBalance {
|
|||||||
{
|
{
|
||||||
depositableMakerAmount = uint256(-1);
|
depositableMakerAmount = uint256(-1);
|
||||||
// The conversion rate from maker -> taker.
|
// The conversion rate from maker -> taker.
|
||||||
Fraction memory makerToTakerRate = Fraction(
|
int256 makerToTakerRate = D18.div(
|
||||||
info.takerAssetAmount,
|
info.takerAssetAmount,
|
||||||
info.makerAssetAmount
|
info.makerAssetAmount
|
||||||
);
|
);
|
||||||
@ -180,22 +166,17 @@ library LibDydxBalance {
|
|||||||
if (action.actionType != IDydxBridge.BridgeActionType.Deposit) {
|
if (action.actionType != IDydxBridge.BridgeActionType.Deposit) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Fraction memory depositRate = _getActionRate(action);
|
int256 depositRate = _getActionRate(action);
|
||||||
// Taker tokens will be transferred to the maker for every fill, so
|
// Taker tokens will be transferred to the maker for every fill, so
|
||||||
// we reduce the effective deposit rate if we're depositing the taker
|
// we reduce the effective deposit rate if we're depositing the taker
|
||||||
// token.
|
// token.
|
||||||
address depositToken = info.dydx.getMarketTokenAddress(action.marketId);
|
address depositToken = info.dydx.getMarketTokenAddress(action.marketId);
|
||||||
if (info.takerTokenAddress != address(0) && depositToken == info.takerTokenAddress) {
|
if (info.takerTokenAddress != address(0) && depositToken == info.takerTokenAddress) {
|
||||||
// `depositRate = max(0, depositRate - makerToTakerRate)`
|
depositRate = D18.sub(depositRate, makerToTakerRate);
|
||||||
if (_ltf(makerToTakerRate, depositRate)) {
|
|
||||||
depositRate = _subf(depositRate, makerToTakerRate);
|
|
||||||
} else {
|
|
||||||
depositRate = Fraction(0, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// If the deposit rate is > 0, we are limited by the transferrable
|
// If the deposit rate is > 0, we are limited by the transferrable
|
||||||
// token balance of the maker.
|
// token balance of the maker.
|
||||||
if (_gtf(depositRate, Fraction(0, 1))) {
|
if (depositRate > 0) {
|
||||||
uint256 supply = _getTransferabeTokenAmount(
|
uint256 supply = _getTransferabeTokenAmount(
|
||||||
depositToken,
|
depositToken,
|
||||||
info.makerAddress,
|
info.makerAddress,
|
||||||
@ -203,11 +184,7 @@ library LibDydxBalance {
|
|||||||
);
|
);
|
||||||
depositableMakerAmount = LibSafeMath.min256(
|
depositableMakerAmount = LibSafeMath.min256(
|
||||||
depositableMakerAmount,
|
depositableMakerAmount,
|
||||||
LibMath.getPartialAmountFloor(
|
uint256(D18.div(supply, depositRate))
|
||||||
depositRate.d,
|
|
||||||
depositRate.n,
|
|
||||||
supply
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,15 +202,13 @@ library LibDydxBalance {
|
|||||||
assert(info.actions.length >= 1);
|
assert(info.actions.length >= 1);
|
||||||
IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1];
|
IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1];
|
||||||
assert(withdraw.actionType == IDydxBridge.BridgeActionType.Withdraw);
|
assert(withdraw.actionType == IDydxBridge.BridgeActionType.Withdraw);
|
||||||
Fraction memory minCr = _getMinimumCollateralizationRatio(info.dydx);
|
int256 minCr = _getMinimumCollateralizationRatio(info.dydx);
|
||||||
// CR < 1 will cause math underflows.
|
|
||||||
require(_gtef(minCr, Fraction(1, 1)), "DevUtils/MIN_CR_MUST_BE_GTE_ONE");
|
|
||||||
// Loop through the accounts.
|
// Loop through the accounts.
|
||||||
for (uint256 accountIdx = 0; accountIdx < info.accounts.length; ++accountIdx) {
|
for (uint256 accountIdx = 0; accountIdx < info.accounts.length; ++accountIdx) {
|
||||||
(uint256 supplyValue, uint256 borrowValue) =
|
(uint256 supplyValue, uint256 borrowValue) =
|
||||||
_getAccountValues(info, info.accounts[accountIdx]);
|
_getAccountValues(info, info.accounts[accountIdx]);
|
||||||
// All accounts must currently be solvent.
|
// All accounts must currently be solvent.
|
||||||
if (borrowValue != 0 && _ltf(Fraction(supplyValue, borrowValue), minCr)) {
|
if (borrowValue != 0 && D18.div(supplyValue, borrowValue) < minCr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// If this is the same account used to in the withdraw/borrow action,
|
// If this is the same account used to in the withdraw/borrow action,
|
||||||
@ -243,12 +218,12 @@ library LibDydxBalance {
|
|||||||
}
|
}
|
||||||
// Compute the deposit/collateralization rate, which is the rate at
|
// Compute the deposit/collateralization rate, which is the rate at
|
||||||
// which (USD) value is added to the account across all markets.
|
// which (USD) value is added to the account across all markets.
|
||||||
Fraction memory dd = Fraction(0, 1);
|
int256 dd = 0;
|
||||||
for (uint256 i = 0; i < info.actions.length - 1; ++i) {
|
for (uint256 i = 0; i < info.actions.length - 1; ++i) {
|
||||||
IDydxBridge.BridgeAction memory deposit = info.actions[i];
|
IDydxBridge.BridgeAction memory deposit = info.actions[i];
|
||||||
assert(deposit.actionType == IDydxBridge.BridgeActionType.Deposit);
|
assert(deposit.actionType == IDydxBridge.BridgeActionType.Deposit);
|
||||||
if (deposit.accountIdx == accountIdx) {
|
if (deposit.accountIdx == accountIdx) {
|
||||||
dd = _addf(
|
dd = D18.add(
|
||||||
dd,
|
dd,
|
||||||
_toQuoteValue(
|
_toQuoteValue(
|
||||||
info.dydx,
|
info.dydx,
|
||||||
@ -260,14 +235,14 @@ library LibDydxBalance {
|
|||||||
}
|
}
|
||||||
// Compute the borrow/withdraw rate, which is the rate at which
|
// Compute the borrow/withdraw rate, which is the rate at which
|
||||||
// (USD) value is deducted from the account.
|
// (USD) value is deducted from the account.
|
||||||
Fraction memory db = _toQuoteValue(
|
int256 db = _toQuoteValue(
|
||||||
info.dydx,
|
info.dydx,
|
||||||
withdraw.marketId,
|
withdraw.marketId,
|
||||||
_getActionRate(withdraw)
|
_getActionRate(withdraw)
|
||||||
);
|
);
|
||||||
// If the deposit to withdraw ratio is >= the minimum collateralization
|
// If the deposit to withdraw ratio is >= the minimum collateralization
|
||||||
// rate, then we will never become insolvent at these prices.
|
// rate, then we will never become insolvent at these prices.
|
||||||
if (_gtef(_divf(dd, db), minCr)) {
|
if (D18.div(dd, db) >= minCr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// The collateralization ratio for this account, parameterized by
|
// The collateralization ratio for this account, parameterized by
|
||||||
@ -275,18 +250,13 @@ library LibDydxBalance {
|
|||||||
// `cr = (supplyValue + t * dd) / (borrowValue + t * db)`
|
// `cr = (supplyValue + t * dd) / (borrowValue + t * db)`
|
||||||
// Solving for `t` gives us:
|
// Solving for `t` gives us:
|
||||||
// `t = (supplyValue - cr * borrowValue) / (cr * db - dd)`
|
// `t = (supplyValue - cr * borrowValue) / (cr * db - dd)`
|
||||||
// TODO(dorothy-zbornak): It'll also revert when getting extremely
|
int256 t = D18.div(
|
||||||
// close to the minimum collateralization ratio.
|
D18.sub(supplyValue, D18.mul(minCr, borrowValue)),
|
||||||
Fraction memory t = _divf(
|
D18.sub(D18.mul(minCr, db), dd)
|
||||||
_subf(
|
|
||||||
Fraction(supplyValue, DYDX_UNITS_BASE),
|
|
||||||
_mulf(minCr, Fraction(borrowValue, DYDX_UNITS_BASE))
|
|
||||||
),
|
|
||||||
_subf(_mulf(minCr, db), dd)
|
|
||||||
);
|
);
|
||||||
solventMakerAmount = LibSafeMath.min256(
|
solventMakerAmount = LibSafeMath.min256(
|
||||||
solventMakerAmount,
|
solventMakerAmount,
|
||||||
t.n.safeDiv(t.d)
|
uint256(D18.clip(t))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,15 +292,13 @@ library LibDydxBalance {
|
|||||||
function _getActionRate(IDydxBridge.BridgeAction memory action)
|
function _getActionRate(IDydxBridge.BridgeAction memory action)
|
||||||
private
|
private
|
||||||
pure
|
pure
|
||||||
returns (Fraction memory rate)
|
returns (int256 rate)
|
||||||
{
|
{
|
||||||
rate = action.conversionRateDenominator == 0
|
rate = action.conversionRateDenominator == 0
|
||||||
? Fraction(1, 1)
|
? D18.one()
|
||||||
: _normalizef(
|
: D18.div(
|
||||||
Fraction(
|
|
||||||
action.conversionRateNumerator,
|
action.conversionRateNumerator,
|
||||||
action.conversionRateDenominator
|
action.conversionRateDenominator
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,35 +308,24 @@ library LibDydxBalance {
|
|||||||
function _getMinimumCollateralizationRatio(IDydx dydx)
|
function _getMinimumCollateralizationRatio(IDydx dydx)
|
||||||
private
|
private
|
||||||
view
|
view
|
||||||
returns (Fraction memory ratio)
|
returns (int256 ratio)
|
||||||
{
|
{
|
||||||
IDydx.RiskParams memory riskParams = dydx.getRiskParams();
|
IDydx.RiskParams memory riskParams = dydx.getRiskParams();
|
||||||
return _normalizef(
|
return D18.toSigned(riskParams.marginRatio.value);
|
||||||
Fraction(
|
|
||||||
riskParams.marginRatio.value,
|
|
||||||
DYDX_UNITS_BASE
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Get the quote (USD) value of a rate within a market.
|
/// @dev Get the quote (USD) value of a rate within a market.
|
||||||
/// @param dydx The Dydx interface.
|
/// @param dydx The Dydx interface.
|
||||||
/// @param marketId Dydx market ID.
|
/// @param marketId Dydx market ID.
|
||||||
/// @param rate Rate to scale by price.
|
/// @param rate Rate to scale by price.
|
||||||
function _toQuoteValue(IDydx dydx, uint256 marketId, Fraction memory rate)
|
function _toQuoteValue(IDydx dydx, uint256 marketId, int256 rate)
|
||||||
private
|
private
|
||||||
view
|
view
|
||||||
returns (Fraction memory quotedRate)
|
returns (int256 quotedRate)
|
||||||
{
|
{
|
||||||
IDydx.Price memory price = dydx.getMarketPrice(marketId);
|
IDydx.Price memory price = dydx.getMarketPrice(marketId);
|
||||||
uint8 tokenDecimals = LibERC20Token.decimals(dydx.getMarketTokenAddress(marketId));
|
uint8 tokenDecimals = LibERC20Token.decimals(dydx.getMarketTokenAddress(marketId));
|
||||||
return _mulf(
|
return D18.mul(D18.div(price.value, 10 ** uint256(tokenDecimals)), rate);
|
||||||
Fraction(
|
|
||||||
price.value,
|
|
||||||
10 ** uint256(DYDX_UNITS_DECIMALS + tokenDecimals)
|
|
||||||
),
|
|
||||||
rate
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Get the total supply and borrow values for an account across all markets.
|
/// @dev Get the total supply and borrow values for an account across all markets.
|
||||||
@ -406,78 +363,4 @@ library LibDydxBalance {
|
|||||||
LibERC20Token.balanceOf(tokenAddress, owner)
|
LibERC20Token.balanceOf(tokenAddress, owner)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** Fraction helpers ***/
|
|
||||||
|
|
||||||
/// @dev Check if `a < b`.
|
|
||||||
function _ltf(Fraction memory a, Fraction memory b)
|
|
||||||
private
|
|
||||||
pure
|
|
||||||
returns (bool isLessThan)
|
|
||||||
{
|
|
||||||
return LibFractions.cmp(a.n, a.d, b.n, b.d) == -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Check if `a > b`.
|
|
||||||
function _gtf(Fraction memory a, Fraction memory b)
|
|
||||||
private
|
|
||||||
pure
|
|
||||||
returns (bool isGreaterThan)
|
|
||||||
{
|
|
||||||
return LibFractions.cmp(a.n, a.d, b.n, b.d) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Check if `a >= b`.
|
|
||||||
function _gtef(Fraction memory a, Fraction memory b)
|
|
||||||
private
|
|
||||||
pure
|
|
||||||
returns (bool isGreaterThanOrEqual)
|
|
||||||
{
|
|
||||||
return !_ltf(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Compute `a + b`.
|
|
||||||
function _addf(Fraction memory a, Fraction memory b)
|
|
||||||
private
|
|
||||||
pure
|
|
||||||
returns (Fraction memory r)
|
|
||||||
{
|
|
||||||
(r.n, r.d) = LibFractions.add(a.n, a.d, b.n, b.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Compute `a - b`.
|
|
||||||
function _subf(Fraction memory a, Fraction memory b)
|
|
||||||
private
|
|
||||||
pure
|
|
||||||
returns (Fraction memory r)
|
|
||||||
{
|
|
||||||
(r.n, r.d) = LibFractions.sub(a.n, a.d, b.n, b.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Compute `a * b`.
|
|
||||||
function _mulf(Fraction memory a, Fraction memory b)
|
|
||||||
private
|
|
||||||
pure
|
|
||||||
returns (Fraction memory r)
|
|
||||||
{
|
|
||||||
(r.n, r.d) = LibFractions.mul(a.n, a.d, b.n, b.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Compute `a / b`.
|
|
||||||
function _divf(Fraction memory a, Fraction memory b)
|
|
||||||
private
|
|
||||||
pure
|
|
||||||
returns (Fraction memory r)
|
|
||||||
{
|
|
||||||
(r.n, r.d) = LibFractions.mul(a.n, a.d, b.d, b.n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Normalize a fraction to prevent arithmetic overflows.
|
|
||||||
function _normalizef(Fraction memory f)
|
|
||||||
private
|
|
||||||
pure
|
|
||||||
returns (Fraction memory r)
|
|
||||||
{
|
|
||||||
(r.n, r.d) = LibFractions.normalize(f.n, f.d);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "DevUtils,LibAssetData,LibDydxBalance,LibOrderTransferSimulation,LibTransactionDecoder",
|
"publicInterfaceContracts": "DevUtils,LibAssetData,LibDydxBalance,LibOrderTransferSimulation,LibTransactionDecoder",
|
||||||
"abis": "./test/generated-artifacts/@(Addresses|AssetBalance|DevUtils|EthBalanceChecker|ExternalFunctions|LibAssetData|LibDydxBalance|LibOrderTransferSimulation|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils|TestDydx|TestLibDydxBalance).json",
|
"abis": "./test/generated-artifacts/@(Addresses|AssetBalance|D18|DevUtils|EthBalanceChecker|ExternalFunctions|LibAssetData|LibDydxBalance|LibOrderTransferSimulation|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils|TestDydx|TestLibDydxBalance).json",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -7,6 +7,7 @@ import { ContractArtifact } from 'ethereum-types';
|
|||||||
|
|
||||||
import * as Addresses from '../test/generated-artifacts/Addresses.json';
|
import * as Addresses from '../test/generated-artifacts/Addresses.json';
|
||||||
import * as AssetBalance from '../test/generated-artifacts/AssetBalance.json';
|
import * as AssetBalance from '../test/generated-artifacts/AssetBalance.json';
|
||||||
|
import * as D18 from '../test/generated-artifacts/D18.json';
|
||||||
import * as DevUtils from '../test/generated-artifacts/DevUtils.json';
|
import * as DevUtils from '../test/generated-artifacts/DevUtils.json';
|
||||||
import * as EthBalanceChecker from '../test/generated-artifacts/EthBalanceChecker.json';
|
import * as EthBalanceChecker from '../test/generated-artifacts/EthBalanceChecker.json';
|
||||||
import * as ExternalFunctions from '../test/generated-artifacts/ExternalFunctions.json';
|
import * as ExternalFunctions from '../test/generated-artifacts/ExternalFunctions.json';
|
||||||
@ -21,6 +22,7 @@ import * as TestLibDydxBalance from '../test/generated-artifacts/TestLibDydxBala
|
|||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
Addresses: Addresses as ContractArtifact,
|
Addresses: Addresses as ContractArtifact,
|
||||||
AssetBalance: AssetBalance as ContractArtifact,
|
AssetBalance: AssetBalance as ContractArtifact,
|
||||||
|
D18: D18 as ContractArtifact,
|
||||||
DevUtils: DevUtils as ContractArtifact,
|
DevUtils: DevUtils as ContractArtifact,
|
||||||
EthBalanceChecker: EthBalanceChecker as ContractArtifact,
|
EthBalanceChecker: EthBalanceChecker as ContractArtifact,
|
||||||
ExternalFunctions: ExternalFunctions as ContractArtifact,
|
ExternalFunctions: ExternalFunctions as ContractArtifact,
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
export * from '../test/generated-wrappers/addresses';
|
export * from '../test/generated-wrappers/addresses';
|
||||||
export * from '../test/generated-wrappers/asset_balance';
|
export * from '../test/generated-wrappers/asset_balance';
|
||||||
|
export * from '../test/generated-wrappers/d18';
|
||||||
export * from '../test/generated-wrappers/dev_utils';
|
export * from '../test/generated-wrappers/dev_utils';
|
||||||
export * from '../test/generated-wrappers/eth_balance_checker';
|
export * from '../test/generated-wrappers/eth_balance_checker';
|
||||||
export * from '../test/generated-wrappers/external_functions';
|
export * from '../test/generated-wrappers/external_functions';
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"generated-artifacts/LibTransactionDecoder.json",
|
"generated-artifacts/LibTransactionDecoder.json",
|
||||||
"test/generated-artifacts/Addresses.json",
|
"test/generated-artifacts/Addresses.json",
|
||||||
"test/generated-artifacts/AssetBalance.json",
|
"test/generated-artifacts/AssetBalance.json",
|
||||||
|
"test/generated-artifacts/D18.json",
|
||||||
"test/generated-artifacts/DevUtils.json",
|
"test/generated-artifacts/DevUtils.json",
|
||||||
"test/generated-artifacts/EthBalanceChecker.json",
|
"test/generated-artifacts/EthBalanceChecker.json",
|
||||||
"test/generated-artifacts/ExternalFunctions.json",
|
"test/generated-artifacts/ExternalFunctions.json",
|
||||||
|
@ -37,10 +37,6 @@
|
|||||||
{
|
{
|
||||||
"note": "Export `EvmBytecodeOutputLinkReferences` type.",
|
"note": "Export `EvmBytecodeOutputLinkReferences` type.",
|
||||||
"pr": 2462
|
"pr": 2462
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Add more functions to `LibFractions`.",
|
|
||||||
"pr": 2466
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timestamp": 1580811564
|
"timestamp": 1580811564
|
||||||
|
@ -37,101 +37,7 @@ library LibFractions {
|
|||||||
.safeMul(d2)
|
.safeMul(d2)
|
||||||
.safeAdd(n2.safeMul(d1));
|
.safeAdd(n2.safeMul(d1));
|
||||||
denominator = d1.safeMul(d2);
|
denominator = d1.safeMul(d2);
|
||||||
return normalize(numerator, denominator);
|
return (numerator, denominator);
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Safely subracts two fractions `n1/d1 - n2/d2`
|
|
||||||
/// @param n1 numerator of `1`
|
|
||||||
/// @param d1 denominator of `1`
|
|
||||||
/// @param n2 numerator of `2`
|
|
||||||
/// @param d2 denominator of `2`
|
|
||||||
/// @return numerator Numerator of sum
|
|
||||||
/// @return denominator Denominator of sum
|
|
||||||
function sub(
|
|
||||||
uint256 n1,
|
|
||||||
uint256 d1,
|
|
||||||
uint256 n2,
|
|
||||||
uint256 d2
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (
|
|
||||||
uint256 numerator,
|
|
||||||
uint256 denominator
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (n2 == 0) {
|
|
||||||
return (numerator = n1, denominator = d1);
|
|
||||||
}
|
|
||||||
numerator = n1
|
|
||||||
.safeMul(d2)
|
|
||||||
.safeSub(n2.safeMul(d1));
|
|
||||||
denominator = d1.safeMul(d2);
|
|
||||||
return normalize(numerator, denominator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Multiply two fractions.
|
|
||||||
/// @param n1 numerator of `1`
|
|
||||||
/// @param d1 denominator of `1`
|
|
||||||
/// @param n2 numerator of `2`
|
|
||||||
/// @param d2 denominator of `2`
|
|
||||||
/// @return numerator numerator of product.
|
|
||||||
/// @return denominator numerator of product.
|
|
||||||
function mul(
|
|
||||||
uint256 n1,
|
|
||||||
uint256 d1,
|
|
||||||
uint256 n2,
|
|
||||||
uint256 d2
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (
|
|
||||||
uint256 numerator,
|
|
||||||
uint256 denominator
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return normalize(n1.safeMul(n2), d1.safeMul(d2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Compares two fractions.
|
|
||||||
/// @param n1 numerator of `1`
|
|
||||||
/// @param d1 denominator of `1`
|
|
||||||
/// @param n2 numerator of `2`
|
|
||||||
/// @param d2 denominator of `2`
|
|
||||||
/// @return compareResult
|
|
||||||
/// `-1` if `n1/d1 < n2/d2`.
|
|
||||||
/// `0` if `n1/d1 == n2/d2`.
|
|
||||||
/// `1` if `n1/d1 > n2/d2`.
|
|
||||||
function cmp(
|
|
||||||
uint256 n1,
|
|
||||||
uint256 d1,
|
|
||||||
uint256 n2,
|
|
||||||
uint256 d2
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (int8 compareResult)
|
|
||||||
{
|
|
||||||
// Handle infinities.
|
|
||||||
if (d1 == 0) {
|
|
||||||
if (d2 == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
if (d2 == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint256 nd1 = n1.safeMul(d2);
|
|
||||||
uint256 nd2 = n2.safeMul(d1);
|
|
||||||
if (nd1 > nd2) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (nd1 < nd2) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Rescales a fraction to prevent overflows during addition if either
|
/// @dev Rescales a fraction to prevent overflows during addition if either
|
||||||
|
Loading…
x
Reference in New Issue
Block a user