diff --git a/.gitignore b/.gitignore index 305350c..828b11c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules - +package-lock.json #Hardhat files cache artifacts @@ -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/Bytes.sol b/contracts/Bytes.sol new file mode 100644 index 0000000..d6258dd --- /dev/null +++ b/contracts/Bytes.sol @@ -0,0 +1,156 @@ +// 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); + } +} diff --git a/contracts/FluiDex.sol b/contracts/FluiDex.sol index c8f8907..7c1df55 100644 --- a/contracts/FluiDex.sol +++ b/contracts/FluiDex.sol @@ -5,17 +5,25 @@ 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 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 +45,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 +60,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; } /** @@ -68,9 +80,10 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { /** * @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 @@ -85,6 +98,9 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { tokenIdToAddr[tokenId] = tokenAddr; tokenAddrToId[tokenAddr] = tokenId; + uint8 tokenDecimal = IERC20Metadata(tokenAddr).decimals(); + require(tokenDecimal >= prec, "prec can not exceed token's decimal"); + tokenScales[tokenId] = tokenDecimal - prec; return tokenId; } @@ -96,25 +112,61 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { payable override onlyRole(DELEGATE_ROLE) - {} + returns (uint128 realAmount) + { + uint16 accountId = userBjjPubkeyToUserId[to]; + require(accountId != 0, "non-existed user"); + realAmount = Operations.scaleTokenValueToAmount( + msg.value, + tokenScales[0] + ); + + Operations.Deposit memory op = Operations.Deposit({ + accountId: accountId, + tokenId: 0, + amount: realAmount + }); + + addPriorityRequest( + Operations.OpType.Deposit, + Operations.writeDepositPubdataForPriorityQueue(op) + ); + } /** * @param amount the deposit amount. */ - function depositERC20(IERC20 token, uint256 amount) + function depositERC20( + IERC20 token, + bytes32 to, + uint256 amount + ) external override 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)); - realAmount = balanceAfterDeposit - balanceBeforeDeposit; + uint16 accountId = userBjjPubkeyToUserId[to]; + require(accountId != 0, "non-existed user"); + realAmount = Operations.scaleTokenValueToAmount( + amount, + tokenScales[tokenId] + ); + + Operations.Deposit memory op = Operations.Deposit({ + accountId: accountId, + tokenId: tokenId, + amount: realAmount + }); + + addPriorityRequest( + Operations.OpType.Deposit, + Operations.writeDepositPubdataForPriorityQueue(op) + ); } /** @@ -138,6 +190,16 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { bjjPubkey: bjjPubkey }); userBjjPubkeyToUserId[bjjPubkey] = userId; + + Operations.Registry memory op = Operations.Registry({ + accountId: userId, + l2key: bjjPubkey + }); + + addPriorityRequest( + Operations.OpType.Registry, + Operations.writeRegistryPubdataForPriorityQueue(op) + ); } function getBlockStateByBlockId(uint256 _block_id) @@ -150,17 +212,137 @@ contract FluiDexDemo is AccessControl, IFluiDex, Ownable, ReentrancyGuard { } /** - * @notice request to submit a new l2 block - * @param _block_id the l2 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[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + 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, "invalid public input fields"); + + bytes32 h = sha256(_public_data); + + //console.logBytes(_public_data); + //console.logBytes32(h); + + uint256 h_lo = 0; + 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 (uint256 i = 0; i < 16; i++) { + uint256 tmp = uint256(uint8(h[i])) << (120 - 8 * i); + h_hi = h_hi + tmp; + } + + 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; + } + + require( + verifier.verify_serialized_proof(_public_inputs, _serialized_proof), + "proof is invalid" + ); + return next_priority_op; + } + + /** + * @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 + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + bytes calldata _public_data, + bytes calldata _priority_op_index ) external override returns (bool) { + 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]); + } + + if (_serialized_proof.length != 0) { + uint64 nextIndex = verifyBlock( + _public_inputs, + _serialized_proof, + _public_data, + _priority_op_index + ); + + //forward priority op + assert( + totalOpenPriorityRequests >= nextIndex - firstPriorityRequestId + ); + totalOpenPriorityRequests -= nextIndex - firstPriorityRequestId; + firstPriorityRequestId = nextIndex; + + 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]; + return true; + } + + /** + * @notice request to submit a new l2 block + * @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 + * @return true if the block was accepted + */ + function submitBlockLegacy( + uint256 _block_id, + 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 require(_public_inputs.length >= 2); diff --git a/contracts/FluiDexDelegate.sol b/contracts/FluiDexDelegate.sol index 955d09e..ab2346f 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); } @@ -80,18 +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, uint256 finalAmount) = target.depositERC20( - token, - realAmount - ); - emit Deposit(tokenId, to, finalAmount); + (uint16 tokenId, ) = target.depositERC20(token, to, realAmount); + emit Deposit(tokenId, to, realAmount); } /** @@ -103,10 +101,19 @@ contract FluiDexDelegate is */ function submitBlock( uint256 _block_id, - uint256[] memory _public_inputs, - uint256[] memory _serialized_proof + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + bytes calldata _public_data, + bytes calldata _priority_op_index ) external override returns (bool) { - return target.submitBlock(_block_id, _public_inputs, _serialized_proof); + return + target.submitBlock( + _block_id, + _public_inputs, + _serialized_proof, + _public_data, + _priority_op_index + ); } /** diff --git a/contracts/IFluiDex.sol b/contracts/IFluiDex.sol index 96f1826..7c3c763 100644 --- a/contracts/IFluiDex.sol +++ b/contracts/IFluiDex.sol @@ -19,21 +19,27 @@ 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) - external - returns (uint16 tokenId, uint256 realAmount); + function depositERC20( + IERC20 token, + bytes32 to, + uint256 amount + ) external returns (uint16 tokenId, uint128 realAmount); function getBlockStateByBlockId(uint256 _block_id) external @@ -44,12 +50,16 @@ 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) + * @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[] memory _public_inputs, - uint256[] memory _serialized_proof + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + bytes calldata _public_data, + bytes calldata _priority_op_index ) external returns (bool); /** diff --git a/contracts/IFluiDexDelegate.sol b/contracts/IFluiDexDelegate.sol index 23605f5..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. @@ -32,11 +33,15 @@ 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) + * @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[] memory _public_inputs, - uint256[] memory _serialized_proof + uint256[] calldata _public_inputs, + uint256[] calldata _serialized_proof, + bytes calldata _public_data, + bytes calldata _priority_op_index ) external returns (bool); } diff --git a/contracts/Operations.sol b/contracts/Operations.sol new file mode 100644 index 0000000..0356974 --- /dev/null +++ b/contracts/Operations.sol @@ -0,0 +1,135 @@ +// 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 = 5; + uint8 constant ORDER_BITS = 3; + uint256 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, uint256 pos) + internal + pure + returns (bytes20) + { + uint256 start = pos * TX_PUBDATA_BYTES; + + return + Utils.hashBytesToBytes20( + _public_data[start:start + TX_PUBDATA_BYTES] + ); + } + + // Registry L2key pubdata + struct Registry { + uint32 accountId; + bytes32 l2key; + } + + // Deposit pubdata + struct Deposit { + uint32 accountId; + uint16 tokenId; + uint128 amount; + } + + function scaleTokenValueToAmount(uint256 value, uint8 scale) + internal + pure + returns (uint128) + { + //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)); + } + + function hashOpDataFromBuf(bytes memory buf) + internal + pure + returns (bytes20) + { + bytes memory truncatedBuf = new bytes(TX_PUBDATA_BYTES); + for (uint256 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..8281dda --- /dev/null +++ b/contracts/Storage.sol @@ -0,0 +1,104 @@ +// 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 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 + ) 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 (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])); + 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) { + 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..87ea3dd --- /dev/null +++ b/contracts/TestLibs.sol @@ -0,0 +1,59 @@ +// 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); + } +} diff --git a/contracts/Utils.sol b/contracts/Utils.sol new file mode 100644 index 0000000..500671d --- /dev/null +++ b/contracts/Utils.sol @@ -0,0 +1,13 @@ +// 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/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<string, string | number> = {}; @@ -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, 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); + }); 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); + }); diff --git a/test/operations-test.js b/test/operations-test.js new file mode 100644 index 0000000..bc86c1c --- /dev/null +++ b/test/operations-test.js @@ -0,0 +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(); + + 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); + }); +}); 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==