Skip to content

Commit ea59d99

Browse files
authored
[Loopring_3.6] improve exchange staking (#1617)
1 parent 685501d commit ea59d99

File tree

10 files changed

+176
-143
lines changed

10 files changed

+176
-143
lines changed

packages/loopring_v3/DESIGN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ The operator contract can also be used to enforce an off-chain data-availability
132132

133133
The operator creates a block and submits it on-chain by calling `submitBlocks`. Multiple blocks can be submitted at the same time. All blocks will be immediately verified. If possible, batch verification is used to verify multiple blocks of the same type.
134134

135-
An operator can only submit new blocks when the the exchange owner has enough LRC staked. For an exchange with data-availability the exchange stake needs to be at least `minExchangeStakeRollup`LRC and for an exchange without data-availability the stake needs to be at least `minExchangeStakeValidium`LRC.
135+
An operator can only submit new blocks when the the exchange owner has enough LRC staked. For the first 10 thousand blocks, this check is skipped. Each exchange stake needs to be at least `stakePerThousandBlocks * numBlocks /1000` USD worth of LRC. The total staking requirement will be cappped at 1,000,000 blocks.
136136

137137
#### Only Allow Off-chain Requests to be Used Once
138138

packages/loopring_v3/contracts/aux/access/LoopringV3Owner.sol

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,25 @@ contract LoopringV3Owner is DelayedOwner
1616

1717
struct Costs
1818
{
19-
uint minExchangeStake;
19+
uint stakePerThousandBlocks;
2020
}
2121

2222
Costs public USD;
2323

2424
event LRCValuesUpdated(
25-
uint minExchangeStakeLRC
25+
uint stakePerThousandBlocks
2626
);
2727

2828
constructor(
2929
ILoopringV3 _loopringV3,
3030
ITokenPriceProvider _provider,
31-
uint _minExchangeStakeUSD
31+
uint _stakePerThousandBlocksUSD
3232
)
3333
DelayedOwner(address(_loopringV3), 3 days)
3434
{
3535
loopringV3 = _loopringV3;
3636
provider = _provider;
37-
USD.minExchangeStake = _minExchangeStakeUSD;
37+
USD.stakePerThousandBlocks = _stakePerThousandBlocksUSD;
3838

3939
setFunctionDelay(loopringV3.transferOwnership.selector, 7 days);
4040
setFunctionDelay(loopringV3.updateSettings.selector, 7 days);
@@ -49,7 +49,7 @@ contract LoopringV3Owner is DelayedOwner
4949
{
5050
// Get the current costs in LRC
5151
Costs memory lrcCosts = Costs(
52-
provider.usd2lrc(USD.minExchangeStake)
52+
provider.usd2lrc(USD.stakePerThousandBlocks)
5353
);
5454

5555
// Set the new LRC values on the protocol contract immediately
@@ -58,11 +58,11 @@ contract LoopringV3Owner is DelayedOwner
5858
loopringV3.blockVerifierAddress(),
5959
loopringV3.exchangeCreationCostLRC(),
6060
loopringV3.forcedWithdrawalFee(),
61-
lrcCosts.minExchangeStake
61+
lrcCosts.stakePerThousandBlocks
6262
);
6363

6464
emit LRCValuesUpdated(
65-
lrcCosts.minExchangeStake
65+
lrcCosts.stakePerThousandBlocks
6666
);
6767
}
6868
}

packages/loopring_v3/contracts/core/iface/ExchangeData.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ library ExchangeData
120120
function TIMESTAMP_HALF_WINDOW_SIZE_IN_SECONDS() internal pure returns (uint32) { return 7 days; }
121121
function MAX_NUM_ACCOUNTS() internal pure returns (uint) { return 2 ** 32; }
122122
function MAX_NUM_TOKENS() internal pure returns (uint) { return 2 ** 16; }
123-
function MIN_AGE_PROTOCOL_FEES_UNTIL_UPDATED() internal pure returns (uint32) { return 1 days; }
124-
function MIN_TIME_IN_SHUTDOWN() internal pure returns (uint32) { return 28 days; }
123+
function MIN_AGE_PROTOCOL_FEES_UNTIL_UPDATED() internal pure returns (uint32) { return 7 days; }
124+
function MIN_TIME_IN_SHUTDOWN() internal pure returns (uint32) { return 30 days; }
125125
// The amount of bytes each rollup transaction uses in the block data for data-availability.
126126
// This is the maximum amount of bytes of all different transaction types.
127127
function TX_DATA_AVAILABILITY_SIZE() internal pure returns (uint32) { return 68; }
128-
function MAX_AGE_DEPOSIT_UNTIL_WITHDRAWABLE_UPPERBOUND() internal pure returns (uint32) { return 14 days; }
128+
function MAX_AGE_DEPOSIT_UNTIL_WITHDRAWABLE_UPPERBOUND() internal pure returns (uint32) { return 15 days; }
129129
function ACCOUNTID_PROTOCOLFEE() internal pure returns (uint32) { return 0; }
130130

