From e97431ba7e69e95c8d52c7775b806530ab539a5c Mon Sep 17 00:00:00 2001 From: Ho Date: Fri, 19 Nov 2021 11:32:46 +0800 Subject: [PATCH 01/14] contract with DA --- .gitignore | 2 +- contracts/FluiDex.sol | 108 ++++++++++++++++++++++++++++++++- contracts/FluiDexDelegate.sol | 5 +- contracts/IFluiDex.sol | 4 +- contracts/IFluiDexDelegate.sol | 4 +- 5 files changed, 116 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 305350c..6f5618b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules - +package-lock.json #Hardhat files cache artifacts diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index c8f8907..c1f86cf 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -149,6 +149,110 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { return block_states[_block_id]; } + /** + * @notice to verify the validity of a sole block + * @param _public_inputs the public inputs of this block + * @param _serialized_proof the serialized proof of this block + * @param _public_data the serialized tx data inside this block (data availability) + * @return true if the block was accepted + */ + function verifyBlock( + uint256[] memory _public_inputs, + uint256[] memory _serialized_proof, + bytes memory _public_data + ) public view returns (bool) { + // _public_inputs[2]/[3] is the low/high 128bit of sha256 hash of _public_data respectively + require(_public_inputs.length >= 4); + + bytes32 h = sha256(_public_data); + + console.logBytes(_public_data); + console.logBytes32(h); + + uint256 h_lo = 0; + for(uint i=0;i<16;i++){ + uint tmp = uint(uint8(h[i+16]))<<(120-8*i); + h_lo = h_lo + tmp; + + } + uint256 h_hi = 0; + for(uint i=0;i<16;i++){ + uint tmp = uint(uint8(h[i]))<<(120-8*i); + h_hi = h_hi + tmp; + } + + assert(_public_inputs[2] == h_hi); + assert(_public_inputs[3] == h_lo); + + return verifier.verify_serialized_proof( + _public_inputs, + _serialized_proof + ); + } + + /** + * @notice to test a block can be submitted or not, this require the block itself + * is valid, and be consistent with state root list + * @param _public_inputs the public inputs of this block + * @param _serialized_proof the serialized proof of this block + * @param _public_data the serialized tx data inside this block (data availability) + * @return true if the block can be submitted + */ + function verifySubmitting( + uint256 _block_id, + uint256[] memory _public_inputs, + uint256[] memory _serialized_proof, + bytes memory _public_data + ) public view returns (bool) { + // _public_inputs[0] is previous_state_root + // _public_inputs[1] is new_state_root + require(_public_inputs.length >= 2); + if (_block_id == 0) { + assert(_public_inputs[0] == GENESIS_ROOT); + } else { + assert(_public_inputs[0] == state_roots[_block_id - 1]); + } + + return verifyBlock( + _public_inputs, + _serialized_proof, + _public_data + ); + } + + /** + * @notice request to submit a new l2 block, same parameters with verifySubmitting + * @return true if the block was accepted + */ + function submitBlock( + uint256 _block_id, + uint256[] memory _public_inputs, + uint256[] memory _serialized_proof, + bytes memory _public_data + ) external override returns (bool) { + + require(block_states[_block_id] != BlockState.Verified, "Block must not be submitted twice"); + if (_block_id > 0) { + require(block_states[_block_id - 1] == BlockState.Verified, "Previous block must be verified"); + } + + bool ret = verifySubmitting( + _block_id, + _public_inputs, + _serialized_proof, + _public_data + ); + + if (!ret){ + return ret; + } + + state_roots[_block_id] = _public_inputs[1]; + block_states[_block_id] = BlockState.Verified; + + return true; + } + /** * @notice request to submit a new l2 block * @param _block_id the l2 block id @@ -156,11 +260,11 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { * @param _serialized_proof the serialized proof of this block * @return true if the block was accepted */ - function submitBlock( + function submitBlockLegacy( uint256 _block_id, uint256[] memory _public_inputs, uint256[] memory _serialized_proof - ) external override returns (bool) { + ) external returns (bool) { // _public_inputs[0] is previous_state_root // _public_inputs[1] is new_state_root require(_public_inputs.length >= 2); diff --git a/contracts/FluiDexDelegate.sol b/contracts/FluiDexDelegate.sol index 955d09e..03af0bb 100644 --- a/contracts/FluiDexDelegate.sol +++ b/contracts/FluiDexDelegate.sol @@ -104,9 +104,10 @@ contract FluiDexDelegate is function submitBlock( uint256 _block_id, uint256[] memory _public_inputs, - uint256[] memory _serialized_proof + uint256[] memory _serialized_proof, + bytes memory _public_data ) external override returns (bool) { - return target.submitBlock(_block_id, _public_inputs, _serialized_proof); + return target.submitBlock(_block_id, _public_inputs, _serialized_proof, _public_data); } /** diff --git a/contracts/IFluiDex.sol b/contracts/IFluiDex.sol index 96f1826..03241a2 100644 --- a/contracts/IFluiDex.sol +++ b/contracts/IFluiDex.sol @@ -44,12 +44,14 @@ interface IFluiDex { * @param _block_id the l2 block id * @param _public_inputs the public inputs of this block * @param _serialized_proof the serialized proof of this block + * @param _public_data the serialized tx data inside this block (data availability) * @return true if the block was accepted */ function submitBlock( uint256 _block_id, uint256[] memory _public_inputs, - uint256[] memory _serialized_proof + uint256[] memory _serialized_proof, + bytes memory _public_data ) external returns (bool); /** diff --git a/contracts/IFluiDexDelegate.sol b/contracts/IFluiDexDelegate.sol index 23605f5..be2868e 100644 --- a/contracts/IFluiDexDelegate.sol +++ b/contracts/IFluiDexDelegate.sol @@ -32,11 +32,13 @@ interface IFluiDexDelegate { * @param _block_id the l2 block id * @param _public_inputs the public inputs of this block * @param _serialized_proof the serialized proof of this block + * @param _public_data the serialized tx data inside this block (data availability) * @return true if the block was accepted */ function submitBlock( uint256 _block_id, uint256[] memory _public_inputs, - uint256[] memory _serialized_proof + uint256[] memory _serialized_proof, + bytes memory _public_data ) external returns (bool); } From b31275f294344c072d237c853ccf0a1526b10c2c Mon Sep 17 00:00:00 2001 From: Ho Date: Fri, 19 Nov 2021 11:36:30 +0800 Subject: [PATCH 02/14] fmt --- contracts/FluiDex.sol | 40 +++++++++++++++++------------------ contracts/FluiDexDelegate.sol | 8 ++++++- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index c1f86cf..c3bd6a3 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -101,7 +101,7 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { /** * @param amount the deposit amount. */ - function depositERC20(IERC20 token, uint256 amount) + function depositERC20(IERC20 token, bytes32 to, uint256 amount) external override nonReentrant @@ -170,24 +170,21 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { console.logBytes32(h); uint256 h_lo = 0; - for(uint i=0;i<16;i++){ - uint tmp = uint(uint8(h[i+16]))<<(120-8*i); + for (uint256 i = 0; i < 16; i++) { + uint256 tmp = uint256(uint8(h[i + 16])) << (120 - 8 * i); h_lo = h_lo + tmp; - } uint256 h_hi = 0; - for(uint i=0;i<16;i++){ - uint tmp = uint(uint8(h[i]))<<(120-8*i); + for (uint256 i = 0; i < 16; i++) { + uint256 tmp = uint256(uint8(h[i])) << (120 - 8 * i); h_hi = h_hi + tmp; } assert(_public_inputs[2] == h_hi); assert(_public_inputs[3] == h_lo); - return verifier.verify_serialized_proof( - _public_inputs, - _serialized_proof - ); + return + verifier.verify_serialized_proof(_public_inputs, _serialized_proof); } /** @@ -213,11 +210,7 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { assert(_public_inputs[0] == state_roots[_block_id - 1]); } - return verifyBlock( - _public_inputs, - _serialized_proof, - _public_data - ); + return verifyBlock(_public_inputs, _serialized_proof, _public_data); } /** @@ -230,10 +223,15 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { uint256[] memory _serialized_proof, bytes memory _public_data ) external override returns (bool) { - - require(block_states[_block_id] != BlockState.Verified, "Block must not be submitted twice"); + require( + block_states[_block_id] != BlockState.Verified, + "Block must not be submitted twice" + ); if (_block_id > 0) { - require(block_states[_block_id - 1] == BlockState.Verified, "Previous block must be verified"); + require( + block_states[_block_id - 1] == BlockState.Verified, + "Previous block must be verified" + ); } bool ret = verifySubmitting( @@ -241,9 +239,9 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { _public_inputs, _serialized_proof, _public_data - ); - - if (!ret){ + ); + + if (!ret) { return ret; } diff --git a/contracts/FluiDexDelegate.sol b/contracts/FluiDexDelegate.sol index 03af0bb..8f23dc2 100644 --- a/contracts/FluiDexDelegate.sol +++ b/contracts/FluiDexDelegate.sol @@ -107,7 +107,13 @@ contract FluiDexDelegate is uint256[] memory _serialized_proof, bytes memory _public_data ) external override returns (bool) { - return target.submitBlock(_block_id, _public_inputs, _serialized_proof, _public_data); + return + target.submitBlock( + _block_id, + _public_inputs, + _serialized_proof, + _public_data + ); } /** From 4464b42fa79af48711a71b9525f2be15d29a8446 Mon Sep 17 00:00:00 2001 From: Ho Date: Mon, 29 Nov 2021 15:13:19 +0800 Subject: [PATCH 03/14] resume committing action for submitting --- contracts/FluiDex.sol | 75 +++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index c3bd6a3..41cd7ea 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -188,21 +188,15 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { } /** - * @notice to test a block can be submitted or not, this require the block itself - * is valid, and be consistent with state root list - * @param _public_inputs the public inputs of this block - * @param _serialized_proof the serialized proof of this block - * @param _public_data the serialized tx data inside this block (data availability) - * @return true if the block can be submitted + * @notice request to submit a new l2 block, same parameters with verifySubmitting + * @return true if the block was accepted */ - function verifySubmitting( + function submitBlock( uint256 _block_id, uint256[] memory _public_inputs, uint256[] memory _serialized_proof, bytes memory _public_data - ) public view returns (bool) { - // _public_inputs[0] is previous_state_root - // _public_inputs[1] is new_state_root + ) external override returns (bool) { require(_public_inputs.length >= 2); if (_block_id == 0) { assert(_public_inputs[0] == GENESIS_ROOT); @@ -210,44 +204,41 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { assert(_public_inputs[0] == state_roots[_block_id - 1]); } - return verifyBlock(_public_inputs, _serialized_proof, _public_data); - } - - /** - * @notice request to submit a new l2 block, same parameters with verifySubmitting - * @return true if the block was accepted - */ - function submitBlock( - uint256 _block_id, - uint256[] memory _public_inputs, - uint256[] memory _serialized_proof, - bytes memory _public_data - ) external override returns (bool) { - require( - block_states[_block_id] != BlockState.Verified, - "Block must not be submitted twice" - ); - if (_block_id > 0) { - require( - block_states[_block_id - 1] == BlockState.Verified, - "Previous block must be verified" + if (_serialized_proof.length != 0) { + bool ret = verifyBlock( + _public_inputs, + _serialized_proof, + _public_data ); - } - bool ret = verifySubmitting( - _block_id, - _public_inputs, - _serialized_proof, - _public_data - ); + if (!ret) { + return ret; + } - if (!ret) { - return ret; + if (_block_id > 0) { + require( + block_states[_block_id - 1] == BlockState.Verified, + "Previous block must be verified" + ); + } + require( + block_states[_block_id] != BlockState.Verified, + "Block must not be submitted twice" + ); + block_states[_block_id] = BlockState.Verified; + } else { + // mark a block as Committed directly, because we may + // temporarily run out of proving resource. + // note: Committing a block without a rollback/revert mechanism should + // only happen in demo version! + if (_block_id > 0) { + assert(block_states[_block_id - 1] != BlockState.Empty); + } + assert(block_states[_block_id] == BlockState.Empty); + block_states[_block_id] = BlockState.Committed; } state_roots[_block_id] = _public_inputs[1]; - block_states[_block_id] = BlockState.Verified; - return true; } From 16ac1cf3cf6d977cbba884185895477de47a22c9 Mon Sep 17 00:00:00 2001 From: Ho Date: Thu, 2 Dec 2021 10:30:36 +0800 Subject: [PATCH 04/14] change parameters from memory to calldata in external function --- contracts/FluiDex.sol | 16 ++++++++-------- contracts/FluiDexDelegate.sol | 6 +++--- contracts/IFluiDex.sol | 6 +++--- contracts/IFluiDexDelegate.sol | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index 41cd7ea..c1ebf8c 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -157,9 +157,9 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { * @return true if the block was accepted */ function verifyBlock( - uint256[] memory _public_inputs, - uint256[] memory _serialized_proof, - bytes memory _public_data + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + bytes calldata _public_data ) public view returns (bool) { // _public_inputs[2]/[3] is the low/high 128bit of sha256 hash of _public_data respectively require(_public_inputs.length >= 4); @@ -193,9 +193,9 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { */ function submitBlock( uint256 _block_id, - uint256[] memory _public_inputs, - uint256[] memory _serialized_proof, - bytes memory _public_data + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + bytes calldata _public_data ) external override returns (bool) { require(_public_inputs.length >= 2); if (_block_id == 0) { @@ -251,8 +251,8 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { */ function submitBlockLegacy( uint256 _block_id, - uint256[] memory _public_inputs, - uint256[] memory _serialized_proof + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof ) external returns (bool) { // _public_inputs[0] is previous_state_root // _public_inputs[1] is new_state_root diff --git a/contracts/FluiDexDelegate.sol b/contracts/FluiDexDelegate.sol index 8f23dc2..d69c0ed 100644 --- a/contracts/FluiDexDelegate.sol +++ b/contracts/FluiDexDelegate.sol @@ -103,9 +103,9 @@ contract FluiDexDelegate is */ function submitBlock( uint256 _block_id, - uint256[] memory _public_inputs, - uint256[] memory _serialized_proof, - bytes memory _public_data + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + bytes calldata _public_data ) external override returns (bool) { return target.submitBlock( diff --git a/contracts/IFluiDex.sol b/contracts/IFluiDex.sol index 03241a2..eab01dd 100644 --- a/contracts/IFluiDex.sol +++ b/contracts/IFluiDex.sol @@ -49,9 +49,9 @@ interface IFluiDex { */ function submitBlock( uint256 _block_id, - uint256[] memory _public_inputs, - uint256[] memory _serialized_proof, - bytes memory _public_data + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + bytes calldata _public_data ) external returns (bool); /** diff --git a/contracts/IFluiDexDelegate.sol b/contracts/IFluiDexDelegate.sol index be2868e..264f3ee 100644 --- a/contracts/IFluiDexDelegate.sol +++ b/contracts/IFluiDexDelegate.sol @@ -37,8 +37,8 @@ interface IFluiDexDelegate { */ function submitBlock( uint256 _block_id, - uint256[] memory _public_inputs, - uint256[] memory _serialized_proof, - bytes memory _public_data + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + bytes calldata _public_data ) external returns (bool); } From 772c3c2b15785739e1bd28e378cec9e7535e3615 Mon Sep 17 00:00:00 2001 From: Ho Date: Fri, 3 Dec 2021 15:11:02 +0800 Subject: [PATCH 05/14] code for priority op queue, include unit-tests --- contracts/Bytes.sol | 105 +++++++++++++++++++++++++++++++++++++ contracts/Operations.sol | 110 +++++++++++++++++++++++++++++++++++++++ contracts/Storage.sol | 74 ++++++++++++++++++++++++++ contracts/TestLibs.sol | 42 +++++++++++++++ contracts/Utils.sol | 9 ++++ package.json | 1 + test/operations-test.js | 70 +++++++++++++++++++++++++ 7 files changed, 411 insertions(+) create mode 100644 contracts/Bytes.sol create mode 100644 contracts/Operations.sol create mode 100644 contracts/Storage.sol create mode 100644 contracts/TestLibs.sol create mode 100644 contracts/Utils.sol create mode 100644 test/operations-test.js diff --git a/contracts/Bytes.sol b/contracts/Bytes.sol new file mode 100644 index 0000000..9fa4d6f --- /dev/null +++ b/contracts/Bytes.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +pragma solidity ^0.8.0; + +library Bytes { + + function shiftAndReverseBits8(uint8 val, uint8 offset) internal pure returns (uint256 ret) { + uint16 effectLen = offset < 248 ? 8 : 256 - offset; + for(uint16 i = 0; i < effectLen; i++){ + if (val & 1 == 1){ + ret += (1 << (255-i-offset)); + } + val >>=1; + } + } + + function shiftAndReverseBits16(uint16 val, uint8 offset) internal pure returns (uint256 ret) { + uint16 effectLen = offset < 240 ? 16 : 256 - offset; + for(uint16 i = 0; i < effectLen; i++){ + if (val & 1 == 1){ + ret += (1 << (255-i-offset)); + } + val >>=1; + } + } + + function shiftAndReverseBits32(uint32 val, uint8 offset) internal pure returns (uint256 ret) { + uint16 effectLen = offset < 224 ? 32 : 256 - offset; + for(uint16 i = 0; i < effectLen; i++){ + if (val & 1 == 1){ + ret += (1 << (255-i-offset)); + } + val >>=1; + } + } + + function shiftAndReverseBits64(uint64 val, uint8 offset) internal pure returns (uint256 ret) { + uint16 effectLen = offset < 192 ? 64 : 256 - offset; + for(uint16 i = 0; i < effectLen; i++){ + if (val & 1 == 1){ + ret += (1 << (255-i-offset)); + } + val >>=1; + } + } + + function shiftAndReverseBits128(uint128 val, uint8 offset) internal pure returns (uint256 ret) { + uint16 effectLen = offset < 128 ? 128 : 256 - offset; + for(uint16 i = 0; i < effectLen; i++){ + if (val & 1 == 1){ + ret += (1 << (255-i-offset)); + } + val >>=1; + } + } + + function shiftAndReverseBits(uint256 val, uint8 offset) internal pure returns (uint256 ret) { + for(uint16 i = 0; i < 256 - offset; i++){ + if (val & 1 == 1){ + ret += (1 << (255-i-offset)); + } + val >>=1; + } + } + + //see https://ethereum.stackexchange.com/questions/83626/how-to-reverse-byte-order-in-uint256-or-bytes32 + function swapBytes(uint256 input) internal pure returns (uint256 v) { + v = input; + + // swap bytes + v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | + ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); + + // swap 2-byte long pairs + v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | + ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); + + // swap 4-byte long pairs + v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) | + ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); + + // swap 8-byte long pairs + v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) | + ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); + + // swap 16-byte long pairs + v = (v >> 128) | (v << 128); + } + + // See comment at the top of this file for explanation of how this function works. + // NOTE: theoretically possible overflow of (_start + 0x2) + function bytesToUInt16(bytes memory _bytes, uint256 _start) internal pure returns (uint16 r) { + uint256 offset = _start + 0x2; + require(_bytes.length >= offset, "T"); + assembly { + r := mload(add(_bytes, offset)) + } + } + + // NOTE: theoretically possible overflow of (_offset + 2) + function readUInt16(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, uint16 r) { + newOffset = _offset + 2; + r = bytesToUInt16(_data, _offset); + } +} \ No newline at end of file diff --git a/contracts/Operations.sol b/contracts/Operations.sol new file mode 100644 index 0000000..f0c8819 --- /dev/null +++ b/contracts/Operations.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +pragma solidity ^0.8.0; +pragma experimental ABIEncoderV2; + +import "./Bytes.sol"; +import "./Utils.sol"; +import "hardhat/console.sol"; //for debugging + +/// @title Fluidex operations tools +library Operations { + + /// @notice Config parameters, generated from circuit parameters + uint8 constant BALANCE_BITS = 3; + uint8 constant ACCOUNT_BITS = 4; + uint8 constant ORDER_BITS = 4; + uint constant TX_PUBDATA_BYTES = 33; + + /// @dev Expected average period of block creation + uint256 internal constant BLOCK_PERIOD = 15 seconds; + + /// @dev Expiration delta for priority request to be satisfied (in seconds) + /// @dev NOTE: Priority expiration should be > (EXPECT_VERIFICATION_IN * BLOCK_PERIOD) + /// @dev otherwise incorrect block with priority op could not be reverted. + uint256 internal constant PRIORITY_EXPIRATION_PERIOD = 7 days; + + /// @dev Expiration delta for priority request to be satisfied (in ETH blocks) + uint256 internal constant PRIORITY_EXPIRATION = PRIORITY_EXPIRATION_PERIOD / BLOCK_PERIOD; + + /// @notice Fluidex circuit operation type + enum OpType { + Deposit, + Registry + } + + function hashPubData(bytes calldata _public_data, uint pos) internal pure returns (bytes20){ + return Utils.hashBytesToBytes20(_public_data[pos:pos+TX_PUBDATA_BYTES]); + } + + // Registry L2key pubdata + struct Registry { + uint32 accountId; + bytes32 l2key; + } + + // Deposit pubdata + struct Deposit { + uint32 accountId; + uint16 tokenId; + uint128 amount; + } + + function scaleTokenValueToAmount(uint value, uint8 scale) internal pure returns (uint128) { + require(scale > 0, "Known token must has a scaling"); + return uint128(value / (10 ** scale)); + } + + function hashOpDataFromBuf(bytes memory buf) internal pure returns (bytes20){ + bytes memory truncatedBuf = new bytes(TX_PUBDATA_BYTES); + for(uint i = 0; i < TX_PUBDATA_BYTES; i++){ + truncatedBuf[i] = buf[i]; + } + + return Utils.hashBytesToBytes20(truncatedBuf); + } + + /// Serialize registry pubdata + function writeRegistryPubdataForPriorityQueue(Registry memory op) internal pure returns (bytes20) { + + uint256 encoded_1 = 0; + uint8 offset = 0; + encoded_1 += Bytes.shiftAndReverseBits8(uint8(1), offset); //100 in bits + offset += 3; + encoded_1 += Bytes.shiftAndReverseBits32(op.accountId, offset); + offset += ACCOUNT_BITS; + uint8 sign = op.l2key[31] & 0x80 != 0 ? 1 : 0; + encoded_1 += Bytes.shiftAndReverseBits8(sign, offset); + offset += 1; + uint256 ay = uint256(op.l2key); + ay -= (uint8(op.l2key[31]) - uint8(op.l2key[31] & 0x7f)); + //notice babyjub consider the read bytes as LITTLE-endian integer + ay = Bytes.swapBytes(ay); + encoded_1 += Bytes.shiftAndReverseBits(ay, offset); + //calc the resident of bits in ay + ay >>= (256 - offset); + uint256 encoded_2 = Bytes.shiftAndReverseBits(ay, 0); + + return hashOpDataFromBuf(abi.encodePacked(encoded_1, encoded_2)); + } + + /// Serialize deposit pubdata + function writeDepositPubdataForPriorityQueue(Deposit memory op) internal pure returns (bytes20) { + uint256 encoded_1 = 0; + uint8 offset = 0; + encoded_1 += Bytes.shiftAndReverseBits8(uint8(0), offset); //000 in bits + offset += 3; + encoded_1 += Bytes.shiftAndReverseBits32(op.accountId, offset); + offset += ACCOUNT_BITS; + //according to the encoding scheme we need to encode account id twice + encoded_1 += Bytes.shiftAndReverseBits32(op.accountId, offset); + offset += ACCOUNT_BITS; + encoded_1 += Bytes.shiftAndReverseBits16(op.tokenId, offset); + offset += BALANCE_BITS; + assert(offset <= 128); + + encoded_1 += Bytes.shiftAndReverseBits128(op.amount, offset); + + return hashOpDataFromBuf(abi.encodePacked(encoded_1, uint256(0))); + } +} diff --git a/contracts/Storage.sol b/contracts/Storage.sol new file mode 100644 index 0000000..25341e1 --- /dev/null +++ b/contracts/Storage.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +pragma solidity ^0.8.0; + +import "./Operations.sol"; + +/// @title Fluidex storage contract +contract Storage { + + /// @notice First open priority request id + uint64 public firstPriorityRequestId; + + /// @notice Total number of requests + uint64 public totalOpenPriorityRequests; + + /// @notice Priority Operation container + /// @member hashedPubData Hashed priority operation public data + /// @member expirationBlock Expiration block number (ETH block) for this request (must be satisfied before) + /// @member opType Priority operation type + struct PriorityOperation { + bytes20 hashedPubData; + uint64 expirationBlock; + Operations.OpType opType; + } + + /// @dev Priority Requests mapping (request id - operation) + /// @dev Contains op type, pubdata and expiration block of unsatisfied requests. + /// @dev Numbers are in order of requests receiving + mapping(uint64 => PriorityOperation) internal priorityRequests; + + /// @notice Verify priorityOp inside the calling public data match the priority queue + /// @dev Calculates expiration block for request, store this request and emit NewPriorityRequest event + /// @param _public_data Calling public_data + /// @param _op_indexs indexs specify which op should be checked + function verifyPriorityOp(bytes calldata _public_data, bytes calldata _op_indexs) internal view returns (bool _ret, uint64 _priorityRequestId){ + //_op_indexs is uint16 being encode packed + assert(_op_indexs.length % 2 == 0); + + _priorityRequestId = firstPriorityRequestId; + + for(uint i = 0; i < _op_indexs.length; i+= 2){ + //TODO: with compiler later than 0.8.10 we can use slice + //uint pos = uint16(bytes2(_op_indexs[i:i+2])); + uint pos = uint(uint8(_op_indexs[i])) * 256 + uint(uint8(_op_indexs[i+1])); + assert(pos < _public_data.length); + bytes20 hashedPubdata = priorityRequests[_priorityRequestId].hashedPubData; + if (Operations.hashPubData(_public_data, pos) != hashedPubdata){ + return (false, _priorityRequestId); + } + _priorityRequestId++; + } + + _ret = true; + } + + /// @notice Saves priority request in storage + /// @dev Calculates expiration block for request, store this request and emit NewPriorityRequest event + /// @param _opType Rollup operation type + /// @param _hashedPubData Hashed Operation pubdata + function addPriorityRequest(Operations.OpType _opType, bytes20 _hashedPubData) internal { + // Expiration block is: current block number + priority expiration delta + uint64 expirationBlock = uint64(block.number + Operations.PRIORITY_EXPIRATION); + + uint64 nextPriorityRequestId = firstPriorityRequestId + totalOpenPriorityRequests; + + priorityRequests[nextPriorityRequestId] = PriorityOperation({ + hashedPubData: _hashedPubData, + expirationBlock: expirationBlock, + opType: _opType + }); + + totalOpenPriorityRequests++; + } +} diff --git a/contracts/TestLibs.sol b/contracts/TestLibs.sol new file mode 100644 index 0000000..bf06c8f --- /dev/null +++ b/contracts/TestLibs.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +pragma solidity ^0.8.0; + +import "./Operations.sol"; + +/// @title Unittest contract for libraries +contract TestLibs { + + function testBitsOp8(uint8 val, uint8 offset) public pure returns (uint256){ + return Bytes.shiftAndReverseBits8(val, offset); + } + + function testBitsOp32(uint32 val, uint8 offset) public pure returns (uint256){ + return Bytes.shiftAndReverseBits32(val, offset); + } + + function testBitsOp256(uint256 val, uint8 offset) public pure returns (uint256){ + return Bytes.shiftAndReverseBits(val, offset); + } + + function testWriteRegistryPubdata(uint32 accId, bytes32 l2key) public pure returns (bytes20){ + + Operations.Registry memory op = Operations.Registry({ + accountId: accId, + l2key: l2key + }); + + return Operations.writeRegistryPubdataForPriorityQueue(op); + } + + function testWriteDepositPubdata(uint32 accId, uint16 tokenId, uint128 amount) public pure returns (bytes20){ + + Operations.Deposit memory op = Operations.Deposit({ + accountId: accId, + tokenId: tokenId, + amount: amount + }); + + return Operations.writeDepositPubdataForPriorityQueue(op); + } +} \ No newline at end of file diff --git a/contracts/Utils.sol b/contracts/Utils.sol new file mode 100644 index 0000000..06d44c3 --- /dev/null +++ b/contracts/Utils.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +pragma solidity ^0.8.0; + +library Utils { + function hashBytesToBytes20(bytes memory _bytes) internal pure returns (bytes20) { + return bytes20(uint160(uint256(keccak256(_bytes)))); + } +} diff --git a/package.json b/package.json index c27de65..5c83278 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "ethers": "^5.0.24", "fluidex.js": "git+https://github.com/fluidex/fluidex.js.git#b9224719013c224445fe8ec06f6a05e800b4469e", "hardhat": "^2.0.6", + "mocha": "^9.1.3", "prettier": "^2.2.1", "prettier-plugin-solidity": "^1.0.0-beta.2", "ts-node": "^10.2.1", diff --git a/test/operations-test.js b/test/operations-test.js new file mode 100644 index 0000000..e0b2824 --- /dev/null +++ b/test/operations-test.js @@ -0,0 +1,70 @@ +const { expect } = require("chai"); +const { ethers } = require("hardhat"); + +describe("TestBytes", function(){ + it("Express input to reversed-bit inside the returning integer", async function () { + const TestC = await ethers.getContractFactory("TestLibs"); + const testC = await TestC.deploy(); + + await testC.deployed(); + + expect(await testC.testBitsOp8(0, 138)).to.equal(0); + expect(await testC.testBitsOp8(1, 0)).to.equal(BigInt("0x8000000000000000000000000000000000000000000000000000000000000000")); + expect(await testC.testBitsOp8(1, 1)).to.equal(BigInt("0x4000000000000000000000000000000000000000000000000000000000000000")); + expect(await testC.testBitsOp8(42, 3)).to.equal(BigInt("0x0A80000000000000000000000000000000000000000000000000000000000000")); + expect(await testC.testBitsOp8(3, 255)).to.equal(1); + expect(await testC.testBitsOp32(1, 0)).to.equal(BigInt("0x8000000000000000000000000000000000000000000000000000000000000000")); + expect(await testC.testBitsOp32(42, 3)).to.equal(BigInt("0x0A80000000000000000000000000000000000000000000000000000000000000")); + expect(await testC.testBitsOp32(BigInt("0x80000001"), 225)).to.equal(BigInt("0x40000000")); + expect(await testC.testBitsOp32(995535, 236)).to.equal(995535); + expect(await testC.testBitsOp256(1, 0)).to.equal(BigInt("0x8000000000000000000000000000000000000000000000000000000000000000")); + expect(await testC.testBitsOp256(1, 128)).to.equal(BigInt("0x80000000000000000000000000000000")); + expect(await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 0)).to.equal(BigInt("0x100000000000000000000000000000000")); + expect(await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 1)).to.equal(BigInt("0x80000000000000000000000000000000")); + expect(await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 128)).to.equal(1); + expect(await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 129)).to.equal(0); + }); +}) + +const keccak256To160 = bytesLike => ('0x' + ethers.utils.keccak256(bytesLike).slice(26)); + +describe("TestWriteRegistryOp", function(){ + it("Encode registry op just like circuit did", async function () { + const TestC = await ethers.getContractFactory("TestLibs"); + const testC = await TestC.deploy(); + + await testC.deployed(); + + //this cases only work for acc = 4, order = 4 and balance = 3 + const expectedEncodeOp1 = keccak256To160("0x91ba18348a3d7f991abc0eaee50583b0697d1fd451a039d21fa36fe748324fddc4"); + const expectedEncodeOp2 = keccak256To160("0x8997ad724ddb0f85f255bf087945654549ed416e131cf8719f21bb7b7ff54d7bf4"); + const expectedEncodeOp3 = keccak256To160("0x949c82e7b8eefc3ce0ef812304c79cba948014945150117fda5f1c0c33873099b8"); + + expect(await testC.testWriteRegistryPubdata(1, + "0x5d182c51bcfe99583d7075a7a0c10d96bef82b8a059c4bf8c5f6e7124cf2bba3")) + .to.equal(expectedEncodeOp1); + expect(await testC.testWriteRegistryPubdata(2, + "0xe9b54eb2dbf0a14faafd109ea2a6a292b78276c8381f8ef984dddefeafb2deaf")) + .to.equal(expectedEncodeOp2); + expect(await testC.testWriteRegistryPubdata(5, + "0x3941e71d773f3c07f781c420e3395d290128298a0a88fe5bfa3830cce10c991d")) + .to.equal(expectedEncodeOp3); + }); +}) + + +describe("TestWriteDepositOp", function(){ + it("Encode deposit op just like circuit did", async function () { + const TestC = await ethers.getContractFactory("TestLibs"); + const testC = await TestC.deploy(); + + await testC.deployed(); + + //this cases only work for acc = 4, order = 4 and balance = 3 + const expectedEncodeOp1 = keccak256To160("0x111000452958b80000000000000000000000000000000000000000000000000000"); + + expect(await testC.testWriteDepositPubdata(1, 1, + BigInt("500000000000"))) + .to.equal(expectedEncodeOp1); + }); +}) \ No newline at end of file From d5616855f1fb0159321fede49872cb5a7dfc60ca Mon Sep 17 00:00:00 2001 From: Ho Date: Fri, 3 Dec 2021 15:56:51 +0800 Subject: [PATCH 06/14] handling priority op in demo contract --- contracts/Bytes.sol | 135 ++++++++++++++++++-------- contracts/FluiDex.sol | 81 +++++++++++++++- contracts/FluiDexDelegate.sol | 6 +- contracts/IFluiDex.sol | 4 +- contracts/IFluiDexDelegate.sol | 4 +- contracts/Operations.sol | 44 ++++++--- contracts/Storage.sol | 50 ++++++++-- contracts/TestLibs.sol | 37 +++++-- contracts/Utils.sol | 6 +- test/operations-test.js | 171 ++++++++++++++++++++++----------- 10 files changed, 398 insertions(+), 140 deletions(-) diff --git a/contracts/Bytes.sol b/contracts/Bytes.sol index 9fa4d6f..d6258dd 100644 --- a/contracts/Bytes.sol +++ b/contracts/Bytes.sol @@ -3,63 +3,86 @@ pragma solidity ^0.8.0; library Bytes { - - function shiftAndReverseBits8(uint8 val, uint8 offset) internal pure returns (uint256 ret) { + function shiftAndReverseBits8(uint8 val, uint8 offset) + internal + pure + returns (uint256 ret) + { uint16 effectLen = offset < 248 ? 8 : 256 - offset; - for(uint16 i = 0; i < effectLen; i++){ - if (val & 1 == 1){ - ret += (1 << (255-i-offset)); + for (uint16 i = 0; i < effectLen; i++) { + if (val & 1 == 1) { + ret += (1 << (255 - i - offset)); } - val >>=1; + val >>= 1; } } - function shiftAndReverseBits16(uint16 val, uint8 offset) internal pure returns (uint256 ret) { + function shiftAndReverseBits16(uint16 val, uint8 offset) + internal + pure + returns (uint256 ret) + { uint16 effectLen = offset < 240 ? 16 : 256 - offset; - for(uint16 i = 0; i < effectLen; i++){ - if (val & 1 == 1){ - ret += (1 << (255-i-offset)); + for (uint16 i = 0; i < effectLen; i++) { + if (val & 1 == 1) { + ret += (1 << (255 - i - offset)); } - val >>=1; + val >>= 1; } } - function shiftAndReverseBits32(uint32 val, uint8 offset) internal pure returns (uint256 ret) { + function shiftAndReverseBits32(uint32 val, uint8 offset) + internal + pure + returns (uint256 ret) + { uint16 effectLen = offset < 224 ? 32 : 256 - offset; - for(uint16 i = 0; i < effectLen; i++){ - if (val & 1 == 1){ - ret += (1 << (255-i-offset)); + for (uint16 i = 0; i < effectLen; i++) { + if (val & 1 == 1) { + ret += (1 << (255 - i - offset)); } - val >>=1; + val >>= 1; } } - function shiftAndReverseBits64(uint64 val, uint8 offset) internal pure returns (uint256 ret) { + function shiftAndReverseBits64(uint64 val, uint8 offset) + internal + pure + returns (uint256 ret) + { uint16 effectLen = offset < 192 ? 64 : 256 - offset; - for(uint16 i = 0; i < effectLen; i++){ - if (val & 1 == 1){ - ret += (1 << (255-i-offset)); + for (uint16 i = 0; i < effectLen; i++) { + if (val & 1 == 1) { + ret += (1 << (255 - i - offset)); } - val >>=1; + val >>= 1; } } - function shiftAndReverseBits128(uint128 val, uint8 offset) internal pure returns (uint256 ret) { + function shiftAndReverseBits128(uint128 val, uint8 offset) + internal + pure + returns (uint256 ret) + { uint16 effectLen = offset < 128 ? 128 : 256 - offset; - for(uint16 i = 0; i < effectLen; i++){ - if (val & 1 == 1){ - ret += (1 << (255-i-offset)); + for (uint16 i = 0; i < effectLen; i++) { + if (val & 1 == 1) { + ret += (1 << (255 - i - offset)); } - val >>=1; + val >>= 1; } } - function shiftAndReverseBits(uint256 val, uint8 offset) internal pure returns (uint256 ret) { - for(uint16 i = 0; i < 256 - offset; i++){ - if (val & 1 == 1){ - ret += (1 << (255-i-offset)); + function shiftAndReverseBits(uint256 val, uint8 offset) + internal + pure + returns (uint256 ret) + { + for (uint16 i = 0; i < 256 - offset; i++) { + if (val & 1 == 1) { + ret += (1 << (255 - i - offset)); } - val >>=1; + val >>= 1; } } @@ -68,20 +91,40 @@ library Bytes { v = input; // swap bytes - v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | - ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); + v = + ((v & + 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> + 8) | + ((v & + 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << + 8); // swap 2-byte long pairs - v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | - ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); + v = + ((v & + 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> + 16) | + ((v & + 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << + 16); // swap 4-byte long pairs - v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) | - ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); + v = + ((v & + 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> + 32) | + ((v & + 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << + 32); // swap 8-byte long pairs - v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) | - ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); + v = + ((v & + 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> + 64) | + ((v & + 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << + 64); // swap 16-byte long pairs v = (v >> 128) | (v << 128); @@ -89,7 +132,11 @@ library Bytes { // See comment at the top of this file for explanation of how this function works. // NOTE: theoretically possible overflow of (_start + 0x2) - function bytesToUInt16(bytes memory _bytes, uint256 _start) internal pure returns (uint16 r) { + function bytesToUInt16(bytes memory _bytes, uint256 _start) + internal + pure + returns (uint16 r) + { uint256 offset = _start + 0x2; require(_bytes.length >= offset, "T"); assembly { @@ -98,8 +145,12 @@ library Bytes { } // NOTE: theoretically possible overflow of (_offset + 2) - function readUInt16(bytes memory _data, uint256 _offset) internal pure returns (uint256 newOffset, uint16 r) { + function readUInt16(bytes memory _data, uint256 _offset) + internal + pure + returns (uint256 newOffset, uint16 r) + { newOffset = _offset + 2; r = bytesToUInt16(_data, _offset); } -} \ No newline at end of file +} diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index c1ebf8c..4736d52 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -11,11 +11,18 @@ import "hardhat/console.sol"; // for debugging import "./IFluiDex.sol"; import "./IVerifier.sol"; +import "./Storage.sol"; /** * @title FluiDexDemo */ -contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { +contract FluiDexDemo is + AccessControl, + IFluiDex, + Ownable, + ReentrancyGuard, + Storage +{ using SafeERC20 for IERC20; bytes32 public constant PLUGIN_ADMIN_ROLE = keccak256("PLUGIN_ADMIN_ROLE"); @@ -37,6 +44,7 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { uint16 public tokenNum; mapping(uint16 => address) public tokenIdToAddr; + mapping(uint16 => uint8) public tokenScales; mapping(address => uint16) public tokenAddrToId; uint16 public userNum; @@ -51,6 +59,9 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { _setRoleAdmin(DELEGATE_ROLE, DEFAULT_ADMIN_ROLE); grantRole(PLUGIN_ADMIN_ROLE, msg.sender); grantRole(DELEGATE_ROLE, msg.sender); + + //TODO: define defaut scale of ETH: eth (10^18 wei) with prec 6 so we get + tokenScales[0] = 12; } /** @@ -85,6 +96,10 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { tokenIdToAddr[tokenId] = tokenAddr; tokenAddrToId[tokenAddr] = tokenId; + //TODO: should provide token's prec and check token's decimal + tokenScales[tokenId] = 12; + + emit NewToken(origin, tokenAddr, tokenId); return tokenId; } @@ -96,12 +111,33 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { payable override onlyRole(DELEGATE_ROLE) - {} + { + uint16 accountId = userBjjPubkeyToUserId[to]; + require(accountId != 0, "non-existed user"); + uint128 amount = Operations.scaleTokenValueToAmount( + msg.value, + tokenScales[0] + ); + + Operations.Deposit memory op = Operations.Deposit({ + accountId: accountId, + tokenId: 0, + amount: amount + }); + + addPriorityRequest( + Operations.OpType.Deposit, + Operations.writeDepositPubdataForPriorityQueue(op) + ); + + //TODO: correct the value to scaled amount? + emit Deposit(ETH_ID, to, msg.value); + } /** * @param amount the deposit amount. */ - function depositERC20(IERC20 token, bytes32 to, uint256 amount) + function depositERC20(IERC20 token, bytes32 to, uint256 amount) external override nonReentrant @@ -114,7 +150,27 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { uint256 balanceBeforeDeposit = token.balanceOf(address(this)); token.safeTransferFrom(msg.sender, address(this), amount); uint256 balanceAfterDeposit = token.balanceOf(address(this)); - realAmount = balanceAfterDeposit - balanceBeforeDeposit; + uint256 realAmount = balanceAfterDeposit - balanceBeforeDeposit; + + uint16 accountId = userBjjPubkeyToUserId[to]; + require(accountId != 0, "non-existed user"); + uint128 scaledAmount = Operations.scaleTokenValueToAmount( + amount, + tokenScales[tokenId] + ); + + Operations.Deposit memory op = Operations.Deposit({ + accountId: accountId, + tokenId: tokenId, + amount: scaledAmount + }); + + addPriorityRequest( + Operations.OpType.Deposit, + Operations.writeDepositPubdataForPriorityQueue(op) + ); + + emit Deposit(tokenId, to, realAmount); } /** @@ -195,7 +251,8 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { uint256 _block_id, uint256[] calldata _public_inputs, uint256[] calldata _serialized_proof, - bytes calldata _public_data + bytes calldata _public_data, + bytes calldata _priority_op_index ) external override returns (bool) { require(_public_inputs.length >= 2); if (_block_id == 0) { @@ -204,6 +261,20 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { assert(_public_inputs[0] == state_roots[_block_id - 1]); } + //forward priority op + if (_priority_op_index.length != 0) { + (bool pass, uint64 nextIndex) = verifyPriorityOp( + _public_data, + _priority_op_index + ); + require(pass, "handling priority ops not correct"); + assert( + totalOpenPriorityRequests >= nextIndex - firstPriorityRequestId + ); + totalOpenPriorityRequests -= nextIndex - firstPriorityRequestId; + firstPriorityRequestId = nextIndex; + } + if (_serialized_proof.length != 0) { bool ret = verifyBlock( _public_inputs, diff --git a/contracts/FluiDexDelegate.sol b/contracts/FluiDexDelegate.sol index d69c0ed..c2bf5fd 100644 --- a/contracts/FluiDexDelegate.sol +++ b/contracts/FluiDexDelegate.sol @@ -105,14 +105,16 @@ contract FluiDexDelegate is uint256 _block_id, uint256[] calldata _public_inputs, uint256[] calldata _serialized_proof, - bytes calldata _public_data + bytes calldata _public_data, + bytes calldata _priority_op_index ) external override returns (bool) { return target.submitBlock( _block_id, _public_inputs, _serialized_proof, - _public_data + _public_data, + _priority_op_index ); } diff --git a/contracts/IFluiDex.sol b/contracts/IFluiDex.sol index eab01dd..4a14f63 100644 --- a/contracts/IFluiDex.sol +++ b/contracts/IFluiDex.sol @@ -45,13 +45,15 @@ interface IFluiDex { * @param _public_inputs the public inputs of this block * @param _serialized_proof the serialized proof of this block * @param _public_data the serialized tx data inside this block (data availability) + * @param _priority_op_index the positions of priority op in public data * @return true if the block was accepted */ function submitBlock( uint256 _block_id, uint256[] calldata _public_inputs, uint256[] calldata _serialized_proof, - bytes calldata _public_data + bytes calldata _public_data, + bytes calldata _priority_op_index ) external returns (bool); /** diff --git a/contracts/IFluiDexDelegate.sol b/contracts/IFluiDexDelegate.sol index 264f3ee..640c5a6 100644 --- a/contracts/IFluiDexDelegate.sol +++ b/contracts/IFluiDexDelegate.sol @@ -33,12 +33,14 @@ interface IFluiDexDelegate { * @param _public_inputs the public inputs of this block * @param _serialized_proof the serialized proof of this block * @param _public_data the serialized tx data inside this block (data availability) + * @param _priority_op_index the positions of priority op in public data * @return true if the block was accepted */ function submitBlock( uint256 _block_id, uint256[] calldata _public_inputs, uint256[] calldata _serialized_proof, - bytes calldata _public_data + bytes calldata _public_data, + bytes calldata _priority_op_index ) external returns (bool); } diff --git a/contracts/Operations.sol b/contracts/Operations.sol index f0c8819..26e767b 100644 --- a/contracts/Operations.sol +++ b/contracts/Operations.sol @@ -9,12 +9,11 @@ import "hardhat/console.sol"; //for debugging /// @title Fluidex operations tools library Operations { - /// @notice Config parameters, generated from circuit parameters uint8 constant BALANCE_BITS = 3; uint8 constant ACCOUNT_BITS = 4; uint8 constant ORDER_BITS = 4; - uint constant TX_PUBDATA_BYTES = 33; + uint256 constant TX_PUBDATA_BYTES = 33; /// @dev Expected average period of block creation uint256 internal constant BLOCK_PERIOD = 15 seconds; @@ -25,7 +24,8 @@ library Operations { uint256 internal constant PRIORITY_EXPIRATION_PERIOD = 7 days; /// @dev Expiration delta for priority request to be satisfied (in ETH blocks) - uint256 internal constant PRIORITY_EXPIRATION = PRIORITY_EXPIRATION_PERIOD / BLOCK_PERIOD; + uint256 internal constant PRIORITY_EXPIRATION = + PRIORITY_EXPIRATION_PERIOD / BLOCK_PERIOD; /// @notice Fluidex circuit operation type enum OpType { @@ -33,8 +33,13 @@ library Operations { Registry } - function hashPubData(bytes calldata _public_data, uint pos) internal pure returns (bytes20){ - return Utils.hashBytesToBytes20(_public_data[pos:pos+TX_PUBDATA_BYTES]); + function hashPubData(bytes calldata _public_data, uint256 pos) + internal + pure + returns (bytes20) + { + return + Utils.hashBytesToBytes20(_public_data[pos:pos + TX_PUBDATA_BYTES]); } // Registry L2key pubdata @@ -50,14 +55,22 @@ library Operations { uint128 amount; } - function scaleTokenValueToAmount(uint value, uint8 scale) internal pure returns (uint128) { + function scaleTokenValueToAmount(uint256 value, uint8 scale) + internal + pure + returns (uint128) + { require(scale > 0, "Known token must has a scaling"); - return uint128(value / (10 ** scale)); + return uint128(value / (10**scale)); } - function hashOpDataFromBuf(bytes memory buf) internal pure returns (bytes20){ + function hashOpDataFromBuf(bytes memory buf) + internal + pure + returns (bytes20) + { bytes memory truncatedBuf = new bytes(TX_PUBDATA_BYTES); - for(uint i = 0; i < TX_PUBDATA_BYTES; i++){ + for (uint256 i = 0; i < TX_PUBDATA_BYTES; i++) { truncatedBuf[i] = buf[i]; } @@ -65,8 +78,11 @@ library Operations { } /// Serialize registry pubdata - function writeRegistryPubdataForPriorityQueue(Registry memory op) internal pure returns (bytes20) { - + function writeRegistryPubdataForPriorityQueue(Registry memory op) + internal + pure + returns (bytes20) + { uint256 encoded_1 = 0; uint8 offset = 0; encoded_1 += Bytes.shiftAndReverseBits8(uint8(1), offset); //100 in bits @@ -89,7 +105,11 @@ library Operations { } /// Serialize deposit pubdata - function writeDepositPubdataForPriorityQueue(Deposit memory op) internal pure returns (bytes20) { + function writeDepositPubdataForPriorityQueue(Deposit memory op) + internal + pure + returns (bytes20) + { uint256 encoded_1 = 0; uint8 offset = 0; encoded_1 += Bytes.shiftAndReverseBits8(uint8(0), offset); //000 in bits diff --git a/contracts/Storage.sol b/contracts/Storage.sol index 25341e1..8281dda 100644 --- a/contracts/Storage.sol +++ b/contracts/Storage.sol @@ -6,7 +6,6 @@ import "./Operations.sol"; /// @title Fluidex storage contract contract Storage { - /// @notice First open priority request id uint64 public firstPriorityRequestId; @@ -28,23 +27,48 @@ contract Storage { /// @dev Numbers are in order of requests receiving mapping(uint64 => PriorityOperation) internal priorityRequests; + /// @notice Check if priorityOp in queue has expired + function checkPriorityOpExpiration() public view returns (bool) { + if (totalOpenPriorityRequests == 0) return false; + + return + priorityRequests[firstPriorityRequestId].expirationBlock < + block.number; + } + /// @notice Verify priorityOp inside the calling public data match the priority queue /// @dev Calculates expiration block for request, store this request and emit NewPriorityRequest event /// @param _public_data Calling public_data /// @param _op_indexs indexs specify which op should be checked - function verifyPriorityOp(bytes calldata _public_data, bytes calldata _op_indexs) internal view returns (bool _ret, uint64 _priorityRequestId){ + function verifyPriorityOp( + bytes calldata _public_data, + bytes calldata _op_indexs + ) public view returns (bool _ret, uint64 _priorityRequestId) { //_op_indexs is uint16 being encode packed assert(_op_indexs.length % 2 == 0); + assert(_public_data.length % Operations.TX_PUBDATA_BYTES == 0); + + require( + !checkPriorityOpExpiration() || + //last chance: we put all effort on priority ops when they have expired + _op_indexs.length / 2 == totalOpenPriorityRequests || + _public_data.length / Operations.TX_PUBDATA_BYTES == + _op_indexs.length / 2, + "priority op must be handled before expiration" + ); _priorityRequestId = firstPriorityRequestId; - for(uint i = 0; i < _op_indexs.length; i+= 2){ + for (uint256 i = 0; i < _op_indexs.length; i += 2) { //TODO: with compiler later than 0.8.10 we can use slice //uint pos = uint16(bytes2(_op_indexs[i:i+2])); - uint pos = uint(uint8(_op_indexs[i])) * 256 + uint(uint8(_op_indexs[i+1])); + uint256 pos = uint256(uint8(_op_indexs[i])) * + 256 + + uint256(uint8(_op_indexs[i + 1])); assert(pos < _public_data.length); - bytes20 hashedPubdata = priorityRequests[_priorityRequestId].hashedPubData; - if (Operations.hashPubData(_public_data, pos) != hashedPubdata){ + bytes20 hashedPubdata = priorityRequests[_priorityRequestId] + .hashedPubData; + if (Operations.hashPubData(_public_data, pos) != hashedPubdata) { return (false, _priorityRequestId); } _priorityRequestId++; @@ -57,11 +81,17 @@ contract Storage { /// @dev Calculates expiration block for request, store this request and emit NewPriorityRequest event /// @param _opType Rollup operation type /// @param _hashedPubData Hashed Operation pubdata - function addPriorityRequest(Operations.OpType _opType, bytes20 _hashedPubData) internal { + function addPriorityRequest( + Operations.OpType _opType, + bytes20 _hashedPubData + ) internal { // Expiration block is: current block number + priority expiration delta - uint64 expirationBlock = uint64(block.number + Operations.PRIORITY_EXPIRATION); + uint64 expirationBlock = uint64( + block.number + Operations.PRIORITY_EXPIRATION + ); - uint64 nextPriorityRequestId = firstPriorityRequestId + totalOpenPriorityRequests; + uint64 nextPriorityRequestId = firstPriorityRequestId + + totalOpenPriorityRequests; priorityRequests[nextPriorityRequestId] = PriorityOperation({ hashedPubData: _hashedPubData, @@ -70,5 +100,5 @@ contract Storage { }); totalOpenPriorityRequests++; - } + } } diff --git a/contracts/TestLibs.sol b/contracts/TestLibs.sol index bf06c8f..87ea3dd 100644 --- a/contracts/TestLibs.sol +++ b/contracts/TestLibs.sol @@ -6,21 +6,35 @@ import "./Operations.sol"; /// @title Unittest contract for libraries contract TestLibs { - - function testBitsOp8(uint8 val, uint8 offset) public pure returns (uint256){ + function testBitsOp8(uint8 val, uint8 offset) + public + pure + returns (uint256) + { return Bytes.shiftAndReverseBits8(val, offset); } - function testBitsOp32(uint32 val, uint8 offset) public pure returns (uint256){ + function testBitsOp32(uint32 val, uint8 offset) + public + pure + returns (uint256) + { return Bytes.shiftAndReverseBits32(val, offset); } - function testBitsOp256(uint256 val, uint8 offset) public pure returns (uint256){ + function testBitsOp256(uint256 val, uint8 offset) + public + pure + returns (uint256) + { return Bytes.shiftAndReverseBits(val, offset); } - function testWriteRegistryPubdata(uint32 accId, bytes32 l2key) public pure returns (bytes20){ - + function testWriteRegistryPubdata(uint32 accId, bytes32 l2key) + public + pure + returns (bytes20) + { Operations.Registry memory op = Operations.Registry({ accountId: accId, l2key: l2key @@ -29,8 +43,11 @@ contract TestLibs { return Operations.writeRegistryPubdataForPriorityQueue(op); } - function testWriteDepositPubdata(uint32 accId, uint16 tokenId, uint128 amount) public pure returns (bytes20){ - + function testWriteDepositPubdata( + uint32 accId, + uint16 tokenId, + uint128 amount + ) public pure returns (bytes20) { Operations.Deposit memory op = Operations.Deposit({ accountId: accId, tokenId: tokenId, @@ -38,5 +55,5 @@ contract TestLibs { }); return Operations.writeDepositPubdataForPriorityQueue(op); - } -} \ No newline at end of file + } +} diff --git a/contracts/Utils.sol b/contracts/Utils.sol index 06d44c3..500671d 100644 --- a/contracts/Utils.sol +++ b/contracts/Utils.sol @@ -3,7 +3,11 @@ pragma solidity ^0.8.0; library Utils { - function hashBytesToBytes20(bytes memory _bytes) internal pure returns (bytes20) { + function hashBytesToBytes20(bytes memory _bytes) + internal + pure + returns (bytes20) + { return bytes20(uint160(uint256(keccak256(_bytes)))); } } diff --git a/test/operations-test.js b/test/operations-test.js index e0b2824..bc86c1c 100644 --- a/test/operations-test.js +++ b/test/operations-test.js @@ -1,70 +1,129 @@ const { expect } = require("chai"); const { ethers } = require("hardhat"); -describe("TestBytes", function(){ - it("Express input to reversed-bit inside the returning integer", async function () { - const TestC = await ethers.getContractFactory("TestLibs"); - const testC = await TestC.deploy(); +describe("TestBytes", function () { + it("Express input to reversed-bit inside the returning integer", async function () { + const TestC = await ethers.getContractFactory("TestLibs"); + const testC = await TestC.deploy(); - await testC.deployed(); + await testC.deployed(); - expect(await testC.testBitsOp8(0, 138)).to.equal(0); - expect(await testC.testBitsOp8(1, 0)).to.equal(BigInt("0x8000000000000000000000000000000000000000000000000000000000000000")); - expect(await testC.testBitsOp8(1, 1)).to.equal(BigInt("0x4000000000000000000000000000000000000000000000000000000000000000")); - expect(await testC.testBitsOp8(42, 3)).to.equal(BigInt("0x0A80000000000000000000000000000000000000000000000000000000000000")); - expect(await testC.testBitsOp8(3, 255)).to.equal(1); - expect(await testC.testBitsOp32(1, 0)).to.equal(BigInt("0x8000000000000000000000000000000000000000000000000000000000000000")); - expect(await testC.testBitsOp32(42, 3)).to.equal(BigInt("0x0A80000000000000000000000000000000000000000000000000000000000000")); - expect(await testC.testBitsOp32(BigInt("0x80000001"), 225)).to.equal(BigInt("0x40000000")); - expect(await testC.testBitsOp32(995535, 236)).to.equal(995535); - expect(await testC.testBitsOp256(1, 0)).to.equal(BigInt("0x8000000000000000000000000000000000000000000000000000000000000000")); - expect(await testC.testBitsOp256(1, 128)).to.equal(BigInt("0x80000000000000000000000000000000")); - expect(await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 0)).to.equal(BigInt("0x100000000000000000000000000000000")); - expect(await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 1)).to.equal(BigInt("0x80000000000000000000000000000000")); - expect(await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 128)).to.equal(1); - expect(await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 129)).to.equal(0); - }); -}) + expect(await testC.testBitsOp8(0, 138)).to.equal(0); + expect(await testC.testBitsOp8(1, 0)).to.equal( + BigInt( + "0x8000000000000000000000000000000000000000000000000000000000000000" + ) + ); + expect(await testC.testBitsOp8(1, 1)).to.equal( + BigInt( + "0x4000000000000000000000000000000000000000000000000000000000000000" + ) + ); + expect(await testC.testBitsOp8(42, 3)).to.equal( + BigInt( + "0x0A80000000000000000000000000000000000000000000000000000000000000" + ) + ); + expect(await testC.testBitsOp8(3, 255)).to.equal(1); + expect(await testC.testBitsOp32(1, 0)).to.equal( + BigInt( + "0x8000000000000000000000000000000000000000000000000000000000000000" + ) + ); + expect(await testC.testBitsOp32(42, 3)).to.equal( + BigInt( + "0x0A80000000000000000000000000000000000000000000000000000000000000" + ) + ); + expect(await testC.testBitsOp32(BigInt("0x80000001"), 225)).to.equal( + BigInt("0x40000000") + ); + expect(await testC.testBitsOp32(995535, 236)).to.equal(995535); + expect(await testC.testBitsOp256(1, 0)).to.equal( + BigInt( + "0x8000000000000000000000000000000000000000000000000000000000000000" + ) + ); + expect(await testC.testBitsOp256(1, 128)).to.equal( + BigInt("0x80000000000000000000000000000000") + ); + expect( + await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 0) + ).to.equal(BigInt("0x100000000000000000000000000000000")); + expect( + await testC.testBitsOp256(BigInt("0x80000000000000000000000000000000"), 1) + ).to.equal(BigInt("0x80000000000000000000000000000000")); + expect( + await testC.testBitsOp256( + BigInt("0x80000000000000000000000000000000"), + 128 + ) + ).to.equal(1); + expect( + await testC.testBitsOp256( + BigInt("0x80000000000000000000000000000000"), + 129 + ) + ).to.equal(0); + }); +}); -const keccak256To160 = bytesLike => ('0x' + ethers.utils.keccak256(bytesLike).slice(26)); +const keccak256To160 = (bytesLike) => + "0x" + ethers.utils.keccak256(bytesLike).slice(26); -describe("TestWriteRegistryOp", function(){ - it("Encode registry op just like circuit did", async function () { - const TestC = await ethers.getContractFactory("TestLibs"); - const testC = await TestC.deploy(); +describe("TestWriteRegistryOp", function () { + it("Encode registry op just like circuit did", async function () { + const TestC = await ethers.getContractFactory("TestLibs"); + const testC = await TestC.deploy(); - await testC.deployed(); + await testC.deployed(); - //this cases only work for acc = 4, order = 4 and balance = 3 - const expectedEncodeOp1 = keccak256To160("0x91ba18348a3d7f991abc0eaee50583b0697d1fd451a039d21fa36fe748324fddc4"); - const expectedEncodeOp2 = keccak256To160("0x8997ad724ddb0f85f255bf087945654549ed416e131cf8719f21bb7b7ff54d7bf4"); - const expectedEncodeOp3 = keccak256To160("0x949c82e7b8eefc3ce0ef812304c79cba948014945150117fda5f1c0c33873099b8"); + //this cases only work for acc = 4, order = 4 and balance = 3 + const expectedEncodeOp1 = keccak256To160( + "0x91ba18348a3d7f991abc0eaee50583b0697d1fd451a039d21fa36fe748324fddc4" + ); + const expectedEncodeOp2 = keccak256To160( + "0x8997ad724ddb0f85f255bf087945654549ed416e131cf8719f21bb7b7ff54d7bf4" + ); + const expectedEncodeOp3 = keccak256To160( + "0x949c82e7b8eefc3ce0ef812304c79cba948014945150117fda5f1c0c33873099b8" + ); - expect(await testC.testWriteRegistryPubdata(1, - "0x5d182c51bcfe99583d7075a7a0c10d96bef82b8a059c4bf8c5f6e7124cf2bba3")) - .to.equal(expectedEncodeOp1); - expect(await testC.testWriteRegistryPubdata(2, - "0xe9b54eb2dbf0a14faafd109ea2a6a292b78276c8381f8ef984dddefeafb2deaf")) - .to.equal(expectedEncodeOp2); - expect(await testC.testWriteRegistryPubdata(5, - "0x3941e71d773f3c07f781c420e3395d290128298a0a88fe5bfa3830cce10c991d")) - .to.equal(expectedEncodeOp3); - }); -}) + expect( + await testC.testWriteRegistryPubdata( + 1, + "0x5d182c51bcfe99583d7075a7a0c10d96bef82b8a059c4bf8c5f6e7124cf2bba3" + ) + ).to.equal(expectedEncodeOp1); + expect( + await testC.testWriteRegistryPubdata( + 2, + "0xe9b54eb2dbf0a14faafd109ea2a6a292b78276c8381f8ef984dddefeafb2deaf" + ) + ).to.equal(expectedEncodeOp2); + expect( + await testC.testWriteRegistryPubdata( + 5, + "0x3941e71d773f3c07f781c420e3395d290128298a0a88fe5bfa3830cce10c991d" + ) + ).to.equal(expectedEncodeOp3); + }); +}); +describe("TestWriteDepositOp", function () { + it("Encode deposit op just like circuit did", async function () { + const TestC = await ethers.getContractFactory("TestLibs"); + const testC = await TestC.deploy(); -describe("TestWriteDepositOp", function(){ - it("Encode deposit op just like circuit did", async function () { - const TestC = await ethers.getContractFactory("TestLibs"); - const testC = await TestC.deploy(); + await testC.deployed(); - await testC.deployed(); + //this cases only work for acc = 4, order = 4 and balance = 3 + const expectedEncodeOp1 = keccak256To160( + "0x111000452958b80000000000000000000000000000000000000000000000000000" + ); - //this cases only work for acc = 4, order = 4 and balance = 3 - const expectedEncodeOp1 = keccak256To160("0x111000452958b80000000000000000000000000000000000000000000000000000"); - - expect(await testC.testWriteDepositPubdata(1, 1, - BigInt("500000000000"))) - .to.equal(expectedEncodeOp1); - }); -}) \ No newline at end of file + expect( + await testC.testWriteDepositPubdata(1, 1, BigInt("500000000000")) + ).to.equal(expectedEncodeOp1); + }); +}); From 67410266a0a27c658e5bb99ea9c91f2d8c59ef30 Mon Sep 17 00:00:00 2001 From: Ho Date: Fri, 3 Dec 2021 16:14:00 +0800 Subject: [PATCH 07/14] add mine script for localhost (instead of tick) --- scripts/mine.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 scripts/mine.ts diff --git a/scripts/mine.ts b/scripts/mine.ts new file mode 100644 index 0000000..b43d62e --- /dev/null +++ b/scripts/mine.ts @@ -0,0 +1,15 @@ +import * as hre from "hardhat"; + +async function main() { + + await hre.network.provider.send("evm_mine", []); + +} + + +main() + .then(() => process.exit(0)) + .catch(error => { + console.error(error); + process.exit(1); + }); From 0b97fae8a8430771731f99585794496eef98e8a5 Mon Sep 17 00:00:00 2001 From: Ho Date: Fri, 3 Dec 2021 16:36:33 +0800 Subject: [PATCH 08/14] encode op for registerUser --- contracts/FluiDex.sol | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index 4736d52..0780ada 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -194,6 +194,18 @@ contract FluiDexDemo is bjjPubkey: bjjPubkey }); userBjjPubkeyToUserId[bjjPubkey] = userId; + + Operations.Registry memory op = Operations.Registry({ + accountId: userId, + l2key: bjjPubkey + }); + + addPriorityRequest( + Operations.OpType.Registry, + Operations.writeRegistryPubdataForPriorityQueue(op) + ); + + emit RegisterUser(ethAddr, userId, bjjPubkey); } function getBlockStateByBlockId(uint256 _block_id) From 8abd4d6fc71e7ea35ec846b6c70d80ec8bfaa09b Mon Sep 17 00:00:00 2001 From: Ho Date: Wed, 29 Dec 2021 16:58:16 +0800 Subject: [PATCH 09/14] catching up with new master --- .gitignore | 4 +++- contracts/Events.sol | 2 +- contracts/FluiDex.sol | 34 ++++++++++++++-------------------- contracts/FluiDexDelegate.sol | 12 +++++++----- contracts/IFluiDex.sol | 12 ++++++++---- contracts/IFluiDexDelegate.sol | 3 ++- 6 files changed, 35 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index 6f5618b..828b11c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,6 @@ contract-deployed.env ganache/ # secrets -/secrets.json \ No newline at end of file +/secrets.json +accounts.json +deployed.json \ No newline at end of file diff --git a/contracts/Events.sol b/contracts/Events.sol index 3f5d793..ae0fc5e 100644 --- a/contracts/Events.sol +++ b/contracts/Events.sol @@ -5,5 +5,5 @@ pragma solidity ^0.8.0; interface Events { event NewToken(address submitter, address tokenAddr, uint16 tokenId); event RegisterUser(address ethAddr, uint16 userId, bytes32 bjjPubkey); - event Deposit(uint16 tokenId, bytes32 to, uint256 amount); + event Deposit(uint16 tokenId, bytes32 to, uint128 amount); } diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index 0780ada..551c55a 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/AccessControl.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "hardhat/console.sol"; // for debugging @@ -79,9 +80,10 @@ contract FluiDexDemo is /** * @notice request to add a new ERC20 token * @param tokenAddr the ERC20 token address + * @param prec specify the precise inside fluidex * @return the new ERC20 token tokenId */ - function addToken(address tokenAddr) + function addToken(address tokenAddr, uint8 prec) external override nonReentrant @@ -94,12 +96,11 @@ contract FluiDexDemo is uint16 tokenId = tokenNum; tokenIdToAddr[tokenId] = tokenAddr; - tokenAddrToId[tokenAddr] = tokenId; + tokenAddrToId[tokenAddr] = prec; - //TODO: should provide token's prec and check token's decimal - tokenScales[tokenId] = 12; - - emit NewToken(origin, tokenAddr, tokenId); + uint8 tokenDecimal = IERC20Metadata(tokenAddr).decimals(); + require(tokenDecimal >= prec, "prec can not exceed token's decimal"); + tokenScales[tokenId] = tokenDecimal - prec; return tokenId; } @@ -111,10 +112,11 @@ contract FluiDexDemo is payable override onlyRole(DELEGATE_ROLE) + returns (uint128 realAmount) { uint16 accountId = userBjjPubkeyToUserId[to]; require(accountId != 0, "non-existed user"); - uint128 amount = Operations.scaleTokenValueToAmount( + realAmount = Operations.scaleTokenValueToAmount( msg.value, tokenScales[0] ); @@ -122,16 +124,13 @@ contract FluiDexDemo is Operations.Deposit memory op = Operations.Deposit({ accountId: accountId, tokenId: 0, - amount: amount + amount: realAmount }); addPriorityRequest( Operations.OpType.Deposit, Operations.writeDepositPubdataForPriorityQueue(op) ); - - //TODO: correct the value to scaled amount? - emit Deposit(ETH_ID, to, msg.value); } /** @@ -143,34 +142,31 @@ contract FluiDexDemo is nonReentrant tokenExist(token) onlyRole(DELEGATE_ROLE) - returns (uint16 tokenId, uint256 realAmount) + returns (uint16 tokenId, uint128 realAmount) { tokenId = tokenAddrToId[address(token)]; uint256 balanceBeforeDeposit = token.balanceOf(address(this)); token.safeTransferFrom(msg.sender, address(this), amount); uint256 balanceAfterDeposit = token.balanceOf(address(this)); - uint256 realAmount = balanceAfterDeposit - balanceBeforeDeposit; uint16 accountId = userBjjPubkeyToUserId[to]; require(accountId != 0, "non-existed user"); - uint128 scaledAmount = Operations.scaleTokenValueToAmount( - amount, + realAmount = Operations.scaleTokenValueToAmount( + balanceAfterDeposit - balanceBeforeDeposit, tokenScales[tokenId] ); Operations.Deposit memory op = Operations.Deposit({ accountId: accountId, tokenId: tokenId, - amount: scaledAmount + amount: realAmount }); addPriorityRequest( Operations.OpType.Deposit, Operations.writeDepositPubdataForPriorityQueue(op) ); - - emit Deposit(tokenId, to, realAmount); } /** @@ -204,8 +200,6 @@ contract FluiDexDemo is Operations.OpType.Registry, Operations.writeRegistryPubdataForPriorityQueue(op) ); - - emit RegisterUser(ethAddr, userId, bjjPubkey); } function getBlockStateByBlockId(uint256 _block_id) diff --git a/contracts/FluiDexDelegate.sol b/contracts/FluiDexDelegate.sol index c2bf5fd..d61cf51 100644 --- a/contracts/FluiDexDelegate.sol +++ b/contracts/FluiDexDelegate.sol @@ -47,15 +47,16 @@ contract FluiDexDelegate is /** * @notice request to add a new ERC20 token * @param tokenAddr the ERC20 token address + * @param prec specify the precise inside fluidex * @return tokenId the new ERC20 token tokenId */ - function addToken(address tokenAddr) + function addToken(address tokenAddr, uint8 prec) external override onlyRole(TOKEN_ADMIN_ROLE) returns (uint16 tokenId) { - tokenId = target.addToken(tokenAddr); + tokenId = target.addToken(tokenAddr, prec); emit NewToken(msg.sender, tokenAddr, tokenId); } @@ -68,8 +69,8 @@ contract FluiDexDelegate is override orCreateUser(msg.sender, to) { - target.depositETH{value: msg.value}(to); - emit Deposit(ETH_ID, to, msg.value); + uint128 finalAmount = target.depositETH{value: msg.value}(to); + emit Deposit(ETH_ID, to, finalAmount); } /** @@ -87,8 +88,9 @@ contract FluiDexDelegate is uint256 realAmount = balanceAfterDeposit - balanceBeforeDeposit; token.safeIncreaseAllowance(address(target), realAmount); - (uint16 tokenId, uint256 finalAmount) = target.depositERC20( + (uint16 tokenId, uint128 finalAmount) = target.depositERC20( token, + to, realAmount ); emit Deposit(tokenId, to, finalAmount); diff --git a/contracts/IFluiDex.sol b/contracts/IFluiDex.sol index 4a14f63..415af67 100644 --- a/contracts/IFluiDex.sol +++ b/contracts/IFluiDex.sol @@ -19,21 +19,25 @@ interface IFluiDex { /** * @notice request to add a new ERC20 token * @param tokenAddr the ERC20 token address + * @param prec specify the precise inside fluidex * @return the new ERC20 token tokenId */ - function addToken(address tokenAddr) external returns (uint16); + function addToken(address tokenAddr, uint8 prec) external returns (uint16); /** * @param to the L2 address (bjjPubkey) of the deposit target. */ - function depositETH(bytes32 to) external payable; + function depositETH(bytes32 to) + external + payable + returns (uint128 realAmount); /** * @param amount the deposit amount. */ - function depositERC20(IERC20 token, uint256 amount) + function depositERC20(IERC20 token, bytes32 to, uint256 amount) external - returns (uint16 tokenId, uint256 realAmount); + returns (uint16 tokenId, uint128 realAmount); function getBlockStateByBlockId(uint256 _block_id) external diff --git a/contracts/IFluiDexDelegate.sol b/contracts/IFluiDexDelegate.sol index 640c5a6..df5be32 100644 --- a/contracts/IFluiDexDelegate.sol +++ b/contracts/IFluiDexDelegate.sol @@ -8,9 +8,10 @@ interface IFluiDexDelegate { /** * @notice request to add a new ERC20 token * @param tokenAddr the ERC20 token address + * @param prec specify the precise inside fluidex * @return the new ERC20 token tokenId */ - function addToken(address tokenAddr) external returns (uint16); + function addToken(address tokenAddr, uint8 prec) external returns (uint16); /** * @param to the L2 address (bjjPubkey) of the deposit target. From e0fcb4d0dd6cd3a0c9c2d97fa0f4ee2668cba7ec Mon Sep 17 00:00:00 2001 From: Ho Date: Wed, 29 Dec 2021 17:02:21 +0800 Subject: [PATCH 10/14] fmt --- contracts/FluiDex.sol | 6 +++++- contracts/IFluiDex.sol | 12 +++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index 551c55a..e7e8d13 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -136,7 +136,11 @@ contract FluiDexDemo is /** * @param amount the deposit amount. */ - function depositERC20(IERC20 token, bytes32 to, uint256 amount) + function depositERC20( + IERC20 token, + bytes32 to, + uint256 amount + ) external override nonReentrant diff --git a/contracts/IFluiDex.sol b/contracts/IFluiDex.sol index 415af67..7c3c763 100644 --- a/contracts/IFluiDex.sol +++ b/contracts/IFluiDex.sol @@ -27,17 +27,19 @@ interface IFluiDex { /** * @param to the L2 address (bjjPubkey) of the deposit target. */ - function depositETH(bytes32 to) - external + function depositETH(bytes32 to) + external payable returns (uint128 realAmount); /** * @param amount the deposit amount. */ - function depositERC20(IERC20 token, bytes32 to, uint256 amount) - external - returns (uint16 tokenId, uint128 realAmount); + function depositERC20( + IERC20 token, + bytes32 to, + uint256 amount + ) external returns (uint16 tokenId, uint128 realAmount); function getBlockStateByBlockId(uint256 _block_id) external From 270b5e3cd20c58ec82fbc9b813626e58f25aef6a Mon Sep 17 00:00:00 2001 From: Ho Date: Tue, 11 Jan 2022 22:24:03 +0800 Subject: [PATCH 11/14] update contracts --- contracts/FluiDex.sol | 72 ++++++++++++++++++++++------------------ contracts/Operations.sol | 13 +++++--- 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index e7e8d13..03d67fa 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -61,8 +61,8 @@ contract FluiDexDemo is grantRole(PLUGIN_ADMIN_ROLE, msg.sender); grantRole(DELEGATE_ROLE, msg.sender); - //TODO: define defaut scale of ETH: eth (10^18 wei) with prec 6 so we get - tokenScales[0] = 12; + //TODO: define defaut scale of ETH: eth (10^18 wei) with prec 4 so we get + tokenScales[0] = 14; } /** @@ -150,14 +150,10 @@ contract FluiDexDemo is { tokenId = tokenAddrToId[address(token)]; - uint256 balanceBeforeDeposit = token.balanceOf(address(this)); - token.safeTransferFrom(msg.sender, address(this), amount); - uint256 balanceAfterDeposit = token.balanceOf(address(this)); - uint16 accountId = userBjjPubkeyToUserId[to]; require(accountId != 0, "non-existed user"); realAmount = Operations.scaleTokenValueToAmount( - balanceAfterDeposit - balanceBeforeDeposit, + amount, tokenScales[tokenId] ); @@ -225,15 +221,16 @@ contract FluiDexDemo is function verifyBlock( uint256[] calldata _public_inputs, uint256[] calldata _serialized_proof, - bytes calldata _public_data - ) public view returns (bool) { + bytes calldata _public_data, + bytes calldata _priority_op_index + ) public view returns (uint64) { // _public_inputs[2]/[3] is the low/high 128bit of sha256 hash of _public_data respectively - require(_public_inputs.length >= 4); + require(_public_inputs.length >= 4, "invalid public input fields"); bytes32 h = sha256(_public_data); - console.logBytes(_public_data); - console.logBytes32(h); + //console.logBytes(_public_data); + //console.logBytes32(h); uint256 h_lo = 0; for (uint256 i = 0; i < 16; i++) { @@ -246,11 +243,32 @@ contract FluiDexDemo is h_hi = h_hi + tmp; } - assert(_public_inputs[2] == h_hi); - assert(_public_inputs[3] == h_lo); + require( + _public_inputs[2] == h_hi && _public_inputs[3] == h_lo, + "tx data invalid" + ); + + uint64 next_priority_op = firstPriorityRequestId; + if (_priority_op_index.length != 0) { + (bool pass, uint64 nextIndex) = verifyPriorityOp( + _public_data, + _priority_op_index + ); + console.log( + "start from %d, stop in index %d, current %d", + firstPriorityRequestId, + nextIndex, + totalOpenPriorityRequests + ); + require(pass, "handling priority ops incorrect"); + next_priority_op = nextIndex; + } - return - verifier.verify_serialized_proof(_public_inputs, _serialized_proof); + require( + verifier.verify_serialized_proof(_public_inputs, _serialized_proof), + "proof is invalid" + ); + return next_priority_op; } /** @@ -271,30 +289,20 @@ contract FluiDexDemo is assert(_public_inputs[0] == state_roots[_block_id - 1]); } - //forward priority op - if (_priority_op_index.length != 0) { - (bool pass, uint64 nextIndex) = verifyPriorityOp( + if (_serialized_proof.length != 0) { + uint64 nextIndex = verifyBlock( + _public_inputs, + _serialized_proof, _public_data, _priority_op_index ); - require(pass, "handling priority ops not correct"); + + //forward priority op assert( totalOpenPriorityRequests >= nextIndex - firstPriorityRequestId ); totalOpenPriorityRequests -= nextIndex - firstPriorityRequestId; firstPriorityRequestId = nextIndex; - } - - if (_serialized_proof.length != 0) { - bool ret = verifyBlock( - _public_inputs, - _serialized_proof, - _public_data - ); - - if (!ret) { - return ret; - } if (_block_id > 0) { require( diff --git a/contracts/Operations.sol b/contracts/Operations.sol index 26e767b..0356974 100644 --- a/contracts/Operations.sol +++ b/contracts/Operations.sol @@ -11,8 +11,8 @@ import "hardhat/console.sol"; //for debugging library Operations { /// @notice Config parameters, generated from circuit parameters uint8 constant BALANCE_BITS = 3; - uint8 constant ACCOUNT_BITS = 4; - uint8 constant ORDER_BITS = 4; + uint8 constant ACCOUNT_BITS = 5; + uint8 constant ORDER_BITS = 3; uint256 constant TX_PUBDATA_BYTES = 33; /// @dev Expected average period of block creation @@ -38,8 +38,12 @@ library Operations { pure returns (bytes20) { + uint256 start = pos * TX_PUBDATA_BYTES; + return - Utils.hashBytesToBytes20(_public_data[pos:pos + TX_PUBDATA_BYTES]); + Utils.hashBytesToBytes20( + _public_data[start:start + TX_PUBDATA_BYTES] + ); } // Registry L2key pubdata @@ -60,7 +64,8 @@ library Operations { pure returns (uint128) { - require(scale > 0, "Known token must has a scaling"); + //require(scale > 0, "Known token must has a scaling"); + //notice scale can be zero if the decimal just equal to the prec used inside fluidex return uint128(value / (10**scale)); } From d172c9cb10e9bccee9cb3fb8b8a270032543e66f Mon Sep 17 00:00:00 2001 From: Ho Date: Thu, 13 Jan 2022 20:21:19 +0800 Subject: [PATCH 12/14] update for DA features --- contracts/Events.sol | 2 +- contracts/FluiDex.sol | 10 +++++----- contracts/FluiDexDelegate.sol | 14 +++++--------- scripts/deploy.ts | 22 +++++++++++++--------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/contracts/Events.sol b/contracts/Events.sol index ae0fc5e..3f5d793 100644 --- a/contracts/Events.sol +++ b/contracts/Events.sol @@ -5,5 +5,5 @@ pragma solidity ^0.8.0; interface Events { event NewToken(address submitter, address tokenAddr, uint16 tokenId); event RegisterUser(address ethAddr, uint16 userId, bytes32 bjjPubkey); - event Deposit(uint16 tokenId, bytes32 to, uint128 amount); + event Deposit(uint16 tokenId, bytes32 to, uint256 amount); } diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index 03d67fa..7c1df55 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -61,8 +61,8 @@ contract FluiDexDemo is grantRole(PLUGIN_ADMIN_ROLE, msg.sender); grantRole(DELEGATE_ROLE, msg.sender); - //TODO: define defaut scale of ETH: eth (10^18 wei) with prec 4 so we get - tokenScales[0] = 14; + //TODO: define defaut scale of ETH: eth (10^18 wei) with prec 6 so we get + tokenScales[0] = 12; } /** @@ -96,7 +96,7 @@ contract FluiDexDemo is uint16 tokenId = tokenNum; tokenIdToAddr[tokenId] = tokenAddr; - tokenAddrToId[tokenAddr] = prec; + tokenAddrToId[tokenAddr] = tokenId; uint8 tokenDecimal = IERC20Metadata(tokenAddr).decimals(); require(tokenDecimal >= prec, "prec can not exceed token's decimal"); @@ -254,12 +254,12 @@ contract FluiDexDemo is _public_data, _priority_op_index ); - console.log( + /* console.log( "start from %d, stop in index %d, current %d", firstPriorityRequestId, nextIndex, totalOpenPriorityRequests - ); + );*/ require(pass, "handling priority ops incorrect"); next_priority_op = nextIndex; } diff --git a/contracts/FluiDexDelegate.sol b/contracts/FluiDexDelegate.sol index d61cf51..ab2346f 100644 --- a/contracts/FluiDexDelegate.sol +++ b/contracts/FluiDexDelegate.sol @@ -69,8 +69,8 @@ contract FluiDexDelegate is override orCreateUser(msg.sender, to) { - uint128 finalAmount = target.depositETH{value: msg.value}(to); - emit Deposit(ETH_ID, to, finalAmount); + target.depositETH{value: msg.value}(to); + emit Deposit(ETH_ID, to, msg.value); } /** @@ -81,19 +81,15 @@ contract FluiDexDelegate is IERC20 token, bytes32 to, uint256 amount - ) external override { + ) external override orCreateUser(msg.sender, to) { uint256 balanceBeforeDeposit = token.balanceOf(address(this)); token.safeTransferFrom(msg.sender, address(this), amount); uint256 balanceAfterDeposit = token.balanceOf(address(this)); uint256 realAmount = balanceAfterDeposit - balanceBeforeDeposit; token.safeIncreaseAllowance(address(target), realAmount); - (uint16 tokenId, uint128 finalAmount) = target.depositERC20( - token, - to, - realAmount - ); - emit Deposit(tokenId, to, finalAmount); + (uint16 tokenId, ) = target.depositERC20(token, to, realAmount); + emit Deposit(tokenId, to, realAmount); } /** diff --git a/scripts/deploy.ts b/scripts/deploy.ts index 75398ee..e50ca21 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -7,6 +7,7 @@ import { getTestAccount } from "./accounts"; const loadAccounts = () => Array.from(botsIds).map((user_id) => Account.fromMnemonic(getTestAccount(user_id).mnemonic)); const botsIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; const accounts = loadAccounts(); +const outputPath = process.env.DEPLOY_DIR || '/tmp/' interface Token { symbol: string, @@ -17,7 +18,7 @@ async function main() { await run('compile'); let tokens: Token[]; - const raw = fs.readFileSync('/tmp/tokens.json', 'utf-8'); + const raw = fs.readFileSync(`${outputPath}tokens.json`, 'utf-8'); tokens = JSON.parse(raw); let deployed: Record = {}; @@ -36,14 +37,15 @@ async function main() { console.log("FluiDex deployed to:", fluiDex.address); deployed['FluiDexDemo'] = fluiDex.address; - const registerUser = fluiDex.functions.registerUser; + // const registerUser = fluiDex.functions.registerUser; const accountsDump = new Array(); for(const [idx, account] of accounts.entries()) { - await registerUser(account.ethAddr, account.bjjPubKey); - accountsDump.push({ id: idx, pubkey: account.bjjPubKey }); + // await registerUser(account.ethAddr, account.bjjPubKey); + // for provided to the "offline" mode of ethlistener, id should start from 1 + accountsDump.push({ id: idx + 1, pubkey: account.bjjPubKey }); console.log(`register user ${account.bjjPubKey}`); } - fs.writeFileSync('/tmp/accounts.json', JSON.stringify(accountsDump)); + fs.writeFileSync(`${outputPath}accounts.json`, JSON.stringify(accountsDump)); const fluiDexDelegateFactory = await ethers.getContractFactory("FluiDexDelegate"); const fluiDexDelegate = await fluiDexDelegateFactory.deploy(fluiDex.address); @@ -53,7 +55,7 @@ async function main() { deployed['FluiDexDelegate'] = fluiDexDelegate.address; const tx = await ethers.provider.getTransaction(fluiDexDelegate.deployTransaction.hash); deployed['baseBlock'] = tx.blockNumber!!; - fs.writeFileSync('/tmp/deployed.json', JSON.stringify(deployed)); + fs.writeFileSync(`${outputPath}deployed.json`, JSON.stringify(deployed)); const DELEGATE_ROLE = await fluiDex.callStatic.DELEGATE_ROLE(); await fluiDex.functions.grantRole(DELEGATE_ROLE, fluiDexDelegate.address); @@ -61,12 +63,14 @@ async function main() { const addToken = fluiDexDelegate.functions.addToken; for (const {symbol, address} of Array.from(tokens)) { - await addToken(address); - console.log(`add ${symbol} token at`, address); + //the prec is consistend with pre-defined assets + let prec = 6; + await addToken(address, 6); + console.log(`add ${symbol} token (prec ${prec}) at`, address); } // skip verify on localhost - if (hre.network.name !== "geth") { + if (hre.network.name == "goerli") { try { await run('verify', { address: verifier.address, From b97eb8988172caf2b8c04d8db6167d8626fc2a46 Mon Sep 17 00:00:00 2001 From: Ho Date: Thu, 13 Jan 2022 22:42:27 +0800 Subject: [PATCH 13/14] deposit script --- scripts/deposit.ts | 87 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 scripts/deposit.ts diff --git a/scripts/deposit.ts b/scripts/deposit.ts new file mode 100644 index 0000000..2816a8b --- /dev/null +++ b/scripts/deposit.ts @@ -0,0 +1,87 @@ +import * as fs from 'fs'; +import { Account } from "fluidex.js"; +import { ethers } from "hardhat"; +//import * as hre from "hardhat"; +import { getTestAccount } from "./accounts"; +import { assert } from 'chai'; + +const loadAccounts = () => Array.from(botsIds).map((user_id) => Account.fromMnemonic(getTestAccount(user_id).mnemonic)); +const botsIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; +const accounts = loadAccounts(); + +interface Token { + symbol: string, + address: string, +} + +const Erc20Abi = [ + // Read-Only Functions + "function balanceOf(address owner) view returns (uint256)", + "function allowance(address owner, address spender) view returns (uint256)", + "function decimals() view returns (uint8)", + "function symbol() view returns (string)", + + // Authenticated Functions + "function transfer(address to, uint amount) returns (bool)", + "function approve(address spender, uint amount) returns (bool)", + + // Events + "event Transfer(address indexed from, address indexed to, uint amount)" +]; + +let tokens: Token[]; +const raw = fs.readFileSync('tokens.json', 'utf-8'); +tokens = JSON.parse(raw); + +async function deploy_account(userId: number, account: Account) { + + let acc_wallet = ethers.Wallet.fromMnemonic(getTestAccount(userId).mnemonic); + let acc_address = await acc_wallet.getAddress(); + assert(account.ethAddr == acc_address, "same account"); + let acc_l2 = account.bjjPubKey; + + acc_wallet = acc_wallet.connect(ethers.provider); + let ethBalance = await acc_wallet.getBalance(); + console.log("eth balance of ", acc_address, ethBalance.toString()); + assert(account.ethAddr == acc_address, "same account"); + + const delegateAddress = process.env.CONTRACT_ADDR; + console.log("delegate contract at:", delegateAddress); + const contract = await ethers.getContractAt("FluiDexDelegate", delegateAddress as string, acc_wallet); + + for (const {symbol, address} of Array.from(tokens)) { + //suppose all symbol use prec as 6 + let depositAmount = symbol == 'USDT' ? BigInt('500000000000') : BigInt('10000000'); + console.log(`Find ${symbol} at`, address); + + let erc20 = new ethers.Contract(address, Erc20Abi, acc_wallet); + let ercBalance = await erc20.functions.balanceOf(acc_address); + console.log(`${acc_address}'s balance of ${symbol}`, ercBalance.toString()); + + let allowedBalanced = await erc20.functions.allowance(acc_address, delegateAddress); + if (allowedBalanced < depositAmount){ + console.log(`no enough allowed balance: expected ${depositAmount} but only ${allowedBalanced}`), + await erc20.functions.approve(delegateAddress, depositAmount); + } + + await contract.functions.depositERC20(address, acc_l2, depositAmount); + } + await contract.functions.depositETH(acc_l2, {value: ethers.utils.parseEther("0.6")} /* overrides */); + +} + + +async function main() { + + for(const [idx, account] of accounts.entries()) { + await deploy_account(idx + 1, account); + } + +} + +main() + .then(() => process.exit(0)) + .catch(error => { + console.error(error); + process.exit(1); + }); From 3a9026ba776a68c9dcf44e77a45e14298a0cb2be Mon Sep 17 00:00:00 2001 From: Ho Date: Fri, 14 Jan 2022 11:29:23 +0800 Subject: [PATCH 14/14] update yarn lock --- yarn.lock | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 250 insertions(+), 7 deletions(-) diff --git a/yarn.lock b/yarn.lock index 77dcd30..7fd2802 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1169,6 +1169,11 @@ "@types/bn.js" "*" "@types/underscore" "*" +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" @@ -1286,7 +1291,7 @@ ansi-colors@3.2.3: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== -ansi-colors@^4.1.1: +ansi-colors@4.1.1, ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== @@ -1335,7 +1340,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -1367,6 +1372,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -2390,6 +2400,11 @@ camelcase@^5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + caniuse-lite@^1.0.30000844: version "1.0.30001240" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001240.tgz#ec15d125b590602c8731545c5351ff054ad2d52f" @@ -2440,6 +2455,14 @@ chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" @@ -2467,7 +2490,7 @@ chokidar@3.3.0: optionalDependencies: fsevents "~2.1.1" -chokidar@^3.4.0: +chokidar@3.5.2, chokidar@^3.4.0: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== @@ -2588,6 +2611,15 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" @@ -2875,6 +2907,13 @@ debug@4, debug@^4.1.1: dependencies: ms "2.1.2" +debug@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + debug@^3.1.0: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -2887,6 +2926,11 @@ decamelize@^1.1.1, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -3015,6 +3059,11 @@ diff@3.5.0: resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -3222,6 +3271,11 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.3: d "^1.0.1" ext "^1.1.2" +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -3232,7 +3286,7 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escape-string-regexp@^4.0.0: +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== @@ -4009,6 +4063,14 @@ find-up@3.0.0, find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -4054,6 +4116,11 @@ flat@^4.1.0: dependencies: is-buffer "~2.0.3" +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + flow-stoplight@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b" @@ -4245,7 +4312,7 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -4314,7 +4381,7 @@ glob@7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.2, glob@^7.1.3, glob@~7.1.6: +glob@7.1.7, glob@^7.1.2, glob@^7.1.3, glob@~7.1.6: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== @@ -4469,6 +4536,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" @@ -4914,6 +4986,11 @@ is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -4963,6 +5040,11 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + is-url@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" @@ -5063,6 +5145,13 @@ js-yaml@3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -5454,6 +5543,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.assign@^4.0.3, lodash.assign@^4.0.6: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" @@ -5476,6 +5572,14 @@ log-symbols@3.0.0: dependencies: chalk "^2.4.2" +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + looper@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec" @@ -5833,6 +5937,36 @@ mocha@^7.1.2: yargs-parser "13.1.2" yargs-unparser "1.6.0" +mocha@^9.1.3: + version "9.1.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.1.3.tgz#8a623be6b323810493d8c8f6f7667440fa469fdb" + integrity sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.2" + debug "4.3.2" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.1.7" + growl "1.10.5" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "3.0.4" + ms "2.1.3" + nanoid "3.1.25" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + workerpool "6.1.5" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + mock-fs@^4.1.0: version "4.14.0" resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" @@ -5853,7 +5987,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -5913,6 +6047,11 @@ nanoassert@^1.0.0: resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d" integrity sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40= +nanoid@3.1.25: + version "3.1.25" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" + integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -6189,6 +6328,13 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -6210,6 +6356,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-timeout@^1.1.1: version "1.2.1" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" @@ -7016,6 +7169,13 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -7477,6 +7637,11 @@ strip-json-comments@2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + supports-color@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" @@ -7484,6 +7649,13 @@ supports-color@6.0.0: dependencies: has-flag "^3.0.0" +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -7496,6 +7668,13 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + swarm-js@^0.1.40: version "0.1.40" resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99" @@ -8391,6 +8570,13 @@ which@1.3.1, which@^1.2.9: dependencies: isexe "^2.0.0" +which@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + wide-align@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -8408,6 +8594,11 @@ worker-threads@^1.0.0: resolved "https://registry.yarnpkg.com/worker-threads/-/worker-threads-1.0.0.tgz#2b49ea7c9692ba737d9148f2c9b2be65e14e3470" integrity sha512-vK6Hhvph8oLxocEJIlc3YfGAZhm210uGzjZsXSu+JYLAQ/s/w4Tqgl60JrdH58hW8NSGP4m3bp8a92qPXgX05w== +workerpool@6.1.5: + version "6.1.5" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" + integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -8434,6 +8625,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -8524,6 +8724,11 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yaeti@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" @@ -8547,6 +8752,11 @@ yargs-parser@13.1.2, yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -8563,6 +8773,11 @@ yargs-parser@^2.4.1: camelcase "^3.0.0" lodash.assign "^4.0.6" +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-unparser@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" @@ -8572,6 +8787,16 @@ yargs-unparser@1.6.0: lodash "^4.17.15" yargs "^13.3.0" +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + yargs@13.3.2, yargs@^13.3.0: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" @@ -8588,6 +8813,19 @@ yargs@13.3.2, yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.2" +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yargs@^15.3.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -8629,3 +8867,8 @@ yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==