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

Xl/delayed upgrade 3.6.3 v3 #2737

Open
wants to merge 10 commits into
base: release_loopring_3.6.3
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;

import "../../lib/Claimable.sol";
import "../../thirdparty/BytesUtil.sol";
import "./DelayedTransaction.sol";

/// @title DelayedSelectorBasedAccessManager
/// @author Break Xiong - <kl456123@outlook.com>
contract DelayedSelectorBasedAccessManager is DelayedTransaction, Claimable {
using BytesUtil for bytes;

address public immutable target;
mapping(address => mapping(bytes4 => bool)) public permissions;

event PermissionUpdate(
address indexed user,
bytes4 indexed selector,
bool allowed
);

modifier withAccess(bytes4 selector) {
require(hasAccessTo(msg.sender, selector), "PERMISSION_DENIED");
_;
}

constructor(
address _target,
uint _timeToLive
) DelayedTransaction(_timeToLive) {
require(_target != address(0), "ZERO_ADDRESS");
target = _target;
}

receive() external payable {}

fallback() external payable {
transact(msg.data);
}

function grantAccess(
address user,
bytes4 selector,
bool granted
) external onlyOwner {
require(permissions[user][selector] != granted, "INVALID_VALUE");
permissions[user][selector] = granted;
emit PermissionUpdate(user, selector, granted);
}

function transact(
bytes calldata data
) public payable withAccess(data.toBytes4(0)) {
transactInternal(target, msg.value, data);
}

function transact(
address,
bytes calldata
) external payable override nonReentrant onlyAuthorized {
revert("Deprecated");
}

function hasAccessTo(
address user,
bytes4 selector
) public view returns (bool) {
return user == owner || permissions[user][selector];
}

function isAuthorizedForTransactions(
address sender
) internal view override returns (bool) {
return hasAccessTo(sender, msg.data.toBytes4(0));
}

function setFunctionDelay(bytes4 functionSelector, uint delay) internal {
setFunctionDelay(target, functionSelector, delay);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ abstract contract DelayedTransaction is IDelayedTransaction, ReentrancyGuard
bytes calldata data
)
external
payable
virtual
override
nonReentrant
payable
onlyAuthorized
{
transactInternal(to, msg.value, data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import "../../lib/Drainable.sol";
import "../../lib/ERC1271.sol";
import "../../lib/MathUint.sol";
import "../../lib/SignatureUtil.sol";
import "./SelectorBasedAccessManager.sol";
import "./DelayedSelectorBasedAccessManager.sol";
import "./IBlockReceiver.sol";


contract LoopringIOExchangeOwner is SelectorBasedAccessManager, ERC1271, Drainable
contract LoopringIOExchangeOwner is DelayedSelectorBasedAccessManager, ERC1271, Drainable
{
using AddressUtil for address;
using AddressUtil for address payable;
Expand Down Expand Up @@ -53,8 +53,10 @@ contract LoopringIOExchangeOwner is SelectorBasedAccessManager, ERC1271, Drainab
constructor(
address _exchange
)
SelectorBasedAccessManager(_exchange)
DelayedSelectorBasedAccessManager(_exchange, 3 days)
{
setFunctionDelay(IExchangeV3.setLoopring.selector, 7 days);
setFunctionDelay(IExchangeV3.refreshBlockVerifier.selector, 7 days);
}

function openAccessToSubmitBlocks(bool _open)
Expand Down
18 changes: 18 additions & 0 deletions packages/loopring_v3/contracts/aux/access/LoopringV3Owner.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;

import "../../core/iface/ILoopringV3.sol";
import "./DelayedOwner.sol";

/// @title LoopringV3Owner
/// @author Break Xiong - <kl456123@outlook.com>
contract LoopringV3Owner is DelayedOwner {
constructor(
ILoopringV3 loopringV3
) DelayedOwner(address(loopringV3), 3 days) {
setFunctionDelay(loopringV3.transferOwnership.selector, 7 days);
setFunctionDelay(loopringV3.updateSettings.selector, 7 days);
setFunctionDelay(loopringV3.updateProtocolFeeSettings.selector, 1 days);
}
}
26 changes: 26 additions & 0 deletions packages/loopring_v3/contracts/aux/access/ProxyOwner.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;

import "./DelayedOwner.sol";

/// @title IProxy
/// @author Break Xiong - <kl456123@outlook.com>
interface IProxy {
function transferProxyOwnership(address newOwner) external;
function upgradeTo(address implementation) external;
function upgradeToAndCall(
address implementation,
bytes memory data
) external payable;
}

/// @title ProxyOwner
/// @author Break Xiong - <kl456123@outlook.com>
contract ProxyOwner is DelayedOwner {
constructor(IProxy proxy) DelayedOwner(address(proxy), 3 days) {
setFunctionDelay(proxy.transferProxyOwnership.selector, 7 days);
setFunctionDelay(proxy.upgradeTo.selector, 7 days);
setFunctionDelay(proxy.upgradeToAndCall.selector, 7 days);
}
}
2 changes: 2 additions & 0 deletions packages/loopring_v3/contracts/core/iface/ExchangeData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ library ExchangeData
// This is the prime number that is used for the alt_bn128 elliptic curve, see EIP-196.
uint public constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

// 0.1% of pending deposited amount
uint public constant MIN_DEPOSIT_PERCENTAGE = 1;
uint public constant MAX_OPEN_FORCED_REQUESTS = 4096;
uint public constant MAX_AGE_FORCED_REQUEST_UNTIL_WITHDRAW_MODE = 15 days;
uint public constant TIMESTAMP_HALF_WINDOW_SIZE_IN_SECONDS = 7 days;
Expand Down
3 changes: 3 additions & 0 deletions packages/loopring_v3/contracts/core/iface/IExchangeV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ abstract contract IExchangeV3 is Claimable
virtual
external;

function getLoopring() external view virtual returns (address);
function setLoopring(address loopringAddr) external virtual;

/// @dev Initialized the agent registry contract used by the exchange.
/// Can only be called by the exchange owner once.
/// @param agentRegistry The agent registry contract to be used
Expand Down
21 changes: 21 additions & 0 deletions packages/loopring_v3/contracts/core/impl/ExchangeV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,27 @@ contract ExchangeV3 is IExchangeV3, ReentrancyGuard, ERC1155Holder, ERC721Holder
);
}

function setLoopring(address _loopringAddr)
external
override
nonReentrant
onlyOwner
{
require(_loopringAddr != address(0), "ZERO_ADDRESS");
// set loopring
state.loopringAddr = _loopringAddr;
state.loopring = ILoopringV3(_loopringAddr);
}

function getLoopring()
external
view
override
returns (address)
{
return state.loopringAddr;
}

function setAgentRegistry(address _agentRegistry)
external
override
Expand Down
4 changes: 4 additions & 0 deletions packages/loopring_v3/contracts/core/impl/LoopringV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ contract LoopringV3 is ILoopringV3, ReentrancyGuard
{
require(address(0) != _protocolFeeVault, "ZERO_ADDRESS");
require(address(0) != _blockVerifierAddress, "ZERO_ADDRESS");
require(
_forcedWithdrawalFee <= 0.5 ether,
"FORCED_WITHDRAWAL_FEE_TOO_HIGH"
);

protocolFeeVault = _protocolFeeVault;
blockVerifierAddress = _blockVerifierAddress;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,16 @@ library ExchangeDeposits
// Allow depositing with amount == 0 to allow updating the deposit timestamp

uint16 tokenID = S.getTokenID(tokenAddress);
ExchangeData.Deposit memory _deposit = S.pendingDeposits[to][tokenID];
// prevent from attackers to deposit too little tokens
require(
amount * 1000 >=
_deposit.amount * ExchangeData.MIN_DEPOSIT_PERCENTAGE,
"DEPOSIT_TOO_LITTLE"
);

if (tokenID == 0 && amount == 0) {
require(msg.value == 0), "INVALID_ETH_DEPOSIT");
require(msg.value == 0, "INVALID_ETH_DEPOSIT");
}

// Transfer the tokens to this contract
Expand All @@ -71,7 +78,6 @@ 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.add(amountDeposited);
S.pendingDeposits[to][tokenID] = _deposit;
Expand Down