131131
struct AccountLeaf

packages/loopring_v3/contracts/core/iface/IExchangeV3.sol

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,22 @@ abstract contract IExchangeV3 is IExchange
183183
view
184184
returns (bool);
185185

186+
/// @dev Returns the number of LRC token required as exchange stake.
187+
/// @return The number of LRC token required as stake.
188+
function getRequiredExchangeStake()
189+
public
190+
virtual
191+
view
192+
returns (uint);
193+
194+
/// @dev Returns whether the Exchange has staked enough to submit blocks.
195+
/// @return True if the exchange has staked enough, else false
196+
function canSubmitBlocks()
197+
external
198+
virtual
199+
view
200+
returns (bool);
201+
186202
// -- Tokens --
187203
/// @dev Registers an ERC20 token for a token id. Note that different exchanges may have
188204
/// different ids for the same ERC20 token.

packages/loopring_v3/contracts/core/iface/ILoopringV3.sol

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ abstract contract ILoopringV3 is ILoopring
5656
uint public forcedWithdrawalFee;
5757
uint public tokenRegistrationFeeLRCBase;
5858
uint public tokenRegistrationFeeLRCDelta;
59-
uint public minExchangeStake;
59+
uint public stakePerThousandBlocks;
6060
uint8 public minProtocolTakerFeeBips;
6161
uint8 public maxProtocolTakerFeeBips;
6262
uint8 public minProtocolMakerFeeBips;
@@ -86,7 +86,7 @@ abstract contract ILoopringV3 is ILoopring
8686
address _blockVerifierAddress, // address(0) not allowed
8787
uint _exchangeCreationCostLRC,
8888
uint _forcedWithdrawalFee,
89-
uint _minExchangeStake
89+
uint _stakePerThousandBlocks
9090
)
9191
external
9292
virtual;
@@ -107,19 +107,6 @@ abstract contract ILoopringV3 is ILoopring
107107
external
108108
virtual;
109109

110-
/// @dev Returns whether the Exchange has staked enough to submit blocks
111-
/// Exchanges with on-chain data-availaiblity need to stake at least
112-
/// minExchangeStake.
113-
/// @param exchangeId The id of the exchange
114-
/// @return True if the exchange has staked enough, else false
115-
function canExchangeSubmitBlocks(
116-
uint exchangeId
117-
)
118-
external
119-
virtual
120-
view
121-
returns (bool);
122-
123110
/// @dev Gets the amount of staked LRC for an exchange.
124111
/// @param exchangeId The id of the exchange
125112
/// @return stakedLRC The amount of LRC

packages/loopring_v3/contracts/core/impl/ExchangeV3.sol

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,24 @@ contract ExchangeV3 is IExchangeV3
170170
return state.isShutdown();
171171
}
172172

173+
function getRequiredExchangeStake()
174+
public
175+
override
176+
view
177+
returns (uint)
178+
{
179+
return state.getRequiredExchangeStake();
180+
}
181+
182+
function canSubmitBlocks()
183+
external
184+
override
185+
view
186+
returns (bool)
187+
{
188+
return state.canSubmitBlocks();
189+
}
190+
173191
// -- Tokens --
174192

175193
function registerToken(

packages/loopring_v3/contracts/core/impl/LoopringV3.sol

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ contract LoopringV3 is ILoopringV3
9191
address _blockVerifierAddress,
9292
uint _exchangeCreationCostLRC,
9393
uint _forcedWithdrawalFee,
94-
uint _minExchangeStake
94+
uint _stakePerThousandBlocks
9595
)
9696
external
9797
override
@@ -103,7 +103,7 @@ contract LoopringV3 is ILoopringV3
103103
_blockVerifierAddress,
104104
_exchangeCreationCostLRC,
105105
_forcedWithdrawalFee,
106-
_minExchangeStake
106+
_stakePerThousandBlocks
107107
);
108108
}
109109

@@ -130,18 +130,6 @@ contract LoopringV3 is ILoopringV3
130130
emit SettingsUpdated(block.timestamp);
131131
}
132132

