Skip to content

[protocol 3.6] uint96 safe math #1766

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

Merged
merged 2 commits into from
Sep 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/loopring_v3/contracts/core/iface/IExchangeV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ abstract contract IExchangeV3 is IExchange
address from,
address to,
address token,
uint96 amount
uint amount
);

event WithdrawalFailed(
address from,
address to,
address token,
uint96 amount
uint amount
);

event ProtocolFeesUpdated(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "../../lib/Claimable.sol";
import "../../lib/ERC20.sol";
import "../../lib/ERC20SafeTransfer.sol";
import "../../lib/MathUint.sol";
import "../../thirdparty/SafeCast.sol";
import "../iface/IDepositContract.sol";


Expand All @@ -24,6 +25,7 @@ contract DefaultDepositContract is IDepositContract, Claimable
using AddressUtil for address;
using ERC20SafeTransfer for address;
using MathUint for uint;
using SafeCast for uint;

address public exchange;

Expand Down Expand Up @@ -108,8 +110,7 @@ contract DefaultDepositContract is IDepositContract, Claimable

uint balanceAfter = checkBalance ? ERC20(token).balanceOf(address(this)) : amount;
uint diff = balanceAfter.sub(balanceBefore);
amountReceived = uint96(diff);
require(uint(amountReceived) == diff, "OUT_OF_RANGE");
amountReceived = diff.toUint96();

ethToReturn = msg.value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "../../../lib/AddressUtil.sol";
import "../../../lib/MathUint96.sol";
import "../../iface/ExchangeData.sol";
import "./ExchangeMode.sol";
import "./ExchangeTokens.sol";
Expand All @@ -15,9 +16,7 @@ import "./ExchangeTokens.sol";
library ExchangeDeposits
{
using AddressUtil for address payable;
using MathUint for uint;
using MathUint for uint64;
using MathUint for uint96;
using MathUint96 for uint96;
using ExchangeMode for ExchangeData.State;
using ExchangeTokens for ExchangeData.State;

Expand Down Expand Up @@ -57,14 +56,14 @@ library ExchangeDeposits
// Add the amount to the deposit request and reset the time the operator has to process it
ExchangeData.Deposit memory _deposit = S.pendingDeposits[to][tokenID];
_deposit.timestamp = uint64(block.timestamp);
_deposit.amount = _deposit.amount.add96(amountDeposited);
_deposit.amount = _deposit.amount.add(amountDeposited);
S.pendingDeposits[to][tokenID] = _deposit;

emit DepositRequested(
to,
tokenAddress,
tokenID,
uint96(amountDeposited)
amountDeposited
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ library ExchangeWithdrawals
address from,
address to,
address token,
uint96 amount
uint amount
);

event WithdrawalFailed(
address from,
address to,
address token,
uint96 amount
uint amount
);

function forceWithdraw(
Expand Down Expand Up @@ -262,7 +262,7 @@ library ExchangeWithdrawals
from,
to,
token,
uint96(amount)
amount
);
if (from == address(0)) {
S.protocolFeeLastWithdrawnTime[token] = block.timestamp;
Expand All @@ -272,7 +272,7 @@ library ExchangeWithdrawals
from,
to,
token,
uint96(amount)
amount
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ library AccountUpdateTransaction
address owner;
uint32 accountID;
uint16 feeTokenID;
uint fee;
uint96 fee;
uint publicKey;
uint32 validUntil;
uint32 nonce;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "../../../lib/EIP712.sol";
import "../../../lib/MathUint.sol";
import "../../../lib/MathUint96.sol";
import "../../../lib/SignatureUtil.sol";
import "../../../thirdparty/BytesUtil.sol";
import "../../iface/ExchangeData.sol";
Expand All @@ -14,15 +14,15 @@ import "../../iface/ExchangeData.sol";
/// @author Brecht Devos - <brecht@loopring.org>
library DepositTransaction
{
using BytesUtil for bytes;
using MathUint for uint;
using BytesUtil for bytes;
using MathUint96 for uint96;

struct Deposit
{
address owner;
uint32 accountID;
uint16 tokenID;
uint amount;
uint96 amount;
}

/*event DepositProcessed(
Expand Down Expand Up @@ -55,7 +55,7 @@ library DepositTransaction
// Also note the original deposit.amount can be zero!
if (deposit.amount > 0) {
require(pendingDeposit.amount >= deposit.amount, "INVALID_AMOUNT");
pendingDeposit.amount = uint96(uint(pendingDeposit.amount).sub(deposit.amount));
pendingDeposit.amount = pendingDeposit.amount.sub(deposit.amount);
}

// If the deposit was fully consumed, reset it so the storage is freed up
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ library TransferTransaction
address from;
address to;
uint16 tokenID;
uint amount;
uint96 amount;
uint16 feeTokenID;
uint fee;
uint96 fee;
uint32 validUntil;
uint32 storageID;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ library WithdrawTransaction
address owner;
uint32 accountID;
uint16 tokenID;
uint amount;
uint96 amount;
uint16 feeTokenID;
uint fee;
uint96 fee;
address to;
bytes extraData;
uint minGas;
Expand Down
7 changes: 4 additions & 3 deletions packages/loopring_v3/contracts/lib/FloatUtil.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
pragma solidity ^0.7.0;

import "./MathUint.sol";
import "../thirdparty/SafeCast.sol";


/// @title Utility Functions for floats
/// @author Brecht Devos - <brecht@loopring.org>
library FloatUtil
{
using MathUint for uint;
using SafeCast for uint;

// Decodes a decimal float value that is encoded like `exponent | mantissa`.
// Both exponent and mantissa are in base 10.
Expand All @@ -24,14 +26,13 @@ library FloatUtil
)
internal
pure
returns (uint value)
returns (uint96 value)
{
uint numBitsMantissa = numBits.sub(5);
uint exponent = f >> numBitsMantissa;
// log2(10**77) = 255.79 < 256
require(exponent <= 77, "EXPONENT_TOO_LARGE");
uint mantissa = f & ((1 << numBitsMantissa) - 1);
value = mantissa.mul(10 ** exponent);
require(value < (2 ** 96), "FLOAT_VALUE_TOO_LARGE");
value = mantissa.mul(10 ** exponent).toUint96();
}
}
12 changes: 0 additions & 12 deletions packages/loopring_v3/contracts/lib/MathUint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,4 @@ library MathUint
c = a + b;
require(c >= a, "ADD_OVERFLOW");
}

function add96(
uint96 a,
uint96 b
)
internal
pure
returns (uint96 c)
{
c = a + b;
require(c >= a, "ADD_OVERFLOW");
}
}
33 changes: 33 additions & 0 deletions packages/loopring_v3/contracts/lib/MathUint96.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;


/// @title Utility Functions for uint
/// @author Daniel Wang - <daniel@loopring.org>
library MathUint96
{
function add(
uint96 a,
uint96 b
)
internal
pure
returns (uint96 c)
{
c = a + b;
require(c >= a, "ADD_OVERFLOW");
}

function sub(
uint96 a,
uint96 b
)
internal
pure
returns (uint96 c)
{
require(b <= a, "SUB_UNDERFLOW");
return a - b;
}
}
Loading