Skip to content

Commit a27649a

Browse files
Brechtpdkongliangzhong
authored andcommitted
[Protocol3] Some minor cleanup/enhancements + More tests (#253)
* [Protocol3] Removed FINALIZED block state + misc cleanup * [Protocol3] Improved tests * [Protocol3] Added some tests/fixed some typos * [Protocol3] Added some tests for overflow checking * [Protocol3] Fixed issue after updating node version
1 parent f168779 commit a27649a

28 files changed

+453
-183
lines changed

packages/loopring_v3/contracts/iface/IExchange.sol

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ contract IExchange
181181
/// depositFee +
182182
/// (isAccountNew ? accountCreationFee : 0) +
183183
/// (isAccountUpdated ? accountUpdateFee : 0)
184-
/// If the user sends too much ETH the surplus is immediatly sent back.
184+
/// If the user sends too much ETH the surplus is sent back immediately.
185185
///
186186
/// Note that after such an operation, it will take the operator some
187187
/// time (no more than MAX_AGE_REQUEST_UNTIL_FORCED) to process the request
@@ -477,11 +477,11 @@ contract IExchange
477477
/// - WalletSplitPercentage: 1 byte
478478
///
479479
/// The RING_SETTLEMENT data availability data is further transformed
480-
/// to make it more compressable:
480+
/// to make it more compressible:
481481
/// - The Ring-matcher account ID, fee amount and token ID (the first 5 bytes) are
482482
/// XORed with the corresponding data from the previous ring
483483
/// - To group more similar data together we don't store all data
484-
/// for a ring next to eachother but group them together for all rings.
484+
/// for a ring next to each other but group them together for all rings.
485485
/// For ALL rings, sequentially:
486486
/// - Ring-matcher account ID + fee + Token ID
487487
/// - orderA.orderID + orderB.orderID
@@ -497,7 +497,7 @@ contract IExchange
497497
/// - Mode 1: An IDecompressor address (20 bytes) is stored after the mode byte.
498498
/// IDecompressor.decompress() will be called to decompress the following data.
499499
/// @param offchainData Arbitrary data for off-chain data-availability, i.e.,
500-
/// the multihash of the IPFS file that containts the block data.
500+
/// the multihash of the IPFS file that contains the block data.
501501
function commitBlock(
502502
uint8 blockType,
503503
uint16 blockSize,
@@ -507,7 +507,7 @@ contract IExchange
507507
)
508508
external;
509509

510-
/// @dev Submit a ZK proof onchain to verify a previouly committed block. Submitting an
510+
/// @dev Submit a ZK proof onchain to verify a previously committed block. Submitting an
511511
/// invalid proof will not change the state of the exchange. Note that proofs can
512512
/// be submitted in a different order than the blocks themselves.
513513
///
@@ -583,7 +583,7 @@ contract IExchange
583583
/// depositFee +
584584
/// (isAccountNew ? accountCreationFee : 0) +
585585
/// (isAccountUpdated ? accountUpdateFee : 0)
586-
/// If the user sends too much ETH the surplus is immediatly sent back.
586+
/// If the user sends too much ETH the surplus is sent back immediately.
587587
///
588588
/// Note that after such an operation, it will take the operator some
589589
/// time (no more than MAX_AGE_REQUEST_UNTIL_FORCED) to process the request
@@ -616,17 +616,17 @@ contract IExchange
616616
/// @dev Deposit Ether or ERC20 tokens to the sender's account.
617617
///
618618
/// The total fee in ETH that the user needs to pay is 'depositFee'.
619-
/// If the user sends too much ETH the surplus is immediatly sent back.
619+
/// If the user sends too much ETH the surplus is sent back immediately.
620620
///
621621
/// Note that after such an operation, it will take the operator some
622622
/// time (no more than MAX_AGE_REQUEST_UNTIL_FORCED) to process the request
623623
/// and create the deposit to the offchain account.
624624
///
625625
/// Warning: the DEX UI should warn their users not to deposit more than 2^96 - 1
626626
/// tokens in total. If that happens, the user may lose token.
627-
/// This token balance upper limit, however, is large enought for most scenarios.
627+
/// This token balance upper limit, however, is large enough for most scenarios.
628628
///
629-
/// @param tokenAddress The adderss of the token, use `0x0` for Ether.
629+
/// @param tokenAddress The address of the token, use `0x0` for Ether.
630630
/// @param amount The amount of tokens to deposit
631631
function deposit(
632632
address tokenAddress,
@@ -638,15 +638,15 @@ contract IExchange
638638
/// @dev Deposit Ether or ERC20 tokens to a recipient account.
639639
///
640640
/// The total fee in ETH that the user needs to pay is 'depositFee'.
641-
/// If the user sends too much ETH the surplus is immediatly sent back.
641+
/// If the user sends too much ETH the surplus is sent back immediately.
642642
///
643643
/// Note that after such an operation, it will take the operator some
644644
/// time (no more than MAX_AGE_REQUEST_UNTIL_FORCED) to process the request
645645
/// and create the deposit to the offchain account.
646646
///
647647
/// Warning: the DEX UI should warn their users not to deposit more than 2^96 - 1
648648
/// tokens in total. If that happens, the user may lose token.
649-
/// This token balance upper limit, however, is large enought for most scenarios.
649+
/// This token balance upper limit, however, is large enough for most scenarios.
650650
///
651651
/// @param recipient The address of the recipient
652652
/// @param tokenAddress The adderss of the token, use `0x0` for Ether.
@@ -699,7 +699,7 @@ contract IExchange
699699
/// Only the owner of the account can request a withdrawal.
700700
///
701701
/// The total fee in ETH that the user needs to pay is 'withdrawalFee'.
702-
/// If the user sends too much ETH the surplus is immediatly sent back.
702+
/// If the user sends too much ETH the surplus is sent back immediately.
703703
///
704704
/// Note that after such an operation, it will take the operator some
705705
/// time (no more than MAX_AGE_REQUEST_UNTIL_FORCED) to process the request
@@ -731,7 +731,7 @@ contract IExchange
731731
payable;
732732

733733
/// @dev Allows an account owner to withdraw his funds using the balances stored
734-
/// in the merkle tree. The funds will be sent to the owner of the acount.
734+
/// in the merkle tree. The funds will be sent to the owner of the account.
735735
///
736736
/// Trading pubKey matching the offchain Merkle tree need to be provided.
737737
/// The pubKey may already be reset to 0 when the exchange is shutdown.
@@ -824,7 +824,7 @@ contract IExchange
824824
/// @dev Allows withdrawing funds after a withdrawal request (either onchain
825825
/// or offchain) was committed in a block by the operator.
826826
///
827-
/// Can be called by anyone. The withdrawan tokens will be sent to
827+
/// Can be called by anyone. The withdrawn tokens will be sent to
828828
/// the owner of the account they were withdrawn out.
829829
///
830830
/// Normally it is should not be needed for users to call this manually.
@@ -946,7 +946,7 @@ contract IExchange
946946
/// @dev Starts or continues maintenance mode for the specified duration.
947947
/// The necessary additional downtime minutes will be purchased. The number of
948948
/// downtime minutes still available for use can be checked with getRemainingDowntime().
949-
/// In maintainance mode, all onchain user requests, including account creation,
949+
/// In maintenance mode, all onchain user requests, including account creation,
950950
/// account update, deposits, and withdrawal requests are disabled.
951951
///
952952
/// The remaining downtime time will be extended so that the exchange can stay in
@@ -955,7 +955,7 @@ contract IExchange
955955
/// The exchange owner can exit maintenance mode by calling stopMaintenanceMode()
956956
/// or by waiting until the remaining downtime is reduced to 0.
957957
///
958-
/// Once entering the maintainance mode, the operator should still fulfill his duty
958+
/// Once entering the maintenance mode, the operator should still fulfill his duty
959959
/// by submitting blocks and proofs until all pending user requests have been taken
960960
/// care of within the required timeouts. In the maintenance mode, operator can no longer
961961
/// submit settlement blocks.
@@ -1015,7 +1015,7 @@ contract IExchange
10151015
///
10161016
/// Note that the exchange can still enter the withdrawal mode after this function
10171017
/// has been invoked successfully. To prevent entering the withdrawal mode, exchange
1018-
/// operators need to reset the Merkle tree to its initial state by doingwithdrawals
1018+
/// operators need to reset the Merkle tree to its initial state by doing withdrawals
10191019
/// within MAX_TIME_IN_SHUTDOWN_BASE + (accounts.length * MAX_TIME_IN_SHUTDOWN_DELTA)
10201020
/// seconds.
10211021
///
@@ -1028,9 +1028,9 @@ contract IExchange
10281028

10291029
/// @dev Get number of available/processed deposits/withdrawals.
10301030
/// @return numDepositRequestsProcessed The num of the processed deposit requests
1031-
/// @return numAvailableDepositSlots The number of slots avalable for deposits
1031+
/// @return numAvailableDepositSlots The number of slots available for deposits
10321032
/// @return numWithdrawalRequestsProcessed The num of processed withdrawal requests
1033-
/// @return numAvailableWithdrawalSlots The number of slots avalable for withdrawals
1033+
/// @return numAvailableWithdrawalSlots The number of slots available for withdrawals
10341034
function getRequestStats()
10351035
external
10361036
view

packages/loopring_v3/contracts/iface/ILoopringV3.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ contract ILoopringV3
148148
/// @param onchainDataAvailability True if "Data Availability" is turned on for this
149149
/// exchange. Note that this value can not be changed once the exchange is created.
150150
/// @return exchangeId The id of the exchange.
151-
/// @return exchangeAddress The address of the newly depolyed exchange contract.
151+
/// @return exchangeAddress The address of the newly deployed exchange contract.
152152
function createExchange(
153153
address payable operator,
154154
bool onchainDataAvailability

packages/loopring_v3/contracts/impl/BlockVerifier.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ contract BlockVerifier is IBlockVerifier, Claimable
8585
vk[7], vk[8], vk[9], vk[10], vk[11], vk[12], vk[13]
8686
];
8787
uint256[4] memory _vk_gammaABC = [vk[14], vk[15], vk[16], vk[17]];
88+
// Maybe we should strip the highest bits of the hash so we don't have any overflow (uint256/prime field)
8889
uint256[1] memory publicInputs = [uint256(publicDataHash)];
8990

9091
return Verifier.Verify(_vk, _vk_gammaABC, proof, publicInputs);

packages/loopring_v3/contracts/impl/Exchange.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ contract Exchange is IExchange, Claimable, ReentrancyGuard
666666
require(blockIdx < state.blocks.length, "INVALID_BLOCK_IDX");
667667
ExchangeData.Block storage withdrawBlock = state.blocks[blockIdx];
668668
state.withdrawFromApprovedWithdrawal(
669+
blockIdx,
669670
withdrawBlock,
670671
slotIdx,
671672
false

packages/loopring_v3/contracts/impl/libexchange/ExchangeAccounts.sol

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,18 @@
1616
*/
1717
pragma solidity 0.5.7;
1818

19-
import "../../lib/AddressUtil.sol";
20-
import "../../lib/BurnableERC20.sol";
21-
import "../../lib/ERC20SafeTransfer.sol";
2219
import "../../lib/MathUint.sol";
2320

24-
import "./ExchangeAccounts.sol";
2521
import "./ExchangeBalances.sol";
2622
import "./ExchangeData.sol";
27-
import "./ExchangeMode.sol";
2823

2924

3025
/// @title ExchangeAccounts.
3126
/// @author Daniel Wang - <[email protected]>
3227
/// @author Brecht Devos - <[email protected]>
3328
library ExchangeAccounts
3429
{
35-
using AddressUtil for address payable;
3630
using MathUint for uint;
37-
using ExchangeMode for ExchangeData.State;
3831
using ExchangeBalances for ExchangeData.State;
3932

4033
event AccountCreated(
@@ -70,7 +63,6 @@ library ExchangeAccounts
7063
pubKeyY = account.pubKeyY;
7164
}
7265

73-
// We do allow pubkeyX and/or pubkeyY to be 0.
7466
function createOrUpdateAccount(
7567
ExchangeData.State storage S,
7668
uint pubKeyX,
@@ -161,7 +153,7 @@ library ExchangeAccounts
161153
returns (uint24 accountID)
162154
{
163155
accountID = S.ownerToAccountId[owner];
164-
require(accountID != 0, "SENDER_HAS_NO_ACCOUNT");
156+
require(accountID != 0, "ADDRESS_HAS_NO_ACCOUNT");
165157

166158
accountID = accountID - 1;
167159
}

packages/loopring_v3/contracts/impl/libexchange/ExchangeAdmins.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import "./ExchangeData.sol";
2525
import "./ExchangeMode.sol";
2626

2727

28-
/// @title ExchangeAccounts.
28+
/// @title ExchangeAdmins.
2929
/// @author Daniel Wang - <[email protected]>
3030
/// @author Brecht Devos - <[email protected]>
3131
library ExchangeAdmins
@@ -210,8 +210,8 @@ library ExchangeAdmins
210210

211211
// Exchange needs to be shutdown
212212
require(S.isShutdown(), "EXCHANGE_NOT_SHUTDOWN");
213-
// Last block needs to be finalized
214-
require(lastBlock.state == ExchangeData.BlockState.FINALIZED, "BLOCK_NOT_FINALIZED");
213+
// All blocks needs to be finalized
214+
require(S.blocks.length == S.numBlocksFinalized, "BLOCK_NOT_FINALIZED");
215215
// We also require that all deposit requests are processed
216216
require(lastBlock.numDepositRequestsCommitted == S.depositChain.length, "DEPOSITS_NOT_PROCESSED");
217217
// Merkle root needs to be reset to the genesis block

packages/loopring_v3/contracts/impl/libexchange/ExchangeBalances.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import "../../lib/MathUint.sol";
2121
import "../../thirdparty/MiMC.sol";
2222

2323

24-
/// @title IManagingMode.
24+
/// @title ExchangeBalances.
2525
/// @author Daniel Wang - <[email protected]>
2626
/// @author Brecht Devos - <[email protected]>
2727
library ExchangeBalances

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

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
*/
1717
pragma solidity 0.5.7;
1818

19-
import "../../lib/BurnableERC20.sol";
2019
import "../../lib/BytesUtil.sol";
21-
import "../../lib/ERC20SafeTransfer.sol";
2220
import "../../lib/MathUint.sol";
2321

2422
import "../../iface/IBlockVerifier.sol";
@@ -108,6 +106,7 @@ library ExchangeBlocks
108106
"PROOF_TOO_LATE"
109107
);
110108

109+
// Verify the proof
111110
require(
112111
S.blockVerifier.verifyProof(
113112
uint8(specifiedBlock.blockType),
@@ -120,29 +119,21 @@ library ExchangeBlocks
120119
"INVALID_PROOF"
121120
);
122121

123-
// Update state of this block and potentially the following blocks
124-
ExchangeData.Block storage previousBlock = S.blocks[blockIdx - 1];
125-
if (previousBlock.state == ExchangeData.BlockState.FINALIZED) {
126-
specifiedBlock.state = ExchangeData.BlockState.FINALIZED;
127-
S.numBlocksFinalized = blockIdx + 1;
128-
emit BlockFinalized(blockIdx);
129-
// The next blocks could become finalized as well so check this now
130-
// The number of blocks after the specified block index is limited
131-
// by MAX_GAP_BETWEEN_FINALIZED_AND_VERIFIED_BLOCKS
132-
// so we don't have to worry about running out of gas in this loop
133-
uint nextBlockIdx = blockIdx + 1;
134-
while (nextBlockIdx < S.blocks.length &&
135-
S.blocks[nextBlockIdx].state == ExchangeData.BlockState.VERIFIED) {
136-
137-
S.blocks[nextBlockIdx].state = ExchangeData.BlockState.FINALIZED;
138-
S.numBlocksFinalized = nextBlockIdx + 1;
139-
emit BlockFinalized(nextBlockIdx);
140-
nextBlockIdx++;
141-
}
142-
} else {
143-
specifiedBlock.state = ExchangeData.BlockState.VERIFIED;
144-
emit BlockVerified(blockIdx);
122+
// Mark the block as verified
123+
specifiedBlock.state = ExchangeData.BlockState.VERIFIED;
124+
emit BlockVerified(blockIdx);
125+
126+
// Update the number of blocks that are finalized
127+
// The number of blocks after the specified block index is limited
128+
// by MAX_GAP_BETWEEN_FINALIZED_AND_VERIFIED_BLOCKS
129+
// so we don't have to worry about running out of gas in this loop
130+
uint idx = S.numBlocksFinalized;
131+
while (idx < S.blocks.length &&
132+
S.blocks[idx].state == ExchangeData.BlockState.VERIFIED) {
133+
emit BlockFinalized(idx);
134+
idx++;
145135
}
136+
S.numBlocksFinalized = idx;
146137
}
147138

148139
function revertBlock(
@@ -159,9 +150,8 @@ library ExchangeBlocks
159150
require(specifiedBlock.state == ExchangeData.BlockState.COMMITTED, "INVALID_BLOCK_STATE");
160151

161152
// The specified block needs to be the first block not finalized
162-
// (this way we always revert to a guaranteed valid block and don't need to revert multiple times)
163-
ExchangeData.Block storage previousBlock = S.blocks[uint(blockIdx).sub(1)];
164-
require(previousBlock.state == ExchangeData.BlockState.FINALIZED, "PREV_BLOCK_NOT_FINALIZED");
153+
// (this way we always revert to a guaranteed valid block and don't revert multiple times)
154+
require(blockIdx == S.numBlocksFinalized, "PREV_BLOCK_NOT_FINALIZED");
165155

166156
// Check if this block is verified too late
167157
require(

packages/loopring_v3/contracts/impl/libexchange/ExchangeData.sol

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import "../../iface/ILoopringV3.sol";
2323
/// @title ExchangeData
2424
/// @author Daniel Wang - <[email protected]>
2525
/// @author Brecht Devos - <[email protected]>
26-
2726
library ExchangeData
2827
{
2928
// -- Enums --
@@ -47,12 +46,8 @@ library ExchangeData
4746
COMMITTED, // = 1
4847

4948
// A valid ZK proof has been submitted for this block.
50-
VERIFIED, // = 2
51-
52-
// A block's state will become FINALIZED when and only when this block is VERIFIED
53-
// and all previous blocks in the chain have become FINALIZED. The genesis block is
54-
// FINALIZED by default.
55-
FINALIZED // = 3
49+
// The genesis block is VERIFIED by default.
50+
VERIFIED // = 2
5651
}
5752

5853
// -- Structs --
@@ -167,7 +162,7 @@ library ExchangeData
167162
}
168163

169164
function MAX_PROOF_GENERATION_TIME_IN_SECONDS() internal pure returns (uint32) { return 1 hours; }
170-
function MAX_GAP_BETWEEN_FINALIZED_AND_VERIFIED_BLOCKS() internal pure returns (uint32) { return 1000; }
165+
function MAX_GAP_BETWEEN_FINALIZED_AND_VERIFIED_BLOCKS() internal pure returns (uint32) { return 2500; }
171166
function MAX_OPEN_DEPOSIT_REQUESTS() internal pure returns (uint16) { return 1024; }
172167
function MAX_OPEN_WITHDRAWAL_REQUESTS() internal pure returns (uint16) { return 1024; }
173168
function MAX_AGE_UNFINALIZED_BLOCK_UNTIL_WITHDRAW_MODE() internal pure returns (uint32) { return 1 days; }
@@ -221,6 +216,9 @@ library ExchangeData
221216
// A map from an account owner to a token to if the balance is withdrawn
222217
mapping (address => mapping (address => bool)) withdrawnInWithdrawMode;
223218

219+
// A block's state will become FINALIZED when and only when this block is VERIFIED
220+
// and all previous blocks in the chain have become FINALIZED.
221+
// The genesis block is FINALIZED by default.
224222
uint numBlocksFinalized;
225223

226224
// Cached data for the protocol fee

packages/loopring_v3/contracts/impl/libexchange/ExchangeDeposits.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
pragma solidity 0.5.7;
1818

19+
import "../../lib/AddressUtil.sol";
1920
import "../../lib/BurnableERC20.sol";
2021
import "../../lib/ERC20SafeTransfer.sol";
2122

@@ -25,7 +26,7 @@ import "./ExchangeMode.sol";
2526
import "./ExchangeTokens.sol";
2627

2728

28-
/// @title ExchangeAccounts.
29+
/// @title ExchangeDeposits.
2930
/// @author Daniel Wang - <[email protected]>
3031
/// @author Brecht Devos - <[email protected]>
3132
library ExchangeDeposits
@@ -109,6 +110,7 @@ library ExchangeDeposits
109110
// Total fee to be paid by the user
110111
uint feeETH = additionalFeeETH.add(S.depositFeeETH);
111112

113+
// Transfer the tokens to this contract
112114
transferDeposit(
113115
account.owner,
114116
tokenAddress,

0 commit comments

Comments
 (0)