133-
function canExchangeSubmitBlocks(
134-
uint exchangeId
135-
)
136-
external
137-
override
138-
view
139-
returns (bool)
140-
{
141-
uint amountStaked = getExchangeStake(exchangeId);
142-
return amountStaked >= minExchangeStake;
143-
}
144-
145133
function getExchangeStake(
146134
uint exchangeId
147135
)
@@ -292,11 +280,12 @@ contract LoopringV3 is ILoopringV3
292280
require(exchange.exchangeAddress != address(0), "INVALID_EXCHANGE_ID");
293281

294282
// Subtract the minimum exchange stake, this amount cannot be used to reduce the protocol fees
295-
uint stake = exchange.exchangeStake - minExchangeStake;
296-
297283
// The total stake used here is the exchange stake + the protocol fee stake, but
298284
// the protocol fee stake has a reduced weight of 50%.
299-
uint protocolFeeStake = stake.add(exchange.protocolFeeStake / 2);
285+
286+
uint protocolFeeStake = exchange.exchangeStake
287+
.add(exchange.protocolFeeStake / 2)
288+
.sub(IExchangeV3(exchange.exchangeAddress).getRequiredExchangeStake());
300289

301290
takerFeeBips = calculateProtocolFee(
302291
minProtocolTakerFeeBips, maxProtocolTakerFeeBips, protocolFeeStake, targetProtocolTakerFeeStake
@@ -325,7 +314,7 @@ contract LoopringV3 is ILoopringV3
325314
address _blockVerifierAddress,
326315
uint _exchangeCreationCostLRC,
327316
uint _forcedWithdrawalFee,
328-
uint _minExchangeStake
317+
uint _stakePerThousandBlocks
329318
)
330319
private
331320
{
@@ -336,7 +325,7 @@ contract LoopringV3 is ILoopringV3
336325
blockVerifierAddress = _blockVerifierAddress;
337326
exchangeCreationCostLRC = _exchangeCreationCostLRC;
338327
forcedWithdrawalFee = _forcedWithdrawalFee;
339-
minExchangeStake = _minExchangeStake;
328+
stakePerThousandBlocks = _stakePerThousandBlocks;
340329

341330
emit SettingsUpdated(block.timestamp);
342331
}

packages/loopring_v3/contracts/core/impl/libexchange/ExchangeBlocks.sol

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,50 @@ library ExchangeBlocks
4343
uint8 previousMakerFeeBips
4444
);
4545

46+
function getRequiredExchangeStake(
47+
ExchangeData.State storage S
48+
)
49+
public
50+
view
51+
returns (uint)
52+
{
53+
uint numStakingUnit = S.numBlocks / 1000;
54+
55+
// waive fee for the first 10K blocks.
56+
if (numStakingUnit <= 10) {
57+
return 0;
58+
}
59+
60+
// Cap at 1 million blocks
61+
if (numStakingUnit > 1000) {
62+
numStakingUnit = 1000;
63+
}
64+
65+
return numStakingUnit.mul(S.loopring.stakePerThousandBlocks());
66+
}
67+
68+
function canSubmitBlocks(
69+
ExchangeData.State storage S
70+
)
71+
public
72+
view
73+
returns (bool)
74+
{
75+
uint numStakingUnit = S.numBlocks / 1000;
76+
77+
// waive fee for the first 10K blocks.
78+
if (numStakingUnit <= 10) {
79+
return true;
80+
}
81+
82+
// Cap at 1 million blocks
83+
if (numStakingUnit > 1000) {
84+
numStakingUnit = 1000;
85+
}
86+
87+
return S.loopring.getExchangeStake(S.id) >= getRequiredExchangeStake(S);
88+
}
89+
4690
function submitBlocks(
4791
ExchangeData.State storage S,
4892
ExchangeData.Block[] memory blocks,
@@ -53,11 +97,7 @@ library ExchangeBlocks
5397
// Exchange cannot be in withdrawal mode
5498
require(!S.isInWithdrawalMode(), "INVALID_MODE");
5599

56-
// Check if this exchange has a minimal amount of LRC staked
57-
require(
58-
S.loopring.canExchangeSubmitBlocks(S.id),
59-
"INSUFFICIENT_EXCHANGE_STAKE"
60-
);
100+
require(canSubmitBlocks(S), "INSUFFICIENT_EXCHANGE_STAKE");
61101

62102
// Commit the blocks
63103
bytes32[] memory publicDataHashes = new bytes32[](blocks.length);

0 commit comments

Comments
 (0)