From 0b8909a210496979935231f2eb969dca3847d6ab Mon Sep 17 00:00:00 2001 From: chenf Date: Tue, 7 Dec 2021 14:13:03 +0800 Subject: [PATCH 01/41] BatchMining --- contracts/NestBase.sol | 6 +- contracts/NestBatchMining.sol | 1484 ++++++++++++++++++++++ contracts/interface/INestBatchMining.sol | 289 +++++ hardhat.config.js | 2 +- scripts/deploy.js | 2 +- scripts/deploy.proxy.js | 47 +- test/16.NestBatchMining.js | 120 ++ test/17.NestBatchMining.js | 132 ++ test/18.NestBatchMining.js | 131 ++ test/19.NestBatchMining.js | 130 ++ 10 files changed, 2322 insertions(+), 21 deletions(-) create mode 100644 contracts/NestBatchMining.sol create mode 100644 contracts/interface/INestBatchMining.sol create mode 100644 test/16.NestBatchMining.js create mode 100644 test/17.NestBatchMining.js create mode 100644 test/18.NestBatchMining.js create mode 100644 test/19.NestBatchMining.js diff --git a/contracts/NestBase.sol b/contracts/NestBase.sol index 8e26a31..75550ba 100644 --- a/contracts/NestBase.sol +++ b/contracts/NestBase.sol @@ -10,8 +10,8 @@ import "./interface/INestLedger.sol"; contract NestBase { // Address of nest token contract - address constant NEST_TOKEN_ADDRESS = 0x98f8669F6481EbB341B522fCD3663f79A3d1A6A7; - + //address constant NEST_TOKEN_ADDRESS = 0x98f8669F6481EbB341B522fCD3663f79A3d1A6A7; + address NEST_TOKEN_ADDRESS; // Genesis block number of nest // NEST token contract is created at block height 6913517. However, because the mining algorithm of nest1.0 // is different from that at present, a new mining algorithm is adopted from nest2.0. The new algorithm @@ -39,6 +39,8 @@ contract NestBase { address governance = _governance; require(governance == msg.sender || INestGovernance(governance).checkGovernance(msg.sender, 0), "NEST:!gov"); _governance = nestGovernanceAddress; + + NEST_TOKEN_ADDRESS = INestGovernance(nestGovernanceAddress).getNestTokenAddress(); } /// @dev Migrate funds from current contract to NestLedger diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol new file mode 100644 index 0000000..babfe5b --- /dev/null +++ b/contracts/NestBatchMining.sol @@ -0,0 +1,1484 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.6; + +import "./lib/IERC20.sol"; +import "./lib/TransferHelper.sol"; + +import "./interface/INestBatchMining.sol"; +import "./interface/INestLedger.sol"; +import "./interface/INToken.sol"; + +import "./NestBase.sol"; + +/// @dev This contract implemented the mining logic of nest +contract NestBatchMining is NestBase, INestBatchMining { + + /// @dev To support open-zeppelin/upgrades + /// @param nestGovernanceAddress INestGovernance implementation contract address + function initialize(address nestGovernanceAddress) public override { + super.initialize(nestGovernanceAddress); + // Placeholder in _accounts, the index of a real account must greater than 0 + _accounts.push(); + } + + /// @dev Definitions for the price sheet, include the full information. + /// (use 256-bits, a storage unit in ethereum evm) + struct PriceSheet { + + // Index of miner account in _accounts. for this way, mapping an address(which need 160-bits) to a 32-bits + // integer, support 4 billion accounts + uint32 miner; + + // The block number of this price sheet packaged + uint32 height; + + // The remain number of this price sheet + uint32 remainNum; + + // The eth number which miner will got + uint32 ethNumBal; + + // The eth number which equivalent to token's value which miner will got + uint32 tokenNumBal; + + // The pledged number of nest in this sheet. (Unit: 1000nest) + uint24 nestNum1k; + + // The level of this sheet. 0 expresses initial price sheet, a value greater than 0 expresses bite price sheet + uint8 level; + + // Post fee shares, if there are many sheets in one block, this value is used to divide up mining value + uint8 shares; + + // Represent price as this way, may lose precision, the error less than 1/10^14 + // price = priceFraction * 16 ^ priceExponent + uint56 priceFloat; + } + + /// @dev Definitions for the price information + struct PriceInfo { + + // Record the index of price sheet, for update price information from price sheet next time. + uint32 index; + + // The block number of this price + uint32 height; + + // The remain number of this price sheet + uint32 remainNum; + + // Price, represent as float + // Represent price as this way, may lose precision, the error less than 1/10^14 + uint56 priceFloat; + + // Avg Price, represent as float + // Represent price as this way, may lose precision, the error less than 1/10^14 + uint56 avgFloat; + + // Square of price volatility, need divide by 2^48 + uint48 sigmaSQ; + } + + // 报价对 + struct PricePair { + address target; + PriceInfo price; + PriceSheet[] sheets; + } + + /// @dev Price channel + struct PriceChannel { + + // The information of mining fee + // Low 128-bits represent fee per post + // High 128-bits represent the current counter of no fee sheets (including settled) + uint feeInfo; + + // 计价代币地址, 0表示eth + address token0; + // 计价代币单位 + uint96 unit; + + // 每个区块的标准出矿量 + uint96 rewardPerBlock; + + // 出矿代币地址 + address reward; + // 矿币总量 + uint96 vault; + + // 管理地址 + address governance; + // 创世区块 + uint32 genesisBlock; + // Post fee(0.0001eth,DIMI_ETHER). 1000 + uint16 postFeeUnit; + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + uint16 singleFee; + // 衰减系数,万分制。8000 + uint16 reductionRate; + uint16 count; + + PricePair[255] pairs; + } + + /// @dev Structure is used to represent a storage location. Storage variable can be used to avoid indexing + /// from mapping many times + struct UINT { + uint value; + } + + /// @dev Account information + struct Account { + + // Address of account + address addr; + + // Balances of mining account + // tokenAddress=>balance + mapping(address=>UINT) balances; + } + + // Configuration + Config _config; + + // Registered account information + Account[] _accounts; + + // Mapping from address to index of account. address=>accountIndex + mapping(address=>uint) _accountMapping; + + // 报价通道映射,通过此映射避免重复添加报价通道 + //mapping(uint=>uint) _channelMapping; + + // 报价通道 + PriceChannel[] _channels; + + // Unit of post fee. 0.0001 ether + uint constant DIMI_ETHER = 0.0001 ether; + + // Ethereum average block time interval, 14 seconds + uint constant ETHEREUM_BLOCK_TIMESPAN = 3; + + /* ========== Governance ========== */ + + /// @dev Modify configuration + /// @param config Configuration object + function setConfig(Config calldata config) external override onlyGovernance { + _config = config; + } + + /// @dev Get configuration + /// @return Configuration object + function getConfig() external view override returns (Config memory) { + return _config; + } + + /// @dev 开通报价通道 + /// @param config 报价通道配置 + function open(ChannelConfig calldata config) external override { + + address token0 = config.token0; + address reward = config.reward; + + emit Open(_channels.length, token0, config.unit, reward); + PriceChannel storage channel = _channels.push(); + channel.token0 = token0; + channel.unit = config.unit; + channel.rewardPerBlock = config.rewardPerBlock; + channel.reward = reward; + // 管理地址 + channel.governance = msg.sender; + // 创世区块 + channel.genesisBlock = uint32(block.number); + // Post fee(0.0001eth,DIMI_ETHER). 1000 + channel.postFeeUnit = config.postFeeUnit; + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + channel.singleFee = config.singleFee; + // 衰减系数,万分制。8000 + channel.reductionRate = config.reductionRate; + channel.count = uint16(config.tokens.length); + for (uint i = 0; i < config.tokens.length; ++i) { + require(token0 != config.tokens[i], "NOM:token can't equal token1"); + channel.pairs[i].target = config.tokens[i]; + } + } + + /// @dev 向报价通道注入矿币 + /// @param channelId 报价通道 + /// @param vault 注入矿币数量 + function increase(uint channelId, uint96 vault) external payable override { + PriceChannel storage channel = _channels[channelId]; + address reward = channel.reward; + if (reward == address(0)) { + require(msg.value == vault, "NOM:vault error"); + } else { + TransferHelper.safeTransferFrom(reward, msg.sender, address(this), vault); + } + channel.vault += vault; + } + + /// @dev 从报价通道取出矿币 + /// @param channelId 报价通道 + /// @param vault 取出矿币数量 + function decrease(uint channelId, uint96 vault) external override { + PriceChannel storage channel = _channels[channelId]; + require(channel.governance == msg.sender, "NOM:not governance"); + address reward = channel.reward; + if (reward == address(0)) { + payable(msg.sender).transfer(vault); + } else { + TransferHelper.safeTransfer(reward, msg.sender, vault); + } + channel.vault -= vault; + } + + // /// @dev 向报价通道注入NToken矿币 + // /// @param channelId 报价通道 + // /// @param vault 注入矿币数量 + // function increaseNToken(uint channelId, uint96 vault) external onlyGovernance { + // PriceChannel storage channel = _channels[channelId]; + // INToken(channel.reward).increaseTotal(vault); + // channel.vault += vault; + // } + + /// @dev 修改治理权限地址 + /// @param channelId 报价通道 + /// @param newGovernance 新治理权限地址 + function changeGovernance(uint channelId, address newGovernance) external { + PriceChannel storage channel = _channels[channelId]; + require(channel.governance == msg.sender, "NOM:not governance"); + channel.governance = newGovernance; + } + + /// @dev 获取报价通道信息 + /// @param channelId 报价通道 + /// @return 报价通道信息 + function getChannelInfo(uint channelId) external view override returns (PriceChannelView memory) { + PriceChannel storage channel = _channels[channelId]; + + uint count = uint(channel.count); + address[] memory tokens = new address[](count); + for (uint i = 0; i < count; ++i) { + tokens[i] = channel.pairs[i].target; + } + + return PriceChannelView ( + channelId, + + //channel.sheets.length, + + // The information of mining fee + // Low 128-bits represent fee per post + // High 128-bits represent the current counter of no fee sheets (including settled) + channel.feeInfo, + + // 计价代币地址, 0表示eth + channel.token0, + // 计价代币单位 + channel.unit, + + //// 报价代币地址,0表示eth + //channel.token1, + // 每个区块的标准出矿量 + channel.rewardPerBlock, + + // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 + // 出矿代币地址 + channel.reward, + // 矿币总量 + channel.vault, + + // 管理地址 + channel.governance, + // 创世区块 + channel.genesisBlock, + // Post fee(0.0001eth,DIMI_ETHER). 1000 + channel.postFeeUnit, + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + channel.singleFee, + // 衰减系数,万分制。8000 + channel.reductionRate, + + tokens + ); + } + + /* ========== Mining ========== */ + + /// @dev 报价 + /// @param channelId 报价通道id + /// @param scale 报价规模(token0,单位unit) + /// @param equivalent 与单位token0等价的token1数量 + function post(uint channelId, uint scale, uint[] calldata equivalent) external payable override { + + // 0. 加载配置 + Config memory config = _config; + + // 1. Check arguments + require(scale == 1, "NOM:!scale"); + + // 2. Check price channel + // 3. Load token channel and sheets + PriceChannel storage channel = _channels[channelId]; + PricePair[255] storage pairs = channel.pairs; + //PriceSheet[] storage sheets = channel.sheets; + + // 4. Freeze assets + uint accountIndex = _addressIndex(msg.sender); + // Freeze token and nest + // Because of the use of floating-point representation(fraction * 16 ^ exponent), it may bring some precision + // loss After assets are frozen according to tokenAmountPerEth * ethNum, the part with poor accuracy may be + // lost when the assets are returned, It should be frozen according to decodeFloat(fraction, exponent) * ethNum + // However, considering that the loss is less than 1 / 10 ^ 14, the loss here is ignored, and the part of + // precision loss can be transferred out as system income in the future + mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + + uint count = uint(channel.count); + uint fee = msg.value; + // 冻结token0 + fee = _freeze(balances, channel.token0, uint(channel.unit) * scale * count, fee); + + // 冻结token1 + //fee = _freeze(balances, channel.token1, scale * equivalent, fee); + while (count > 0) { + //PricePair storage pair = pairs[--count]; + fee = _freeze(balances, pairs[--count].target, scale * equivalent[count], fee); + + PriceSheet[] storage sheets = pairs[count].sheets; + // Calculate the price + // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price + // is placed before the sheet is added, which can reduce unnecessary traversal + _stat(config, pairs[count], sheets); + + // 6. Create token price sheet + emit Post(channelId, msg.sender, sheets.length, scale, equivalent[count]); + _createPriceSheet(sheets, accountIndex, uint32(scale), uint(config.pledgeNest), 1, equivalent[count]); + } + + // 冻结nest + fee = _freeze(balances, NEST_TOKEN_ADDRESS, uint(config.pledgeNest) * 1000 ether * count, fee); + + // 5. Deposit fee + // 只有配置了报价佣金时才检查fee + uint postFeeUnit = uint(channel.postFeeUnit); + if (postFeeUnit > 0) { + require(fee >= postFeeUnit * DIMI_ETHER + tx.gasprice * 400000, "NM:!fee"); + } + if (fee > 0) { + channel.feeInfo += fee; + } + } + + /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet + /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param index The position of the sheet in priceSheetList[token] + /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth + /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth + function takeToken0(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { + + // Config memory config = _config; + + // // 1. Check arguments + // require(takeNum > 0, "NM:!takeNum"); + // require(newEquivalent > 0, "NM:!price"); + + // // 2. Load price sheet + // PriceChannel storage channel = _channels[channelId]; + // PricePair storage pair = channel.pairs[pairIndex]; + // PriceSheet[] storage sheets = pair.sheets; + // PriceSheet memory sheet = sheets[index]; + + // // 3. Check state + // require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); + // require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); + + // // 4. Deposit fee + // // 5. Calculate the number of eth, token and nest needed, and freeze them + // uint needEthNum; + // uint level = uint(sheet.level); + + // // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled + // if (level < uint(config.maxBiteNestedLevel)) { + // // Double scale sheet + // needEthNum = takeNum << 1; + // ++level; + // } + // // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not + // else { + // // Single scale sheet + // needEthNum = takeNum; + // // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 + // // or more, there is no logical dependence on the specific value of the contract, and the count will + // // not increase after it is accumulated to 255 + // if (level < 255) ++level; + // } + + // // Number of nest to be pledged + // //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); + // // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum + // uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); + // // Freeze nest and token + // uint accountIndex = _addressIndex(msg.sender); + // { + // // 冻结资产:token0, token1, nest + // mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + // uint fee = msg.value; + + // // 冻结token0 + // fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); + // // 冻结token1 + // fee = _freeze( + // balances, + // pair.target, + // needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, + // fee + // ); + // // 冻结nest + // fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); + // require(fee == 0, "NOM:!fee"); + // } + + // // 6. Update the bitten sheet + // sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); + // sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); + // sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); + // sheets[index] = sheet; + + // // 7. Calculate the price + // // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price + // // is placed before the sheet is added, which can reduce unnecessary traversal + // _stat(config, pair, sheets); + + // // 8. Create price sheet + // //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); + // _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); + } + + /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet + /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) + /// @param channelId The address of token(ntoken) + /// @param pairIndex 报价对编号 + /// @param index The position of the sheet in priceSheetList[token] + /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth + /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth + function takeToken1(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { + + // Config memory config = _config; + + // // 1. Check arguments + // require(takeNum > 0, "NM:!takeNum"); + // require(newEquivalent > 0, "NM:!price"); + + // // 2. Load price sheet + // PriceChannel storage channel = _channels[channelId]; + // PricePair storage pair = channel.pairs[pairIndex]; + // PriceSheet[] storage sheets = pair.sheets; + // PriceSheet memory sheet = sheets[index]; + + // // 3. Check state + // require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); + // require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); + + // // 4. Deposit fee + + // // 5. Calculate the number of eth, token and nest needed, and freeze them + // uint needEthNum; + // uint level = uint(sheet.level); + + // // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled + // if (level < uint(config.maxBiteNestedLevel)) { + // // Double scale sheet + // needEthNum = takeNum << 1; + // ++level; + // } + // // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not + // else { + // // Single scale sheet + // needEthNum = takeNum; + // // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 + // // or more, there is no logical dependence on the specific value of the contract, and the count will + // // not increase after it is accumulated to 255 + // if (level < 255) ++level; + // } + + // // Number of nest to be pledged + // //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); + // // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum + // uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); + // // Freeze nest and token + // uint accountIndex = _addressIndex(msg.sender); + // { + // // 冻结资产:token0, token1, nest + // mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + + // uint fee = msg.value; + // // 冻结token0 + // fee = _freeze(balances, channel.token0, (needEthNum + takeNum) * uint(channel.unit), fee); + // // 冻结token1 + // uint backTokenValue = _decodeFloat(sheet.priceFloat) * takeNum; + // if (needEthNum * newEquivalent > backTokenValue) { + // fee = _freeze(balances, pair.target, needEthNum * newEquivalent - backTokenValue, fee); + // } else { + // _unfreeze(balances, pair.target, backTokenValue - needEthNum * newEquivalent, msg.sender); + // } + // fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); + // require(fee == 0, "NOM:!fee"); + // } + + // // 6. Update the bitten sheet + // sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); + // sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); + // sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); + // sheets[index] = sheet; + + // // 7. Calculate the price + // // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price + // // is placed before the sheet is added, which can reduce unnecessary traversal + // _stat(config, pair, sheets); + + // // 8. Create price sheet + // //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); + // _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); + } + + /// @dev List sheets by page + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param offset Skip previous (offset) records + /// @param count Return (count) records + /// @param order Order. 0 reverse order, non-0 positive order + /// @return List of price sheets + function list( + uint channelId, + uint pairIndex, + uint offset, + uint count, + uint order + ) external view override noContract returns (PriceSheetView[] memory) { + + PriceSheet[] storage sheets = _channels[channelId].pairs[pairIndex].sheets; + PriceSheetView[] memory result = new PriceSheetView[](count); + uint length = sheets.length; + uint i = 0; + + // Reverse order + if (order == 0) { + + uint index = length - offset; + uint end = index > count ? index - count : 0; + while (index > end) { + --index; + result[i++] = _toPriceSheetView(sheets[index], index); + } + } + // Positive order + else { + + uint index = offset; + uint end = index + count; + if (end > length) { + end = length; + } + while (index < end) { + result[i++] = _toPriceSheetView(sheets[index], index); + ++index; + } + } + return result; + } + + /// @notice Close a batch of price sheets passed VERIFICATION-PHASE + /// @dev Empty sheets but in VERIFICATION-PHASE aren't allowed + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param indices A list of indices of sheets w.r.t. `token` + function close(uint channelId, uint pairIndex, uint[] memory indices) external override { + + PriceChannel storage channel = _channels[channelId]; + PricePair storage pair = channel.pairs[pairIndex]; + // Call _closeList() method to close price sheets + ( + uint accountIndex, + Tuple memory total + ) = _closeList(_config, channel, pair, indices); + + mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + + // 解冻token0 + _unfreeze(balances, channel.token0, uint(total.ethNum) * uint(channel.unit), accountIndex); + // 解冻token1 + _unfreeze(balances, pair.target, uint(total.tokenValue), accountIndex); + // 解冻nest + _unfreeze(balances, NEST_TOKEN_ADDRESS, uint(total.nestValue), accountIndex); + + uint vault = uint(channel.vault); + uint ntokenValue = uint(total.ntokenValue); + if (ntokenValue > vault) { + ntokenValue = vault; + } + // 记录每个通道矿币的数量,防止开通者不打币,直接用资金池内的资金 + channel.vault = uint96(vault - ntokenValue); + // 奖励矿币 + _unfreeze(balances, channel.reward, ntokenValue, accountIndex); + } + + /// @dev The function updates the statistics of price sheets + /// It calculates from priceInfo to the newest that is effective. + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + function stat(uint channelId, uint pairIndex) external override { + PricePair storage pair = _channels[channelId].pairs[pairIndex]; + _stat(_config, pair, pair.sheets); + } + + /// @dev View the number of assets specified by the user + /// @param tokenAddress Destination token address + /// @param addr Destination address + /// @return Number of assets + function balanceOf(address tokenAddress, address addr) external view override returns (uint) { + return _accounts[_accountMapping[addr]].balances[tokenAddress].value; + } + + /// @dev Withdraw assets + /// @param tokenAddress Destination token address + /// @param value The value to withdraw + function withdraw(address tokenAddress, uint value) external override { + + // The user's locked nest and the mining pool's nest are stored together. When the nest is mined over, + // the problem of taking the locked nest as the ore drawing will appear + // As it will take a long time for nest to finish mining, this problem will not be considered for the time being + UINT storage balance = _accounts[_accountMapping[msg.sender]].balances[tokenAddress]; + //uint balanceValue = balance.value; + //require(balanceValue >= value, "NM:!balance"); + balance.value -= value; + + TransferHelper.safeTransfer(tokenAddress, msg.sender, value); + } + + /// @dev Estimated mining amount + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return Estimated mining amount + function estimate(uint channelId, uint pairIndex) external view override returns (uint) { + + PriceChannel storage channel = _channels[channelId]; + PriceSheet[] storage sheets = channel.pairs[pairIndex].sheets; + uint index = sheets.length; + uint blocks = 10; + while (index > 0) { + + PriceSheet memory sheet = sheets[--index]; + if (uint(sheet.shares) > 0) { + blocks = block.number - uint(sheet.height); + break; + } + } + + return + blocks + * uint(channel.rewardPerBlock) + * _reduction(block.number - uint(channel.genesisBlock), uint(channel.reductionRate)) + / 400; + } + + /// @dev Query the quantity of the target quotation + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param index The index of the sheet + /// @return minedBlocks Mined block period from previous block + /// @return totalShares Total shares of sheets in the block + function getMinedBlocks( + uint channelId, + uint pairIndex, + uint index + ) external view override returns (uint minedBlocks, uint totalShares) { + + PriceSheet[] storage sheets = _channels[channelId].pairs[pairIndex].sheets; + PriceSheet memory sheet = sheets[index]; + + // The bite sheet or ntoken sheet doesn't mining + if (uint(sheet.shares) == 0) { + return (0, 0); + } + + return _calcMinedBlocks(sheets, index, sheet); + } + + /// @dev The function returns eth rewards of specified ntoken + /// @param channelId 报价通道编号 + function totalETHRewards(uint channelId) external view override returns (uint) { + return _channels[channelId].feeInfo; + } + + /// @dev Pay + /// @param channelId 报价通道编号 + /// @param to Address to receive + /// @param value Amount to receive + function pay(uint channelId, address to, uint value) external override { + + PriceChannel storage channel = _channels[channelId]; + require(channel.governance == msg.sender, "NOM:!governance"); + channel.feeInfo -= value; + // pay + payable(to).transfer(value); + } + + /// @dev 向DAO捐赠 + /// @param channelId 报价通道 + /// @param value Amount to receive + function donate(uint channelId, uint value) external override { + + PriceChannel storage channel = _channels[channelId]; + require(channel.governance == msg.sender, "NOM:!governance"); + channel.feeInfo -= value; + INestLedger(INestMapping(_governance).getNestLedgerAddress()).addETHReward { value: value } (channelId); + } + + /// @dev Gets the address corresponding to the given index number + /// @param index The index number of the specified address + /// @return The address corresponding to the given index number + function indexAddress(uint index) public view returns (address) { + return _accounts[index].addr; + } + + /// @dev Gets the registration index number of the specified address + /// @param addr Destination address + /// @return 0 means nonexistent, non-0 means index number + function getAccountIndex(address addr) external view returns (uint) { + return _accountMapping[addr]; + } + + /// @dev Get the length of registered account array + /// @return The length of registered account array + function getAccountCount() external view returns (uint) { + return _accounts.length; + } + + // Convert PriceSheet to PriceSheetView + function _toPriceSheetView(PriceSheet memory sheet, uint index) private view returns (PriceSheetView memory) { + + return PriceSheetView( + // Index number + uint32(index), + // Miner address + indexAddress(sheet.miner), + // The block number of this price sheet packaged + sheet.height, + // The remain number of this price sheet + sheet.remainNum, + // The eth number which miner will got + sheet.ethNumBal, + // The eth number which equivalent to token's value which miner will got + sheet.tokenNumBal, + // The pledged number of nest in this sheet. (Unit: 1000nest) + sheet.nestNum1k, + // The level of this sheet. 0 expresses initial price sheet, a value greater than 0 expresses + // bite price sheet + sheet.level, + // Post fee shares + sheet.shares, + // Price + uint152(_decodeFloat(sheet.priceFloat)) + ); + } + + // Create price sheet + function _createPriceSheet( + PriceSheet[] storage sheets, + uint accountIndex, + uint32 ethNum, + uint nestNum1k, + uint level_shares, + uint equivalent + ) private { + + sheets.push(PriceSheet( + uint32(accountIndex), // uint32 miner; + uint32(block.number), // uint32 height; + ethNum, // uint32 remainNum; + ethNum, // uint32 ethNumBal; + ethNum, // uint32 tokenNumBal; + uint24(nestNum1k), // uint32 nestNum1k; + uint8(level_shares >> 8), // uint8 level; + uint8(level_shares & 0xFF), + _encodeFloat(equivalent) + )); + } + + // Calculate price, average price and volatility + function _stat(Config memory config, PricePair storage pair, PriceSheet[] storage sheets) private { + + // Load token price information + PriceInfo memory p0 = pair.price; + + // Length of sheets + uint length = sheets.length; + // The index of the sheet to be processed in the sheet array + uint index = uint(p0.index); + // The latest block number for which the price has been calculated + uint prev = uint(p0.height); + // It's not necessary to load the price information in p0 + // Eth count variable used to calculate price + uint totalEthNum = 0; + // Token count variable for price calculation + uint totalTokenValue = 0; + // Block number of current sheet + uint height = 0; + + // Traverse the sheets to find the effective price + //uint effectBlock = block.number - uint(config.priceEffectSpan); + PriceSheet memory sheet; + for (; ; ++index) { + + // Gas attack analysis, each post transaction, calculated according to post, needs to write + // at least one sheet and freeze two kinds of assets, which needs to consume at least 30000 gas, + // In addition to the basic cost of the transaction, at least 50000 gas is required. + // In addition, there are other reading and calculation operations. The gas consumed by each + // transaction is impossible less than 70000 gas, The attacker can accumulate up to 20 blocks + // of sheets to be generated. To ensure that the calculation can be completed in one block, + // it is necessary to ensure that the consumption of each price does not exceed 70000 / 20 = 3500 gas, + // According to the current logic, each calculation of a price needs to read a storage unit (800) + // and calculate the consumption, which can not reach the dangerous value of 3500, so the gas attack + // is not considered + + // Traverse the sheets that has reached the effective interval from the current position + bool flag = index >= length + || (height = uint((sheet = sheets[index]).height)) + uint(config.priceEffectSpan) >= block.number; + + // Not the same block (or flag is false), calculate the price and update it + if (flag || prev != height) { + + // totalEthNum > 0 Can calculate the price + if (totalEthNum > 0) { + + // Calculate average price and Volatility + // Calculation method of volatility of follow-up price + uint tmp = _decodeFloat(p0.priceFloat); + // New price + uint price = totalTokenValue / totalEthNum; + // Update price + p0.remainNum = uint32(totalEthNum); + p0.priceFloat = _encodeFloat(price); + // Clear cumulative values + totalEthNum = 0; + totalTokenValue = 0; + + if (tmp > 0) { + // Calculate average price + // avgPrice[i + 1] = avgPrice[i] * 90% + price[i] * 10% + p0.avgFloat = _encodeFloat((_decodeFloat(p0.avgFloat) * 9 + price) / 10); + + // When the accuracy of the token is very high or the value of the token relative to + // eth is very low, the price may be very large, and there may be overflow problem, + // it is not considered for the moment + tmp = (price << 48) / tmp; + if (tmp > 0x1000000000000) { + tmp = tmp - 0x1000000000000; + } else { + tmp = 0x1000000000000 - tmp; + } + + // earn = price[i] / price[i - 1] - 1; + // seconds = time[i] - time[i - 1]; + // sigmaSQ[i + 1] = sigmaSQ[i] * 90% + (earn ^ 2 / seconds) * 10% + tmp = ( + uint(p0.sigmaSQ) * 9 + + // It is inevitable that prev greater than p0.height + ((tmp * tmp / ETHEREUM_BLOCK_TIMESPAN / (prev - uint(p0.height))) >> 48) + ) / 10; + + // The current implementation assumes that the volatility cannot exceed 1, and + // corresponding to this, when the calculated value exceeds 1, expressed as 0xFFFFFFFFFFFF + if (tmp > 0xFFFFFFFFFFFF) { + tmp = 0xFFFFFFFFFFFF; + } + p0.sigmaSQ = uint48(tmp); + } + // The calculation methods of average price and volatility are different for first price + else { + // The average price is equal to the price + //p0.avgTokenAmount = uint64(price); + p0.avgFloat = p0.priceFloat; + + // The volatility is 0 + p0.sigmaSQ = uint48(0); + } + + // Update price block number + p0.height = uint32(prev); + } + + // Move to new block number + prev = height; + } + + if (flag) { + break; + } + + // Cumulative price information + totalEthNum += uint(sheet.remainNum); + totalTokenValue += _decodeFloat(sheet.priceFloat) * uint(sheet.remainNum); + } + + // Update price information + if (index > uint(p0.index)) { + p0.index = uint32(index); + pair.price = p0; + } + } + + // This structure is for the _close() method to return multiple values + struct Tuple { + uint tokenValue; + uint64 ethNum; + uint96 nestValue; + uint96 ntokenValue; + } + + // Close price sheet + function _close( + Config memory config, + PriceSheet[] storage sheets, + uint index, + uint rewardPerBlock, + uint genesisBlock, + uint reductionRate + ) private returns (uint accountIndex, Tuple memory value) { + + PriceSheet memory sheet = sheets[index]; + uint height = uint(sheet.height); + + // Check the status of the price sheet to see if it has reached the effective block interval or has been finished + if ((accountIndex = uint(sheet.miner)) > 0 && (height + uint(config.priceEffectSpan) < block.number)) { + + // TMP: tmp is a polysemous name, here means sheet.shares + uint tmp = uint(sheet.shares); + // Mining logic + // The price sheet which shares is zero doesn't mining + if (tmp > 0) { + + // Currently, mined represents the number of blocks has mined + (uint mined, uint totalShares) = _calcMinedBlocks(sheets, index, sheet); + // 当开通者指定的rewardPerBlock非常大时,计算出矿可能会被截断,导致实际能够得到的出矿大大减少 + // 这种情况是不合理的,需要由开通者负责 + value.ntokenValue = uint96( + mined + * tmp + * _reduction(height - genesisBlock, reductionRate) + * rewardPerBlock + / totalShares / 400 + ); + } + + value.nestValue = uint96(uint(sheet.nestNum1k) * 1000 ether); + value.ethNum = uint64(sheet.ethNumBal); + value.tokenValue = _decodeFloat(sheet.priceFloat) * uint(sheet.tokenNumBal); + + // Set sheet.miner to 0, express the sheet is closed + sheet.miner = uint32(0); + sheet.ethNumBal = uint32(0); + sheet.tokenNumBal = uint32(0); + sheets[index] = sheet; + } + } + + // Batch close sheets + function _closeList( + Config memory config, + PriceChannel storage channel, + PricePair storage pair, + uint[] memory indices + ) private returns (uint accountIndex, Tuple memory total) { + + PriceSheet[] storage sheets = pair.sheets; + accountIndex = 0; + + uint rewardPerBlock = uint(channel.rewardPerBlock); + uint genesisBlock = uint(channel.genesisBlock); + uint reductionRate = uint(channel.reductionRate); + + // 1. Traverse sheets + for (uint i = indices.length; i > 0;) { + + // Because too many variables need to be returned, too many variables will be defined, + // so the structure of tuple is defined + (uint minerIndex, Tuple memory value) = _close( + config, + sheets, + indices[--i], + rewardPerBlock, + genesisBlock, + reductionRate + ); + // Batch closing quotation can only close sheet of the same user + if (accountIndex == 0) { + // accountIndex == 0 means the first sheet, and the number of this sheet is taken + accountIndex = minerIndex; + } else { + // accountIndex != 0 means that it is a follow-up sheet, and the miner number must be + // consistent with the previous record + require(accountIndex == minerIndex, "NM:!miner"); + } + + total.ntokenValue += value.ntokenValue; + total.nestValue += value.nestValue; + total.ethNum += value.ethNum; + total.tokenValue += value.tokenValue; + } + + _stat(config, pair, sheets); + } + + // Calculation number of blocks which mined + function _calcMinedBlocks( + PriceSheet[] storage sheets, + uint index, + PriceSheet memory sheet + ) private view returns (uint minedBlocks, uint totalShares) { + + uint length = sheets.length; + uint height = uint(sheet.height); + totalShares = uint(sheet.shares); + + // Backward looking for sheets in the same block + for (uint i = index; ++i < length && uint(sheets[i].height) == height;) { + + // Multiple sheets in the same block is a small probability event at present, so it can be ignored + // to read more than once, if there are always multiple sheets in the same block, it means that the + // sheets are very intensive, and the gas consumed here does not have a great impact + totalShares += uint(sheets[i].shares); + } + + //i = index; + // Find sheets in the same block forward + uint prev = height; + while (index > 0 && uint(prev = sheets[--index].height) == height) { + + // Multiple sheets in the same block is a small probability event at present, so it can be ignored + // to read more than once, if there are always multiple sheets in the same block, it means that the + // sheets are very intensive, and the gas consumed here does not have a great impact + totalShares += uint(sheets[index].shares); + } + + if (index > 0 || height > prev) { + minedBlocks = height - prev; + } else { + minedBlocks = 10; + } + } + + /// @dev freeze token + /// @param balances Balances ledger + /// @param tokenAddress Destination token address + /// @param tokenValue token amount + /// @param value 剩余的eth数量 + function _freeze( + mapping(address=>UINT) storage balances, + address tokenAddress, + uint tokenValue, + uint value + ) private returns (uint) { + if (tokenAddress == address(0)) { + return value - tokenValue; + } else { + // Unfreeze nest + UINT storage balance = balances[tokenAddress]; + uint balanceValue = balance.value; + if (balanceValue < tokenValue) { + balance.value = 0; + TransferHelper.safeTransferFrom(tokenAddress, msg.sender, address(this), tokenValue - balanceValue); + } else { + balance.value = balanceValue - tokenValue; + } + return value; + } + } + + function _unfreeze( + mapping(address=>UINT) storage balances, + address tokenAddress, + uint tokenValue, + uint accountIndex + ) private { + if (tokenValue > 0) { + if (tokenAddress == address(0)) { + payable(indexAddress(accountIndex)).transfer(tokenValue); + } else { + balances[tokenAddress].value += tokenValue; + } + } + } + + function _unfreeze( + mapping(address=>UINT) storage balances, + address tokenAddress, + uint tokenValue, + address owner + ) private { + if (tokenValue > 0) { + if (tokenAddress == address(0)) { + payable(owner).transfer(tokenValue); + } else { + balances[tokenAddress].value += tokenValue; + } + } + } + + // /// @dev Gets the address corresponding to the given index number + // /// @param index The index number of the specified address + // /// @return The address corresponding to the given index number + // function _indexAddress(uint index) public view returns (address) { + // return _accounts[index].addr; + // } + + /// @dev Gets the index number of the specified address. If it does not exist, register + /// @param addr Destination address + /// @return The index number of the specified address + function _addressIndex(address addr) private returns (uint) { + + uint index = _accountMapping[addr]; + if (index == 0) { + // If it exceeds the maximum number that 32 bits can store, you can't continue to register a new account. + // If you need to support a new account, you need to update the contract + require((_accountMapping[addr] = index = _accounts.length) < 0x100000000, "NM:!accounts"); + _accounts.push().addr = addr; + } + + return index; + } + + // Nest ore drawing attenuation interval. 2400000 blocks, about one year + uint constant NEST_REDUCTION_SPAN = 10000000; + // The decay limit of nest ore drawing becomes stable after exceeding this interval. + // 24 million blocks, about 10 years + uint constant NEST_REDUCTION_LIMIT = 100000000; //NEST_REDUCTION_SPAN * 10; + // Attenuation gradient array, each attenuation step value occupies 16 bits. The attenuation value is an integer + uint constant NEST_REDUCTION_STEPS = 0x280035004300530068008300A300CC010001400190; + // 0 + // | (uint(400 / uint(1)) << (16 * 0)) + // | (uint(400 * 8 / uint(10)) << (16 * 1)) + // | (uint(400 * 8 * 8 / uint(10 * 10)) << (16 * 2)) + // | (uint(400 * 8 * 8 * 8 / uint(10 * 10 * 10)) << (16 * 3)) + // | (uint(400 * 8 * 8 * 8 * 8 / uint(10 * 10 * 10 * 10)) << (16 * 4)) + // | (uint(400 * 8 * 8 * 8 * 8 * 8 / uint(10 * 10 * 10 * 10 * 10)) << (16 * 5)) + // | (uint(400 * 8 * 8 * 8 * 8 * 8 * 8 / uint(10 * 10 * 10 * 10 * 10 * 10)) << (16 * 6)) + // | (uint(400 * 8 * 8 * 8 * 8 * 8 * 8 * 8 / uint(10 * 10 * 10 * 10 * 10 * 10 * 10)) << (16 * 7)) + // | (uint(400 * 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 / uint(10 * 10 * 10 * 10 * 10 * 10 * 10 * 10)) << (16 * 8)) + // | (uint(400 * 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 / uint(10 * 10 * 10 * 10 * 10 * 10 * 10 * 10 * 10)) << (16 * 9)) + // //| (uint(400 * 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 / uint(10 * 10 * 10 * 10 * 10 * 10 * 10 * 10 * 10 * 10)) << (16 * 10)); + // | (uint(40) << (16 * 10)); + + // // Calculation of attenuation gradient + // function _reduction(uint delta) private pure returns (uint) { + + // if (delta < NEST_REDUCTION_LIMIT) { + // return (NEST_REDUCTION_STEPS >> ((delta / NEST_REDUCTION_SPAN) << 4)) & 0xFFFF; + // } + // return (NEST_REDUCTION_STEPS >> 160) & 0xFFFF; + // } + + function _reduction(uint delta, uint reductionRate) private pure returns (uint) { + if (delta < NEST_REDUCTION_LIMIT) { + uint n = delta / NEST_REDUCTION_SPAN; + return 400 * reductionRate ** n / 10000 ** n; + } + return 400 * reductionRate ** 10 / 10000 ** 10; + } + + /* ========== Tools and methods ========== */ + + /// @dev Encode the uint value as a floating-point representation in the form of fraction * 16 ^ exponent + /// @param value Destination uint value + /// @return float format + function _encodeFloat(uint value) private pure returns (uint56) { + + uint exponent = 0; + while (value > 0x3FFFFFFFFFFFF) { + value >>= 4; + ++exponent; + } + return uint56((value << 6) | exponent); + } + + /// @dev Decode the floating-point representation of fraction * 16 ^ exponent to uint + /// @param floatValue fraction value + /// @return decode format + function _decodeFloat(uint56 floatValue) private pure returns (uint) { + return (uint(floatValue) >> 6) << ((uint(floatValue) & 0x3F) << 2); + } + + /* ========== 价格查询 ========== */ + + // /// @dev Get the latest trigger price + // /// @param channel 报价通道 + // /// @return blockNumber The block number of price + // /// @return price The token price. (1eth equivalent to (price) token) + // function _triggeredPrice(PriceChannel storage channel) internal view returns (uint blockNumber, uint price) { + + // PriceInfo memory priceInfo = channel.price; + + // if (uint(priceInfo.remainNum) > 0) { + // return (uint(priceInfo.height) + uint(_config.priceEffectSpan), _decodeFloat(priceInfo.priceFloat)); + // } + + // return (0, 0); + // } + + // /// @dev Get the full information of latest trigger price + // /// @param channel 报价通道 + // /// @return blockNumber The block number of price + // /// @return price The token price. (1eth equivalent to (price) token) + // /// @return avgPrice Average price + // /// @return sigmaSQ The square of the volatility (18 decimal places). The current implementation assumes that + // /// the volatility cannot exceed 1. Correspondingly, when the return value is equal to 999999999999996447, + // /// it means that the volatility has exceeded the range that can be expressed + // function _triggeredPriceInfo(PriceChannel storage channel) internal view returns ( + // uint blockNumber, + // uint price, + // uint avgPrice, + // uint sigmaSQ + // ) { + + // PriceInfo memory priceInfo = channel.price; + + // if (uint(priceInfo.remainNum) > 0) { + // return ( + // uint(priceInfo.height) + uint(_config.priceEffectSpan), + // _decodeFloat(priceInfo.priceFloat), + // _decodeFloat(priceInfo.avgFloat), + // (uint(priceInfo.sigmaSQ) * 1 ether) >> 48 + // ); + // } + + // return (0, 0, 0, 0); + // } + + // /// @dev Find the price at block number + // /// @param channel 报价通道 + // /// @param height Destination block number + // /// @return blockNumber The block number of price + // /// @return price The token price. (1eth equivalent to (price) token) + // function _findPrice( + // PriceChannel storage channel, + // uint height + // ) internal view returns (uint blockNumber, uint price) { + + // PriceSheet[] storage sheets = channel.sheets; + // uint priceEffectSpan = uint(_config.priceEffectSpan); + + // uint length = sheets.length; + // uint index = 0; + // uint sheetHeight; + // height -= priceEffectSpan; + // { + // // If there is no sheet in this channel, length is 0, length - 1 will overflow, + // uint right = length - 1; + // uint left = 0; + // // Find the index use Binary Search + // while (left < right) { + + // index = (left + right) >> 1; + // sheetHeight = uint(sheets[index].height); + // if (height > sheetHeight) { + // left = ++index; + // } else if (height < sheetHeight) { + // // When index = 0, this statement will have an underflow exception, which usually + // // indicates that the effective block height passed during the call is lower than + // // the block height of the first quotation + // right = --index; + // } else { + // break; + // } + // } + // } + + // // Calculate price + // uint totalEthNum = 0; + // uint totalTokenValue = 0; + // uint h = 0; + // uint remainNum; + // PriceSheet memory sheet; + + // // Find sheets forward + // for (uint i = index; i < length;) { + + // sheet = sheets[i++]; + // sheetHeight = uint(sheet.height); + // if (height < sheetHeight) { + // break; + // } + // remainNum = uint(sheet.remainNum); + // if (remainNum > 0) { + // if (h == 0) { + // h = sheetHeight; + // } else if (h != sheetHeight) { + // break; + // } + // totalEthNum += remainNum; + // totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; + // } + // } + + // // Find sheets backward + // while (index > 0) { + + // sheet = sheets[--index]; + // remainNum = uint(sheet.remainNum); + // if (remainNum > 0) { + // sheetHeight = uint(sheet.height); + // if (h == 0) { + // h = sheetHeight; + // } else if (h != sheetHeight) { + // break; + // } + // totalEthNum += remainNum; + // totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; + // } + // } + + // if (totalEthNum > 0) { + // return (h + priceEffectSpan, totalTokenValue / totalEthNum); + // } + // return (0, 0); + // } + + // /// @dev Get the latest effective price + // /// @param channel 报价通道 + // /// @return blockNumber The block number of price + // /// @return price The token price. (1eth equivalent to (price) token) + // function _latestPrice(PriceChannel storage channel) internal view returns (uint blockNumber, uint price) { + + // PriceSheet[] storage sheets = channel.sheets; + // PriceSheet memory sheet; + + // uint priceEffectSpan = uint(_config.priceEffectSpan); + // //uint h = block.number - priceEffectSpan; + // uint index = sheets.length; + // uint totalEthNum = 0; + // uint totalTokenValue = 0; + // uint height = 0; + + // for (; ; ) { + + // bool flag = index == 0; + // if (flag || height != uint((sheet = sheets[--index]).height)) { + // if (totalEthNum > 0 && height + priceEffectSpan <= block.number) { + // return (height + priceEffectSpan, totalTokenValue / totalEthNum); + // } + // if (flag) { + // break; + // } + // totalEthNum = 0; + // totalTokenValue = 0; + // height = uint(sheet.height); + // } + + // uint remainNum = uint(sheet.remainNum); + // totalEthNum += remainNum; + // totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; + // } + + // return (0, 0); + // } + + // /// @dev Get the last (num) effective price + // /// @param channel 报价通道 + // /// @param count The number of prices that want to return + // /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + // function _lastPriceList(PriceChannel storage channel, uint count) internal view returns (uint[] memory) { + + // PriceSheet[] storage sheets = channel.sheets; + // PriceSheet memory sheet; + // uint[] memory array = new uint[](count <<= 1); + + // uint priceEffectSpan = uint(_config.priceEffectSpan); + // //uint h = block.number - priceEffectSpan; + // uint index = sheets.length; + // uint totalEthNum = 0; + // uint totalTokenValue = 0; + // uint height = 0; + + // for (uint i = 0; i < count;) { + + // bool flag = index == 0; + // if (flag || height != uint((sheet = sheets[--index]).height)) { + // if (totalEthNum > 0 && height + priceEffectSpan <= block.number) { + // array[i++] = height + priceEffectSpan; + // array[i++] = totalTokenValue / totalEthNum; + // } + // if (flag) { + // break; + // } + // totalEthNum = 0; + // totalTokenValue = 0; + // height = uint(sheet.height); + // } + + // uint remainNum = uint(sheet.remainNum); + // totalEthNum += remainNum; + // totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; + // } + + // return array; + // } + + // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // /// @param channel 报价通道 + // /// @return latestPriceBlockNumber The block number of latest price + // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function _latestPriceAndTriggeredPriceInfo(PriceChannel storage channel) internal view + // returns ( + // uint latestPriceBlockNumber, + // uint latestPriceValue, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ) { + // (latestPriceBlockNumber, latestPriceValue) = _latestPrice(channel); + // ( + // triggeredPriceBlockNumber, + // triggeredPriceValue, + // triggeredAvgPrice, + // triggeredSigmaSQ + // ) = _triggeredPriceInfo(channel); + // } + + // /// @dev Returns lastPriceList and triggered price info + // /// @param channel 报价通道 + // /// @param count The number of prices that want to return + // /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function _lastPriceListAndTriggeredPriceInfo(PriceChannel storage channel, uint count) internal view + // returns ( + // uint[] memory prices, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ) { + // prices = _lastPriceList(channel, count); + // ( + // triggeredPriceBlockNumber, + // triggeredPriceValue, + // triggeredAvgPrice, + // triggeredSigmaSQ + // ) = _triggeredPriceInfo(channel); + // } +} \ No newline at end of file diff --git a/contracts/interface/INestBatchMining.sol b/contracts/interface/INestBatchMining.sol new file mode 100644 index 0000000..88f4513 --- /dev/null +++ b/contracts/interface/INestBatchMining.sol @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.6; + +/// @dev This interface defines the mining methods for nest +interface INestBatchMining { + + /// @dev 开通报价通道 + /// @param channelId 报价通道编号 + /// @param token0 计价代币地址。0表示eth + /// @param unit token0的单位 + /// @param reward 挖矿代币地址。0表示不挖矿 + event Open(uint channelId, address token0, uint unit, address reward); + + /// @dev Post event + /// @param channelId 报价通道编号 + /// @param miner Address of miner + /// @param index Index of the price sheet + /// @param scale 报价规模 + event Post(uint channelId, address miner, uint index, uint scale, uint price); + + /* ========== Structures ========== */ + + /// @dev Nest mining configuration structure + struct Config { + + // // Eth number of each post. 30 + // // We can stop post and taking orders by set postEthUnit to 0 (closing and withdraw are not affected) + // uint32 postEthUnit; + + // // Post fee(0.0001eth,DIMI_ETHER). 1000 + // uint16 postFeeUnit; + + // // Proportion of miners digging(10000 based). 8000 + // uint16 minerNestReward; + + // // The proportion of token dug by miners is only valid for the token created in version 3.0 + // // (10000 based). 9500 + // uint16 minerNTokenReward; + + // // When the circulation of ntoken exceeds this threshold, post() is prohibited(Unit: 10000 ether). 500 + // uint32 doublePostThreshold; + + // // The limit of ntoken mined blocks. 100 + // uint16 ntokenMinedBlockLimit; + + // -- Public configuration + // The number of times the sheet assets have doubled. 4 + uint8 maxBiteNestedLevel; + + // Price effective block interval. 20 + uint16 priceEffectSpan; + + // The amount of nest to pledge for each post (Unit: 1000). 100 + uint16 pledgeNest; + } + + /// @dev PriceSheetView structure + struct PriceSheetView { + + // Index of the price sheet + uint32 index; + + // Address of miner + address miner; + + // The block number of this price sheet packaged + uint32 height; + + // The remain number of this price sheet + uint32 remainNum; + + // The eth number which miner will got + uint32 ethNumBal; + + // The eth number which equivalent to token's value which miner will got + uint32 tokenNumBal; + + // The pledged number of nest in this sheet. (Unit: 1000nest) + uint24 nestNum1k; + + // The level of this sheet. 0 expresses initial price sheet, a value greater than 0 expresses bite price sheet + uint8 level; + + // Post fee shares, if there are many sheets in one block, this value is used to divide up mining value + uint8 shares; + + // The token price. (1eth equivalent to (price) token) + uint152 price; + } + + // 报价通道配置 + struct ChannelConfig { + // 计价代币地址, 0表示eth + address token0; + // 计价代币单位 + uint96 unit; + + // 每个区块的标准出矿量 + uint96 rewardPerBlock; + + // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 + // 出矿代币地址 + address reward; + // 矿币总量 + //uint96 vault; + + // 管理地址 + //address governance; + // 创世区块 + //uint32 genesisBlock; + // Post fee(0.0001eth,DIMI_ETHER). 1000 + uint16 postFeeUnit; + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + uint16 singleFee; + // 衰减系数,万分制。8000 + uint16 reductionRate; + + address[] tokens; + } + + /// @dev Price channel view + struct PriceChannelView { + + uint channelId; + + //uint sheetCount; + + // The information of mining fee + // Low 128-bits represent fee per post + // High 128-bits represent the current counter of no fee sheets (including settled) + uint feeInfo; + + // 计价代币地址, 0表示eth + address token0; + // 计价代币单位 + uint96 unit; + + // // 报价代币地址,0表示eth + // address token1; + // 每个区块的标准出矿量 + uint96 rewardPerBlock; + + // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 + // 出矿代币地址 + address reward; + // 矿币总量 + uint96 vault; + + // 管理地址 + address governance; + // 创世区块 + uint32 genesisBlock; + // Post fee(0.0001eth,DIMI_ETHER). 1000 + uint16 postFeeUnit; + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + uint16 singleFee; + // 衰减系数,万分制。8000 + uint16 reductionRate; + + address[] tokens; + } + + /* ========== Configuration ========== */ + + /// @dev Modify configuration + /// @param config Configuration object + function setConfig(Config calldata config) external; + + /// @dev Get configuration + /// @return Configuration object + function getConfig() external view returns (Config memory); + + // /// @dev 开通报价通道 + // /// @param token0 计价代币地址。0表示eth + // /// @param unit token0的单位 + // /// @param token1 报价代币地址。0表示eth + // /// @param reward 挖矿代币地址。0表示挖eth + // function open(address token0, uint unit, address token1, address reward) external; + + /// @dev 开通报价通道 + /// @param config 报价通道配置 + function open(ChannelConfig calldata config) external; + + /// @dev 向报价通道注入矿币 + /// @param channelId 报价通道 + /// @param vault 注入矿币数量 + function increase(uint channelId, uint96 vault) external payable; + + /// @dev 从报价通道取出矿币 + /// @param channelId 报价通道 + /// @param vault 注入矿币数量 + function decrease(uint channelId, uint96 vault) external; + + /// @dev 获取报价通道信息 + /// @param channelId 报价通道 + /// @return 报价通道信息 + function getChannelInfo(uint channelId) external view returns (PriceChannelView memory); + + /// @dev 报价 + /// @param channelId 报价通道id + /// @param scale 报价规模(token0,单位unit) + /// @param equivalent 与单位token0等价的token1数量 + function post(uint channelId, uint scale, uint[] calldata equivalent) external payable; + + /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet + /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param index The position of the sheet in priceSheetList[token] + /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth + /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth + function takeToken0(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable; + + /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet + /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) + /// @param channelId The address of token(ntoken) + /// @param pairIndex 报价对编号 + /// @param index The position of the sheet in priceSheetList[token] + /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth + /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth + function takeToken1(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable; + + /// @dev List sheets by page + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param offset Skip previous (offset) records + /// @param count Return (count) records + /// @param order Order. 0 reverse order, non-0 positive order + /// @return List of price sheets + function list(uint channelId, uint pairIndex, uint offset, uint count, uint order) external view returns (PriceSheetView[] memory); + + /// @notice Close a batch of price sheets passed VERIFICATION-PHASE + /// @dev Empty sheets but in VERIFICATION-PHASE aren't allowed + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param indices A list of indices of sheets w.r.t. `token` + function close(uint channelId, uint pairIndex, uint[] memory indices) external; + + /// @dev The function updates the statistics of price sheets + /// It calculates from priceInfo to the newest that is effective. + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + function stat(uint channelId, uint pairIndex) external; + + /// @dev View the number of assets specified by the user + /// @param tokenAddress Destination token address + /// @param addr Destination address + /// @return Number of assets + function balanceOf(address tokenAddress, address addr) external view returns (uint); + + /// @dev Withdraw assets + /// @param tokenAddress Destination token address + /// @param value The value to withdraw + function withdraw(address tokenAddress, uint value) external; + + /// @dev Estimated mining amount + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return Estimated mining amount + function estimate(uint channelId, uint pairIndex) external view returns (uint); + + /// @dev Query the quantity of the target quotation + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param index The index of the sheet + /// @return minedBlocks Mined block period from previous block + /// @return totalShares Total shares of sheets in the block + function getMinedBlocks( + uint channelId, + uint pairIndex, + uint index + ) external view returns (uint minedBlocks, uint totalShares); + + /// @dev The function returns eth rewards of specified ntoken + /// @param channelId 报价通道编号 + function totalETHRewards(uint channelId) external view returns (uint); + + /// @dev Pay + /// @param channelId 报价通道编号 + /// @param to Address to receive + /// @param value Amount to receive + function pay(uint channelId, address to, uint value) external; + + /// @dev 向DAO捐赠 + /// @param channelId 报价通道 + /// @param value Amount to receive + function donate(uint channelId, uint value) external; +} \ No newline at end of file diff --git a/hardhat.config.js b/hardhat.config.js index d60a902..f4523d8 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -25,7 +25,7 @@ module.exports = { settings: { optimizer: { enabled: true, - runs: 2048 + runs: 256 } } }, diff --git a/scripts/deploy.js b/scripts/deploy.js index 8613b36..36f3883 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -5,6 +5,6 @@ // Runtime Environment's members available in the global scope. //const hre = require('hardhat'); -const deploy = require('./bsc@20211120.js'); +const deploy = require('./deploy.proxy.js'); exports.deploy = deploy.deploy; \ No newline at end of file diff --git a/scripts/deploy.proxy.js b/scripts/deploy.proxy.js index 075daf3..3e41f6a 100644 --- a/scripts/deploy.proxy.js +++ b/scripts/deploy.proxy.js @@ -19,6 +19,7 @@ exports.deploy = async function() { const NestGovernance = await ethers.getContractFactory('NestGovernance'); const NestLedger = await ethers.getContractFactory('NestLedger'); const NestOpenMining = await ethers.getContractFactory('NestOpenPlatform'); + const NestBatchMining = await ethers.getContractFactory('NestBatchMining'); const NestVote = await ethers.getContractFactory('NestVote'); console.log('** 开始部署合约 deploy.proxy.js **'); @@ -32,6 +33,14 @@ exports.deploy = async function() { //const usdt = await TestERC20.attach('0x0000000000000000000000000000000000000000'); console.log('usdt: ' + usdt.address); + const usdc = await TestERC20.deploy('USDC', 'USDC', 18); + //const usdc = await TestERC20.attach('0x0000000000000000000000000000000000000000'); + console.log('usdc: ' + usdc.address); + + const cofi = await TestERC20.deploy('COFI', 'COFI', 18); + //const cofi = await TestERC20.attach('0x0000000000000000000000000000000000000000'); + console.log('cofi: ' + cofi.address); + const hbtc = await TestERC20.deploy('HBTC', 'HBTC', 18); //const hbtc = await TestERC20.attach('0x0000000000000000000000000000000000000000'); console.log('hbtc: ' + hbtc.address); @@ -52,6 +61,10 @@ exports.deploy = async function() { //const nestOpenMining = await NestOpenMining.attach('0x0000000000000000000000000000000000000000'); console.log('nestOpenMining: ' + nestOpenMining.address); + const nestBatchMining = await upgrades.deployProxy(NestBatchMining, [nestGovernance.address], { initializer: 'initialize' }); + //const nestBatchMining = await NestBatchMining.attach('0x0000000000000000000000000000000000000000'); + console.log('nestBatchMining: ' + nestBatchMining.address); + // const nestPriceFacade = await upgrades.deployProxy(NestPriceFacade, [nestGovernance.address], { initializer: 'initialize' }); // //const nestPriceFacade = await NestPriceFacade.attach('0x0000000000000000000000000000000000000000'); // console.log('nestPriceFacade: ' + nestPriceFacade.address); @@ -92,6 +105,10 @@ exports.deploy = async function() { //await nestMining.update(nestGovernance.address); console.log('4. nestOpenMining.update()'); await nestOpenMining.update(nestGovernance.address); + + console.log('5. nestBatchMining.update()'); + await nestBatchMining.update(nestGovernance.address); + //console.log('5. nestPriceFacade.update()'); //await nestPriceFacade.update(nestGovernance.address); console.log('6. nestVote.update()'); @@ -105,26 +122,19 @@ exports.deploy = async function() { console.log('10. nestOpenMining.setConfig()'); await nestOpenMining.setConfig({ - // // Eth number of each post. 30 - // // We can stop post and taking orders by set postEthUnit to 0 (closing and withdraw are not affected) - // postEthUnit: 30, - - // // Post fee(0.0001eth,DIMI_ETHER). 1000 - // postFeeUnit: 1000, - - // // Proportion of miners digging(10000 based). 8000 - // minerNestReward: 8000, + // -- Public configuration + // The number of times the sheet assets have doubled. 4 + maxBiteNestedLevel: 4, - // // The proportion of token dug by miners is only valid for the token created in version 3.0 - // // (10000 based). 9500 - // minerNTokenReward: 9500, + // Price effective block interval. 20 + priceEffectSpan: 50, - // // When the circulation of ntoken exceeds this threshold, post() is prohibited(Unit: 10000 ether). 500 - // doublePostThreshold: 500, - - // // The limit of ntoken mined blocks. 100 - // ntokenMinedBlockLimit: 100, + // The amount of nest to pledge for each post (Unit: 1000). 100 + pledgeNest: 100 + }); + console.log('11. nestBatchMining.setConfig()'); + await nestBatchMining.setConfig({ // -- Public configuration // The number of times the sheet assets have doubled. 4 maxBiteNestedLevel: 4, @@ -145,11 +155,14 @@ exports.deploy = async function() { nest: nest, usdt: usdt, hbtc: hbtc, + usdc: usdc, + cofi: cofi, nestGovernance: nestGovernance, nestLedger: nestLedger, //nestMining: nestMining, nestOpenMining: nestOpenMining, + nestBatchMining: nestBatchMining, //nestPriceFacade: nestPriceFacade, nestVote: nestVote, // nTokenController: nTokenController, diff --git a/test/16.NestBatchMining.js b/test/16.NestBatchMining.js new file mode 100644 index 0000000..b447570 --- /dev/null +++ b/test/16.NestBatchMining.js @@ -0,0 +1,120 @@ +const { expect } = require('chai'); +const { deploy } = require('../scripts/deploy.js'); +const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); + +describe('NestOpenMining', function() { + it('First', async function() { + var [owner, addr1, addr2] = await ethers.getSigners(); + + const { + nest, usdt, hbtc, + + nestGovernance, nestLedger, + nestMining, nestOpenMining, + nestPriceFacade, nestVote, + nTokenController, nestRedeeming + } = await deploy(); + + const getAccountInfo = async function(account) { + let acc = account; + account = account.address; + return { + eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), + usdt: toDecimal(await usdt.balanceOf(account), 6), + hbtc: toDecimal(await hbtc.balanceOf(account), 18), + nest: toDecimal(await nest.balanceOf(account), 18), + }; + }; + const getStatus = async function() { + return { + height: await ethers.provider.getBlockNumber(), + owner: await getAccountInfo(owner), + addr1: await getAccountInfo(addr1), + mining: await getAccountInfo(nestOpenMining) + }; + }; + + const showStatus = async function() { + let status = await getStatus(); + //console.log(status); + return status; + } + + const skipBlocks = async function(n) { + for (var i = 0; i < n; ++i) { + await usdt.transfer(owner.address, 0); + } + } + + await usdt.transfer(owner.address, 10000000000000n); + await hbtc.transfer(owner.address, 10000000000000000000000000n); + await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); + await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); + await nest.transfer(addr1.address, 1000000000000000000000000000n); + console.log(await getStatus()); + + await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); + await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); + await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + + //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestOpenMining.open({ + // 计价代币地址, 0表示eth + token0: hbtc.address, + // 计价代币单位 + unit: 1000000000000000000n, + + // 报价代币地址,0表示eth + token1: usdt.address, + // 每个区块的标准出矿量 + rewardPerBlock: 1000000000000000000n, + + // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 + // 出矿代币地址 + reward: nest.address, + // 矿币总量 + //uint96 vault; + + // 管理地址 + //address governance; + // 创世区块 + //uint32 genesisBlock; + // Post fee(0.0001eth,DIMI_ETHER). 1000 + postFeeUnit: 1000, + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + singleFee: 100, + // 衰减系数,万分制。8000 + reductionRate: 8000 + }); + await nestOpenMining.increase(0, 5000000000000000000000000000n); + //console.log(await getStatus()); + + const GASLIMIT = 400000n; + const POSTFEE = 0.1; + const OPEN_FEE = 0n; + const EFFECT_BLOCK = 50; + + if (true) { + console.log('1. post'); + let receipt = await nestOpenMining.post(0, 1, 60000000000n, { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + + console.log('1. wait 20 and close'); + await skipBlocks(EFFECT_BLOCK); + await nestOpenMining.close(0, [0]); + } + + if (true) { + console.log('1. post'); + let receipt = await nestOpenMining.post(0, 1, 60000000000n, { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + } + }); +}); diff --git a/test/17.NestBatchMining.js b/test/17.NestBatchMining.js new file mode 100644 index 0000000..8bc7693 --- /dev/null +++ b/test/17.NestBatchMining.js @@ -0,0 +1,132 @@ +const { expect } = require('chai'); +const { deploy } = require('../scripts/deploy.js'); +const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); + +describe('NestOpenMining', function() { + it('First', async function() { + var [owner, addr1, addr2] = await ethers.getSigners(); + + const { + nest, usdt, hbtc, usdc, cofi, + + nestGovernance, nestLedger, + nestMining, nestOpenMining, nestBatchMining, + nestPriceFacade, nestVote, + nTokenController, nestRedeeming + } = await deploy(); + + const getAccountInfo = async function(account) { + let acc = account; + account = account.address; + return { + eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), + usdt: toDecimal(await usdt.balanceOf(account), 6), + hbtc: toDecimal(await hbtc.balanceOf(account), 18), + nest: toDecimal(await nest.balanceOf(account), 18), + }; + }; + const getStatus = async function() { + return { + height: await ethers.provider.getBlockNumber(), + owner: await getAccountInfo(owner), + addr1: await getAccountInfo(addr1), + mining: await getAccountInfo(nestBatchMining) + }; + }; + + const showStatus = async function() { + let status = await getStatus(); + //console.log(status); + return status; + } + + const skipBlocks = async function(n) { + for (var i = 0; i < n; ++i) { + await usdt.transfer(owner.address, 0); + } + } + + await usdt.transfer(owner.address, 10000000000000n); + await usdc.transfer(owner.address, 10000000000000n); + await cofi.transfer(owner.address, 10000000000000n); + await hbtc.transfer(owner.address, 10000000000000000000000000n); + await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); + await usdc.connect(addr1).transfer(addr1.address, 10000000000000n); + await cofi.connect(addr1).transfer(addr1.address, 10000000000000n); + await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); + await nest.transfer(addr1.address, 1000000000000000000000000000n); + console.log(await getStatus()); + + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await usdc.approve(nestBatchMining.address, 10000000000000000000000000n); + await cofi.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await usdc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await cofi.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + + //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ + // 计价代币地址, 0表示eth + token0: hbtc.address, + // 计价代币单位 + unit: 1000000000000000000n, + + // 报价代币地址,0表示eth + //token1: usdt.address, + // 每个区块的标准出矿量 + rewardPerBlock: 1000000000000000000n, + + // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 + // 出矿代币地址 + reward: nest.address, + // 矿币总量 + //uint96 vault; + + // 管理地址 + //address governance; + // 创世区块 + //uint32 genesisBlock; + // Post fee(0.0001eth,DIMI_ETHER). 1000 + postFeeUnit: 1000, + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + singleFee: 100, + // 衰减系数,万分制。8000 + reductionRate: 8000, + + tokens: [usdt.address, usdc.address, cofi.address] + }); + await nestBatchMining.increase(0, 5000000000000000000000000000n); + //console.log(await getStatus()); + + const GASLIMIT = 400000n; + const POSTFEE = 0.1; + const OPEN_FEE = 0n; + const EFFECT_BLOCK = 50; + + if (true) { + console.log('1. post'); + let receipt = await nestBatchMining.post(0, 1, [60000000000n, 60000000000n, 60000000000n], { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + + console.log('1. wait 20 and close'); + await skipBlocks(EFFECT_BLOCK); + await nestBatchMining.close(0, 0, [0]); + await nestBatchMining.close(0, 1, [0]); + await nestBatchMining.close(0, 2, [0]); + } + + if (true) { + console.log('1. post'); + let receipt = await nestBatchMining.post(0, 1, [60000000000n, 60000000000n, 60000000000n], { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + } + }); +}); diff --git a/test/18.NestBatchMining.js b/test/18.NestBatchMining.js new file mode 100644 index 0000000..529925b --- /dev/null +++ b/test/18.NestBatchMining.js @@ -0,0 +1,131 @@ +const { expect } = require('chai'); +const { deploy } = require('../scripts/deploy.js'); +const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); + +describe('NestOpenMining', function() { + it('First', async function() { + var [owner, addr1, addr2] = await ethers.getSigners(); + + const { + nest, usdt, hbtc, usdc, cofi, + + nestGovernance, nestLedger, + nestMining, nestOpenMining, nestBatchMining, + nestPriceFacade, nestVote, + nTokenController, nestRedeeming + } = await deploy(); + + const getAccountInfo = async function(account) { + let acc = account; + account = account.address; + return { + eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), + usdt: toDecimal(await usdt.balanceOf(account), 6), + hbtc: toDecimal(await hbtc.balanceOf(account), 18), + nest: toDecimal(await nest.balanceOf(account), 18), + }; + }; + const getStatus = async function() { + return { + height: await ethers.provider.getBlockNumber(), + owner: await getAccountInfo(owner), + addr1: await getAccountInfo(addr1), + mining: await getAccountInfo(nestBatchMining) + }; + }; + + const showStatus = async function() { + let status = await getStatus(); + //console.log(status); + return status; + } + + const skipBlocks = async function(n) { + for (var i = 0; i < n; ++i) { + await usdt.transfer(owner.address, 0); + } + } + + await usdt.transfer(owner.address, 10000000000000n); + await usdc.transfer(owner.address, 10000000000000n); + await cofi.transfer(owner.address, 10000000000000n); + await hbtc.transfer(owner.address, 10000000000000000000000000n); + await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); + await usdc.connect(addr1).transfer(addr1.address, 10000000000000n); + await cofi.connect(addr1).transfer(addr1.address, 10000000000000n); + await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); + await nest.transfer(addr1.address, 1000000000000000000000000000n); + console.log(await getStatus()); + + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await usdc.approve(nestBatchMining.address, 10000000000000000000000000n); + await cofi.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await usdc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await cofi.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + + //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ + // 计价代币地址, 0表示eth + token0: hbtc.address, + // 计价代币单位 + unit: 1000000000000000000n, + + // 报价代币地址,0表示eth + //token1: usdt.address, + // 每个区块的标准出矿量 + rewardPerBlock: 1000000000000000000n, + + // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 + // 出矿代币地址 + reward: nest.address, + // 矿币总量 + //uint96 vault; + + // 管理地址 + //address governance; + // 创世区块 + //uint32 genesisBlock; + // Post fee(0.0001eth,DIMI_ETHER). 1000 + postFeeUnit: 1000, + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + singleFee: 100, + // 衰减系数,万分制。8000 + reductionRate: 8000, + + tokens: [usdt.address, usdc.address] + }); + await nestBatchMining.increase(0, 5000000000000000000000000000n); + //console.log(await getStatus()); + + const GASLIMIT = 400000n; + const POSTFEE = 0.1; + const OPEN_FEE = 0n; + const EFFECT_BLOCK = 50; + + if (true) { + console.log('1. post'); + let receipt = await nestBatchMining.post(0, 1, [60000000000n, 60000000000n], { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + + console.log('1. wait 20 and close'); + await skipBlocks(EFFECT_BLOCK); + await nestBatchMining.close(0, 0, [0]); + await nestBatchMining.close(0, 1, [0]); + } + + if (true) { + console.log('1. post'); + let receipt = await nestBatchMining.post(0, 1, [60000000000n, 60000000000n], { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + } + }); +}); diff --git a/test/19.NestBatchMining.js b/test/19.NestBatchMining.js new file mode 100644 index 0000000..d2d9cd4 --- /dev/null +++ b/test/19.NestBatchMining.js @@ -0,0 +1,130 @@ +const { expect } = require('chai'); +const { deploy } = require('../scripts/deploy.js'); +const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); + +describe('NestOpenMining', function() { + it('First', async function() { + var [owner, addr1, addr2] = await ethers.getSigners(); + + const { + nest, usdt, hbtc, usdc, cofi, + + nestGovernance, nestLedger, + nestMining, nestOpenMining, nestBatchMining, + nestPriceFacade, nestVote, + nTokenController, nestRedeeming + } = await deploy(); + + const getAccountInfo = async function(account) { + let acc = account; + account = account.address; + return { + eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), + usdt: toDecimal(await usdt.balanceOf(account), 6), + hbtc: toDecimal(await hbtc.balanceOf(account), 18), + nest: toDecimal(await nest.balanceOf(account), 18), + }; + }; + const getStatus = async function() { + return { + height: await ethers.provider.getBlockNumber(), + owner: await getAccountInfo(owner), + addr1: await getAccountInfo(addr1), + mining: await getAccountInfo(nestBatchMining) + }; + }; + + const showStatus = async function() { + let status = await getStatus(); + //console.log(status); + return status; + } + + const skipBlocks = async function(n) { + for (var i = 0; i < n; ++i) { + await usdt.transfer(owner.address, 0); + } + } + + await usdt.transfer(owner.address, 10000000000000n); + await usdc.transfer(owner.address, 10000000000000n); + await cofi.transfer(owner.address, 10000000000000n); + await hbtc.transfer(owner.address, 10000000000000000000000000n); + await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); + await usdc.connect(addr1).transfer(addr1.address, 10000000000000n); + await cofi.connect(addr1).transfer(addr1.address, 10000000000000n); + await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); + await nest.transfer(addr1.address, 1000000000000000000000000000n); + console.log(await getStatus()); + + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await usdc.approve(nestBatchMining.address, 10000000000000000000000000n); + await cofi.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await usdc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await cofi.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + + //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ + // 计价代币地址, 0表示eth + token0: hbtc.address, + // 计价代币单位 + unit: 1000000000000000000n, + + // 报价代币地址,0表示eth + //token1: usdt.address, + // 每个区块的标准出矿量 + rewardPerBlock: 1000000000000000000n, + + // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 + // 出矿代币地址 + reward: nest.address, + // 矿币总量 + //uint96 vault; + + // 管理地址 + //address governance; + // 创世区块 + //uint32 genesisBlock; + // Post fee(0.0001eth,DIMI_ETHER). 1000 + postFeeUnit: 1000, + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + singleFee: 100, + // 衰减系数,万分制。8000 + reductionRate: 8000, + + tokens: [usdt.address] + }); + await nestBatchMining.increase(0, 5000000000000000000000000000n); + //console.log(await getStatus()); + + const GASLIMIT = 400000n; + const POSTFEE = 0.1; + const OPEN_FEE = 0n; + const EFFECT_BLOCK = 50; + + if (true) { + console.log('1. post'); + let receipt = await nestBatchMining.post(0, 1, [60000000000n], { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + + console.log('1. wait 20 and close'); + await skipBlocks(EFFECT_BLOCK); + await nestBatchMining.close(0, 0, [0]); + } + + if (true) { + console.log('1. post'); + let receipt = await nestBatchMining.post(0, 1, [60000000000n], { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + } + }); +}); From f3d7273dbafc3dd25681ead162a7d021568caea3 Mon Sep 17 00:00:00 2001 From: chenf Date: Wed, 8 Dec 2021 15:50:12 +0800 Subject: [PATCH 02/41] Batch close --- contracts/NestBatchMining.sol | 513 ++++++++++++----------- contracts/interface/INestBatchMining.sol | 22 +- test/18.NestBatchMining.js | 3 +- test/19.NestBatchMining.js | 2 +- 4 files changed, 289 insertions(+), 251 deletions(-) diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index babfe5b..8ab3c59 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -93,7 +93,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // The information of mining fee // Low 128-bits represent fee per post // High 128-bits represent the current counter of no fee sheets (including settled) - uint feeInfo; + uint fee; // 计价代币地址, 0表示eth address token0; @@ -118,9 +118,11 @@ contract NestBatchMining is NestBase, INestBatchMining { uint16 singleFee; // 衰减系数,万分制。8000 uint16 reductionRate; + // 报价对数量 uint16 count; - PricePair[255] pairs; + // 报价对数组 + PricePair[0xFFFF] pairs; } /// @dev Structure is used to represent a storage location. Storage variable can be used to avoid indexing @@ -159,7 +161,7 @@ contract NestBatchMining is NestBase, INestBatchMining { uint constant DIMI_ETHER = 0.0001 ether; // Ethereum average block time interval, 14 seconds - uint constant ETHEREUM_BLOCK_TIMESPAN = 3; + uint constant ETHEREUM_BLOCK_TIMESPAN = 14; /* ========== Governance ========== */ @@ -199,12 +201,32 @@ contract NestBatchMining is NestBase, INestBatchMining { // 衰减系数,万分制。8000 channel.reductionRate = config.reductionRate; channel.count = uint16(config.tokens.length); + + // 遍历创建报价对 for (uint i = 0; i < config.tokens.length; ++i) { require(token0 != config.tokens[i], "NOM:token can't equal token1"); + for (uint j = 0; j < i; ++j) { + require(config.tokens[i] != config.tokens[j], "NOM:token reiterated"); + } channel.pairs[i].target = config.tokens[i]; } } + /// @dev 添加报价代币,与计价代币形成新的报价对(暂不支持删除,请谨慎添加) + /// @param channelId 报价通道 + /// @param target 目标代币地址 + function addPair(uint channelId, address target) external { + PriceChannel storage channel = _channels[channelId]; + require(channel.governance == msg.sender, "NOM:not governance"); + require(channel.token0 != target, "NOM:token can't equal token1"); + uint count = uint(channel.count); + for (uint j = 0; j < count; ++j) { + require(channel.pairs[j].target != target, "NOM:token reiterated"); + } + channel.pairs[count].target = target; + ++channel.count; + } + /// @dev 向报价通道注入矿币 /// @param channelId 报价通道 /// @param vault 注入矿币数量 @@ -234,15 +256,6 @@ contract NestBatchMining is NestBase, INestBatchMining { channel.vault -= vault; } - // /// @dev 向报价通道注入NToken矿币 - // /// @param channelId 报价通道 - // /// @param vault 注入矿币数量 - // function increaseNToken(uint channelId, uint96 vault) external onlyGovernance { - // PriceChannel storage channel = _channels[channelId]; - // INToken(channel.reward).increaseTotal(vault); - // channel.vault += vault; - // } - /// @dev 修改治理权限地址 /// @param channelId 报价通道 /// @param newGovernance 新治理权限地址 @@ -259,9 +272,10 @@ contract NestBatchMining is NestBase, INestBatchMining { PriceChannel storage channel = _channels[channelId]; uint count = uint(channel.count); - address[] memory tokens = new address[](count); + PairView[] memory pairs = new PairView[](count); for (uint i = 0; i < count; ++i) { - tokens[i] = channel.pairs[i].target; + PricePair storage pair = channel.pairs[i]; + pairs[i] = PairView(pair.target, uint96(pair.sheets.length)); } return PriceChannelView ( @@ -272,7 +286,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // The information of mining fee // Low 128-bits represent fee per post // High 128-bits represent the current counter of no fee sheets (including settled) - channel.feeInfo, + channel.fee, // 计价代币地址, 0表示eth channel.token0, @@ -300,8 +314,10 @@ contract NestBatchMining is NestBase, INestBatchMining { channel.singleFee, // 衰减系数,万分制。8000 channel.reductionRate, + // 报价对数量 + channel.count, - tokens + pairs ); } @@ -322,7 +338,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // 2. Check price channel // 3. Load token channel and sheets PriceChannel storage channel = _channels[channelId]; - PricePair[255] storage pairs = channel.pairs; + //PricePair[0xFFFF] storage pairs = channel.pairs; //PriceSheet[] storage sheets = channel.sheets; // 4. Freeze assets @@ -335,31 +351,33 @@ contract NestBatchMining is NestBase, INestBatchMining { // precision loss can be transferred out as system income in the future mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; - uint count = uint(channel.count); + uint cn = uint(channel.count); uint fee = msg.value; + + // 冻结nest + fee = _freeze(balances, NEST_TOKEN_ADDRESS, cn * uint(config.pledgeNest) * 1000 ether, fee); + // 冻结token0 - fee = _freeze(balances, channel.token0, uint(channel.unit) * scale * count, fee); + fee = _freeze(balances, channel.token0, cn * uint(channel.unit) * scale, fee); // 冻结token1 //fee = _freeze(balances, channel.token1, scale * equivalent, fee); - while (count > 0) { - //PricePair storage pair = pairs[--count]; - fee = _freeze(balances, pairs[--count].target, scale * equivalent[count], fee); + while (cn > 0) { + PricePair storage pair = channel.pairs[--cn]; + fee = _freeze(balances, pair.target, scale * equivalent[cn], fee); - PriceSheet[] storage sheets = pairs[count].sheets; + PriceSheet[] storage sheets = pair.sheets; // Calculate the price // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price // is placed before the sheet is added, which can reduce unnecessary traversal - _stat(config, pairs[count], sheets); + _stat(config, pair, sheets); // 6. Create token price sheet - emit Post(channelId, msg.sender, sheets.length, scale, equivalent[count]); - _createPriceSheet(sheets, accountIndex, uint32(scale), uint(config.pledgeNest), 1, equivalent[count]); + // TODO: 对事件参数进行优化 + emit Post(channelId, cn, msg.sender, sheets.length, scale, equivalent[cn]); + _createPriceSheet(sheets, accountIndex, uint32(scale), uint(config.pledgeNest), 1, equivalent[cn]); } - // 冻结nest - fee = _freeze(balances, NEST_TOKEN_ADDRESS, uint(config.pledgeNest) * 1000 ether * count, fee); - // 5. Deposit fee // 只有配置了报价佣金时才检查fee uint postFeeUnit = uint(channel.postFeeUnit); @@ -367,7 +385,7 @@ contract NestBatchMining is NestBase, INestBatchMining { require(fee >= postFeeUnit * DIMI_ETHER + tx.gasprice * 400000, "NM:!fee"); } if (fee > 0) { - channel.feeInfo += fee; + channel.fee += fee; } } @@ -380,82 +398,85 @@ contract NestBatchMining is NestBase, INestBatchMining { /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth function takeToken0(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { - // Config memory config = _config; - - // // 1. Check arguments - // require(takeNum > 0, "NM:!takeNum"); - // require(newEquivalent > 0, "NM:!price"); - - // // 2. Load price sheet - // PriceChannel storage channel = _channels[channelId]; - // PricePair storage pair = channel.pairs[pairIndex]; - // PriceSheet[] storage sheets = pair.sheets; - // PriceSheet memory sheet = sheets[index]; - - // // 3. Check state - // require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); - // require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); - - // // 4. Deposit fee - // // 5. Calculate the number of eth, token and nest needed, and freeze them - // uint needEthNum; - // uint level = uint(sheet.level); - - // // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled - // if (level < uint(config.maxBiteNestedLevel)) { - // // Double scale sheet - // needEthNum = takeNum << 1; - // ++level; - // } - // // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not - // else { - // // Single scale sheet - // needEthNum = takeNum; - // // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 - // // or more, there is no logical dependence on the specific value of the contract, and the count will - // // not increase after it is accumulated to 255 - // if (level < 255) ++level; - // } - - // // Number of nest to be pledged - // //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); - // // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum - // uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); - // // Freeze nest and token - // uint accountIndex = _addressIndex(msg.sender); - // { - // // 冻结资产:token0, token1, nest - // mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; - // uint fee = msg.value; - - // // 冻结token0 - // fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); - // // 冻结token1 - // fee = _freeze( - // balances, - // pair.target, - // needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, - // fee - // ); - // // 冻结nest - // fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); - // require(fee == 0, "NOM:!fee"); - // } - - // // 6. Update the bitten sheet - // sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); - // sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); - // sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); - // sheets[index] = sheet; - - // // 7. Calculate the price - // // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price - // // is placed before the sheet is added, which can reduce unnecessary traversal - // _stat(config, pair, sheets); - - // // 8. Create price sheet - // //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); - // _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); + Config memory config = _config; + + // 1. Check arguments + require(takeNum > 0, "NM:!takeNum"); + require(newEquivalent > 0, "NM:!price"); + + // 2. Load price sheet + PriceChannel storage channel = _channels[channelId]; + PricePair storage pair = channel.pairs[pairIndex]; + PriceSheet[] storage sheets = pair.sheets; + PriceSheet memory sheet = sheets[index]; + + // 3. Check state + require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); + require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); + + uint accountIndex = _addressIndex(msg.sender); + // Number of nest to be pledged + //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); + // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum + uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); + + // 4. Deposit fee + // 5. Calculate the number of eth, token and nest needed, and freeze them + uint needEthNum; + { + uint level = uint(sheet.level); + + // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled + if (level < uint(config.maxBiteNestedLevel)) { + // Double scale sheet + needEthNum = takeNum << 1; + ++level; + } + // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not + else { + // Single scale sheet + needEthNum = takeNum; + // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 + // or more, there is no logical dependence on the specific value of the contract, and the count will + // not increase after it is accumulated to 255 + if (level < 255) ++level; + } + + // 7. Calculate the price + // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price + // is placed before the sheet is added, which can reduce unnecessary traversal + _stat(config, pair, sheets); + + // 8. Create price sheet + //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); + _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); + } + + // Freeze nest and token + { + // 冻结资产:token0, token1, nest + mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + uint fee = msg.value; + + // 冻结token0 + fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); + // 冻结token1 + fee = _freeze( + balances, + pair.target, + needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, + fee + ); + // 冻结nest + fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); + require(fee == 0, "NOM:!fee"); + } + + // 6. Update the bitten sheet + sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); + sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); + sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); + sheets[index] = sheet; } /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet @@ -467,82 +488,84 @@ contract NestBatchMining is NestBase, INestBatchMining { /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth function takeToken1(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { - // Config memory config = _config; - - // // 1. Check arguments - // require(takeNum > 0, "NM:!takeNum"); - // require(newEquivalent > 0, "NM:!price"); - - // // 2. Load price sheet - // PriceChannel storage channel = _channels[channelId]; - // PricePair storage pair = channel.pairs[pairIndex]; - // PriceSheet[] storage sheets = pair.sheets; - // PriceSheet memory sheet = sheets[index]; - - // // 3. Check state - // require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); - // require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); - - // // 4. Deposit fee - - // // 5. Calculate the number of eth, token and nest needed, and freeze them - // uint needEthNum; - // uint level = uint(sheet.level); - - // // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled - // if (level < uint(config.maxBiteNestedLevel)) { - // // Double scale sheet - // needEthNum = takeNum << 1; - // ++level; - // } - // // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not - // else { - // // Single scale sheet - // needEthNum = takeNum; - // // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 - // // or more, there is no logical dependence on the specific value of the contract, and the count will - // // not increase after it is accumulated to 255 - // if (level < 255) ++level; - // } - - // // Number of nest to be pledged - // //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); - // // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum - // uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); - // // Freeze nest and token - // uint accountIndex = _addressIndex(msg.sender); - // { - // // 冻结资产:token0, token1, nest - // mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; - - // uint fee = msg.value; - // // 冻结token0 - // fee = _freeze(balances, channel.token0, (needEthNum + takeNum) * uint(channel.unit), fee); - // // 冻结token1 - // uint backTokenValue = _decodeFloat(sheet.priceFloat) * takeNum; - // if (needEthNum * newEquivalent > backTokenValue) { - // fee = _freeze(balances, pair.target, needEthNum * newEquivalent - backTokenValue, fee); - // } else { - // _unfreeze(balances, pair.target, backTokenValue - needEthNum * newEquivalent, msg.sender); - // } - // fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); - // require(fee == 0, "NOM:!fee"); - // } - - // // 6. Update the bitten sheet - // sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); - // sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); - // sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); - // sheets[index] = sheet; - - // // 7. Calculate the price - // // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price - // // is placed before the sheet is added, which can reduce unnecessary traversal - // _stat(config, pair, sheets); - - // // 8. Create price sheet - // //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); - // _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); + Config memory config = _config; + + // 1. Check arguments + require(takeNum > 0, "NM:!takeNum"); + require(newEquivalent > 0, "NM:!price"); + + // 2. Load price sheet + PriceChannel storage channel = _channels[channelId]; + PricePair storage pair = channel.pairs[pairIndex]; + PriceSheet[] storage sheets = pair.sheets; + PriceSheet memory sheet = sheets[index]; + + // 3. Check state + require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); + require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); + + uint accountIndex = _addressIndex(msg.sender); + // Number of nest to be pledged + //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); + // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum + uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); + + // 4. Deposit fee + // 5. Calculate the number of eth, token and nest needed, and freeze them + uint needEthNum; + { + uint level = uint(sheet.level); + + // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled + if (level < uint(config.maxBiteNestedLevel)) { + // Double scale sheet + needEthNum = takeNum << 1; + ++level; + } + // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not + else { + // Single scale sheet + needEthNum = takeNum; + // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 + // or more, there is no logical dependence on the specific value of the contract, and the count will + // not increase after it is accumulated to 255 + if (level < 255) ++level; + } + + // 7. Calculate the price + // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price + // is placed before the sheet is added, which can reduce unnecessary traversal + _stat(config, pair, sheets); + + // 8. Create price sheet + //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); + _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); + } + + // Freeze nest and token + { + // 冻结资产:token0, token1, nest + mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + + uint fee = msg.value; + // 冻结token0 + fee = _freeze(balances, channel.token0, (needEthNum + takeNum) * uint(channel.unit), fee); + // 冻结token1 + uint backTokenValue = _decodeFloat(sheet.priceFloat) * takeNum; + if (needEthNum * newEquivalent > backTokenValue) { + fee = _freeze(balances, pair.target, needEthNum * newEquivalent - backTokenValue, fee); + } else { + _unfreeze(balances, pair.target, backTokenValue - needEthNum * newEquivalent, msg.sender); + } + fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); + require(fee == 0, "NOM:!fee"); + } + + // 6. Update the bitten sheet + sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); + sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); + sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); + sheets[index] = sheet; } /// @dev List sheets by page @@ -594,24 +617,75 @@ contract NestBatchMining is NestBase, INestBatchMining { /// @notice Close a batch of price sheets passed VERIFICATION-PHASE /// @dev Empty sheets but in VERIFICATION-PHASE aren't allowed /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 + /// @param pairIndices 报价对编号数组 /// @param indices A list of indices of sheets w.r.t. `token` - function close(uint channelId, uint pairIndex, uint[] memory indices) external override { + function close(uint channelId, uint[] calldata pairIndices, uint[] calldata indices) external override { + //Config memory config = _config; PriceChannel storage channel = _channels[channelId]; - PricePair storage pair = channel.pairs[pairIndex]; - // Call _closeList() method to close price sheets - ( - uint accountIndex, - Tuple memory total - ) = _closeList(_config, channel, pair, indices); - + + // // Call _closeList() method to close price sheets + // ( + // uint accountIndex, + // Tuple memory total + // ) = _closeList(_config, channel, pair, indices); + + // uint rewardPerBlock = uint(channel.rewardPerBlock); + // uint genesisBlock = uint(channel.genesisBlock); + // uint reductionRate = uint(channel.reductionRate); + + uint accountIndex = 0; + // TODO: storage变量必须在定义时初始化,因此在此处赋值,但是由于accountIndex此时为0,此赋值没有意义 mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + Tuple memory total; + + for (uint j = pairIndices.length; j > 0;) { + PricePair storage pair = channel.pairs[pairIndices[--j]]; + + /////////////////////////////////////////////////////////////////////////////////////// + PriceSheet[] storage sheets = pair.sheets; + + // 1. Traverse sheets + for (uint i = indices.length; i > 0;) { + + // Because too many variables need to be returned, too many variables will be defined, + // so the structure of tuple is defined + (uint minerIndex, Tuple memory value) = _close( + _config, + sheets, + indices[--i], + uint(channel.rewardPerBlock), + uint(channel.genesisBlock), + uint(channel.reductionRate) + ); + // Batch closing quotation can only close sheet of the same user + if (accountIndex == 0) { + // accountIndex == 0 means the first sheet, and the number of this sheet is taken + accountIndex = minerIndex; + balances = _accounts[accountIndex].balances; + } else { + // accountIndex != 0 means that it is a follow-up sheet, and the miner number must be + // consistent with the previous record + require(accountIndex == minerIndex, "NM:!miner"); + } + + total.ntokenValue += value.ntokenValue; + total.nestValue += value.nestValue; + total.ethNum += value.ethNum; + total.tokenValue += value.tokenValue; + } + + _stat(_config, pair, sheets); + /////////////////////////////////////////////////////////////////////////////////////// + + // 解冻token1 + _unfreeze(balances, pair.target, uint(total.tokenValue), accountIndex); + total.tokenValue = 0; + } // 解冻token0 _unfreeze(balances, channel.token0, uint(total.ethNum) * uint(channel.unit), accountIndex); - // 解冻token1 - _unfreeze(balances, pair.target, uint(total.tokenValue), accountIndex); + // 解冻nest _unfreeze(balances, NEST_TOKEN_ADDRESS, uint(total.nestValue), accountIndex); @@ -711,7 +785,7 @@ contract NestBatchMining is NestBase, INestBatchMining { /// @dev The function returns eth rewards of specified ntoken /// @param channelId 报价通道编号 function totalETHRewards(uint channelId) external view override returns (uint) { - return _channels[channelId].feeInfo; + return _channels[channelId].fee; } /// @dev Pay @@ -722,7 +796,7 @@ contract NestBatchMining is NestBase, INestBatchMining { PriceChannel storage channel = _channels[channelId]; require(channel.governance == msg.sender, "NOM:!governance"); - channel.feeInfo -= value; + channel.fee -= value; // pay payable(to).transfer(value); } @@ -734,7 +808,7 @@ contract NestBatchMining is NestBase, INestBatchMining { PriceChannel storage channel = _channels[channelId]; require(channel.governance == msg.sender, "NOM:!governance"); - channel.feeInfo -= value; + channel.fee -= value; INestLedger(INestMapping(_governance).getNestLedgerAddress()).addETHReward { value: value } (channelId); } @@ -987,53 +1061,6 @@ contract NestBatchMining is NestBase, INestBatchMining { } } - // Batch close sheets - function _closeList( - Config memory config, - PriceChannel storage channel, - PricePair storage pair, - uint[] memory indices - ) private returns (uint accountIndex, Tuple memory total) { - - PriceSheet[] storage sheets = pair.sheets; - accountIndex = 0; - - uint rewardPerBlock = uint(channel.rewardPerBlock); - uint genesisBlock = uint(channel.genesisBlock); - uint reductionRate = uint(channel.reductionRate); - - // 1. Traverse sheets - for (uint i = indices.length; i > 0;) { - - // Because too many variables need to be returned, too many variables will be defined, - // so the structure of tuple is defined - (uint minerIndex, Tuple memory value) = _close( - config, - sheets, - indices[--i], - rewardPerBlock, - genesisBlock, - reductionRate - ); - // Batch closing quotation can only close sheet of the same user - if (accountIndex == 0) { - // accountIndex == 0 means the first sheet, and the number of this sheet is taken - accountIndex = minerIndex; - } else { - // accountIndex != 0 means that it is a follow-up sheet, and the miner number must be - // consistent with the previous record - require(accountIndex == minerIndex, "NM:!miner"); - } - - total.ntokenValue += value.ntokenValue; - total.nestValue += value.nestValue; - total.ethNum += value.ethNum; - total.tokenValue += value.tokenValue; - } - - _stat(config, pair, sheets); - } - // Calculation number of blocks which mined function _calcMinedBlocks( PriceSheet[] storage sheets, diff --git a/contracts/interface/INestBatchMining.sol b/contracts/interface/INestBatchMining.sol index 88f4513..aa66977 100644 --- a/contracts/interface/INestBatchMining.sol +++ b/contracts/interface/INestBatchMining.sol @@ -14,10 +14,11 @@ interface INestBatchMining { /// @dev Post event /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 /// @param miner Address of miner /// @param index Index of the price sheet /// @param scale 报价规模 - event Post(uint channelId, address miner, uint index, uint scale, uint price); + event Post(uint channelId, uint pairIndex, address miner, uint index, uint scale, uint price); /* ========== Structures ========== */ @@ -119,6 +120,14 @@ interface INestBatchMining { address[] tokens; } + /// @dev 报价对视图 + struct PairView { + // 报价代币地址 + address target; + // 报价单数量 + uint96 sheetCount; + } + /// @dev Price channel view struct PriceChannelView { @@ -129,7 +138,7 @@ interface INestBatchMining { // The information of mining fee // Low 128-bits represent fee per post // High 128-bits represent the current counter of no fee sheets (including settled) - uint feeInfo; + uint fee; // 计价代币地址, 0表示eth address token0; @@ -157,8 +166,11 @@ interface INestBatchMining { uint16 singleFee; // 衰减系数,万分制。8000 uint16 reductionRate; + // 报价对数量 + uint16 count; - address[] tokens; + // 报价对信息 + PairView[] pairs; } /* ========== Configuration ========== */ @@ -233,9 +245,9 @@ interface INestBatchMining { /// @notice Close a batch of price sheets passed VERIFICATION-PHASE /// @dev Empty sheets but in VERIFICATION-PHASE aren't allowed /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 + /// @param pairIndices 报价对编号数组 /// @param indices A list of indices of sheets w.r.t. `token` - function close(uint channelId, uint pairIndex, uint[] memory indices) external; + function close(uint channelId, uint[] calldata pairIndices, uint[] calldata indices) external; /// @dev The function updates the statistics of price sheets /// It calculates from priceInfo to the newest that is effective. diff --git a/test/18.NestBatchMining.js b/test/18.NestBatchMining.js index 529925b..dab61c6 100644 --- a/test/18.NestBatchMining.js +++ b/test/18.NestBatchMining.js @@ -116,8 +116,7 @@ describe('NestOpenMining', function() { console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestBatchMining.close(0, 0, [0]); - await nestBatchMining.close(0, 1, [0]); + await nestBatchMining.close(0, [0, 1], [0]); } if (true) { diff --git a/test/19.NestBatchMining.js b/test/19.NestBatchMining.js index d2d9cd4..af8608e 100644 --- a/test/19.NestBatchMining.js +++ b/test/19.NestBatchMining.js @@ -116,7 +116,7 @@ describe('NestOpenMining', function() { console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestBatchMining.close(0, 0, [0]); + await nestBatchMining.close(0, [0], [0]); } if (true) { From 4422a283ba55c78b1d34f0b06d6ded1e67f70ede Mon Sep 17 00:00:00 2001 From: chenf Date: Wed, 8 Dec 2021 18:11:21 +0800 Subject: [PATCH 03/41] Complete --- contracts/NestBatchMining.sol | 600 ++++++++++++----------- contracts/interface/INestBatchMining.sol | 22 +- test/17.NestBatchMining.js | 6 +- test/18.NestBatchMining.js | 2 +- test/19.NestBatchMining.js | 2 +- 5 files changed, 329 insertions(+), 303 deletions(-) diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index 8ab3c59..3e117d3 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -93,7 +93,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // The information of mining fee // Low 128-bits represent fee per post // High 128-bits represent the current counter of no fee sheets (including settled) - uint fee; + uint rewards; // 计价代币地址, 0表示eth address token0; @@ -286,7 +286,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // The information of mining fee // Low 128-bits represent fee per post // High 128-bits represent the current counter of no fee sheets (including settled) - channel.fee, + channel.rewards, // 计价代币地址, 0表示eth channel.token0, @@ -375,7 +375,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // 6. Create token price sheet // TODO: 对事件参数进行优化 emit Post(channelId, cn, msg.sender, sheets.length, scale, equivalent[cn]); - _createPriceSheet(sheets, accountIndex, uint32(scale), uint(config.pledgeNest), 1, equivalent[cn]); + _createPriceSheet(sheets, accountIndex, uint32(scale), uint(config.pledgeNest), cn == 0 ? 1 : 0, equivalent[cn]); } // 5. Deposit fee @@ -385,7 +385,7 @@ contract NestBatchMining is NestBase, INestBatchMining { require(fee >= postFeeUnit * DIMI_ETHER + tx.gasprice * 400000, "NM:!fee"); } if (fee > 0) { - channel.fee += fee; + channel.rewards += fee; } } @@ -617,9 +617,8 @@ contract NestBatchMining is NestBase, INestBatchMining { /// @notice Close a batch of price sheets passed VERIFICATION-PHASE /// @dev Empty sheets but in VERIFICATION-PHASE aren't allowed /// @param channelId 报价通道编号 - /// @param pairIndices 报价对编号数组 - /// @param indices A list of indices of sheets w.r.t. `token` - function close(uint channelId, uint[] calldata pairIndices, uint[] calldata indices) external override { + /// @param indices 报价单二维数组,外层对应通道号,内层对应报价单号,如果仅关闭后面的报价对,则前面的报价对数组传空数组 + function close(uint channelId, uint[][] calldata indices) external override { //Config memory config = _config; PriceChannel storage channel = _channels[channelId]; @@ -630,33 +629,36 @@ contract NestBatchMining is NestBase, INestBatchMining { // Tuple memory total // ) = _closeList(_config, channel, pair, indices); - // uint rewardPerBlock = uint(channel.rewardPerBlock); - // uint genesisBlock = uint(channel.genesisBlock); - // uint reductionRate = uint(channel.reductionRate); + //uint rewardPerBlock = uint(channel.rewardPerBlock); + //uint genesisBlock = uint(channel.genesisBlock); + //uint reductionRate = uint(channel.reductionRate); + uint reward = 0; uint accountIndex = 0; // TODO: storage变量必须在定义时初始化,因此在此处赋值,但是由于accountIndex此时为0,此赋值没有意义 mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + // TODO: 不用Tuple? Tuple memory total; - for (uint j = pairIndices.length; j > 0;) { - PricePair storage pair = channel.pairs[pairIndices[--j]]; + for (uint j = indices.length; j > 0;) { + PricePair storage pair = channel.pairs[--j]; /////////////////////////////////////////////////////////////////////////////////////// PriceSheet[] storage sheets = pair.sheets; // 1. Traverse sheets - for (uint i = indices.length; i > 0;) { + for (uint i = indices[j].length; i > 0;) { // Because too many variables need to be returned, too many variables will be defined, // so the structure of tuple is defined (uint minerIndex, Tuple memory value) = _close( _config, sheets, - indices[--i], - uint(channel.rewardPerBlock), - uint(channel.genesisBlock), - uint(channel.reductionRate) + indices[j][--i]//, + // TODO:优化之 + // rewardPerBlock, + // genesisBlock, + // reductionRate ); // Batch closing quotation can only close sheet of the same user if (accountIndex == 0) { @@ -669,8 +671,22 @@ contract NestBatchMining is NestBase, INestBatchMining { require(accountIndex == minerIndex, "NM:!miner"); } - total.ntokenValue += value.ntokenValue; - total.nestValue += value.nestValue; + // TODO: 后面的通道不出矿,不需要出矿逻辑 + // 出矿按照第一个通道计算 + if (j == 0) { + //total.ntokenValue += value.ntokenValue; + + // 当开通者指定的rewardPerBlock非常大时,计算出矿可能会被截断,导致实际能够得到的出矿大大减少 + // 这种情况是不合理的,需要由开通者负责 + reward += ( + uint(value.mined) + * uint(value.share) + * _reduction(uint(value.height) - uint(channel.genesisBlock), uint(channel.reductionRate)) + * uint(channel.rewardPerBlock) + / uint(value.totalShares) / 400 + ); + } + total.nestNum1k += value.nestNum1k; total.ethNum += value.ethNum; total.tokenValue += value.tokenValue; } @@ -687,27 +703,34 @@ contract NestBatchMining is NestBase, INestBatchMining { _unfreeze(balances, channel.token0, uint(total.ethNum) * uint(channel.unit), accountIndex); // 解冻nest - _unfreeze(balances, NEST_TOKEN_ADDRESS, uint(total.nestValue), accountIndex); + _unfreeze(balances, NEST_TOKEN_ADDRESS, uint(total.nestNum1k) * 1000 ether, accountIndex); uint vault = uint(channel.vault); - uint ntokenValue = uint(total.ntokenValue); - if (ntokenValue > vault) { - ntokenValue = vault; + //uint ntokenValue = uint(total.ntokenValue); + if (reward > vault) { + reward = vault; } // 记录每个通道矿币的数量,防止开通者不打币,直接用资金池内的资金 - channel.vault = uint96(vault - ntokenValue); + channel.vault = uint96(vault - reward); + // if (total.ntokenValue > channel.vault) { + // total.ntokenValue = channel.vault; + // channel.vault = uint96(0); + // } else { + // channel.vault -= total.ntokenValue; + // } + // 奖励矿币 - _unfreeze(balances, channel.reward, ntokenValue, accountIndex); + _unfreeze(balances, channel.reward, reward, accountIndex); } - /// @dev The function updates the statistics of price sheets - /// It calculates from priceInfo to the newest that is effective. - /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 - function stat(uint channelId, uint pairIndex) external override { - PricePair storage pair = _channels[channelId].pairs[pairIndex]; - _stat(_config, pair, pair.sheets); - } + // /// @dev The function updates the statistics of price sheets + // /// It calculates from priceInfo to the newest that is effective. + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // function stat(uint channelId, uint pairIndex) external override { + // PricePair storage pair = _channels[channelId].pairs[pairIndex]; + // _stat(_config, pair, pair.sheets); + // } /// @dev View the number of assets specified by the user /// @param tokenAddress Destination token address @@ -733,14 +756,14 @@ contract NestBatchMining is NestBase, INestBatchMining { TransferHelper.safeTransfer(tokenAddress, msg.sender, value); } + // TODO: 解决出矿计算问题 /// @dev Estimated mining amount /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 /// @return Estimated mining amount - function estimate(uint channelId, uint pairIndex) external view override returns (uint) { + function estimate(uint channelId) external view override returns (uint) { PriceChannel storage channel = _channels[channelId]; - PriceSheet[] storage sheets = channel.pairs[pairIndex].sheets; + PriceSheet[] storage sheets = channel.pairs[0].sheets; uint index = sheets.length; uint blocks = 10; while (index > 0) { @@ -761,17 +784,15 @@ contract NestBatchMining is NestBase, INestBatchMining { /// @dev Query the quantity of the target quotation /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 /// @param index The index of the sheet /// @return minedBlocks Mined block period from previous block /// @return totalShares Total shares of sheets in the block function getMinedBlocks( uint channelId, - uint pairIndex, uint index ) external view override returns (uint minedBlocks, uint totalShares) { - PriceSheet[] storage sheets = _channels[channelId].pairs[pairIndex].sheets; + PriceSheet[] storage sheets = _channels[channelId].pairs[0].sheets; PriceSheet memory sheet = sheets[index]; // The bite sheet or ntoken sheet doesn't mining @@ -785,7 +806,7 @@ contract NestBatchMining is NestBase, INestBatchMining { /// @dev The function returns eth rewards of specified ntoken /// @param channelId 报价通道编号 function totalETHRewards(uint channelId) external view override returns (uint) { - return _channels[channelId].fee; + return _channels[channelId].rewards; } /// @dev Pay @@ -796,7 +817,7 @@ contract NestBatchMining is NestBase, INestBatchMining { PriceChannel storage channel = _channels[channelId]; require(channel.governance == msg.sender, "NOM:!governance"); - channel.fee -= value; + channel.rewards -= value; // pay payable(to).transfer(value); } @@ -808,7 +829,7 @@ contract NestBatchMining is NestBase, INestBatchMining { PriceChannel storage channel = _channels[channelId]; require(channel.governance == msg.sender, "NOM:!governance"); - channel.fee -= value; + channel.rewards -= value; INestLedger(INestMapping(_governance).getNestLedgerAddress()).addETHReward { value: value } (channelId); } @@ -1010,18 +1031,22 @@ contract NestBatchMining is NestBase, INestBatchMining { struct Tuple { uint tokenValue; uint64 ethNum; - uint96 nestValue; - uint96 ntokenValue; + uint24 nestNum1k; + //uint96 ntokenValue; + uint32 mined; + uint32 share; + uint32 totalShares; + uint32 height; } // Close price sheet function _close( Config memory config, PriceSheet[] storage sheets, - uint index, - uint rewardPerBlock, - uint genesisBlock, - uint reductionRate + uint index//, + // uint rewardPerBlock, + // uint genesisBlock, + // uint reductionRate ) private returns (uint accountIndex, Tuple memory value) { PriceSheet memory sheet = sheets[index]; @@ -1038,18 +1063,22 @@ contract NestBatchMining is NestBase, INestBatchMining { // Currently, mined represents the number of blocks has mined (uint mined, uint totalShares) = _calcMinedBlocks(sheets, index, sheet); - // 当开通者指定的rewardPerBlock非常大时,计算出矿可能会被截断,导致实际能够得到的出矿大大减少 - // 这种情况是不合理的,需要由开通者负责 - value.ntokenValue = uint96( - mined - * tmp - * _reduction(height - genesisBlock, reductionRate) - * rewardPerBlock - / totalShares / 400 - ); + // // 当开通者指定的rewardPerBlock非常大时,计算出矿可能会被截断,导致实际能够得到的出矿大大减少 + // // 这种情况是不合理的,需要由开通者负责 + // value.ntokenValue = uint96( + // mined + // * tmp + // * _reduction(height - genesisBlock, reductionRate) + // * rewardPerBlock + // / totalShares / 400 + // ); + value.mined = uint32(mined); + value.share = uint32(tmp); + value.totalShares = uint32(totalShares); + value.height = uint32(height); } - value.nestValue = uint96(uint(sheet.nestNum1k) * 1000 ether); + value.nestNum1k = sheet.nestNum1k; //uint96(uint(sheet.nestNum1k) * 1000 ether); value.ethNum = uint64(sheet.ethNumBal); value.tokenValue = _decodeFloat(sheet.priceFloat) * uint(sheet.tokenNumBal); @@ -1061,6 +1090,7 @@ contract NestBatchMining is NestBase, INestBatchMining { } } + // TODO: 如果有吃单,出矿会减少? // Calculation number of blocks which mined function _calcMinedBlocks( PriceSheet[] storage sheets, @@ -1241,221 +1271,221 @@ contract NestBatchMining is NestBase, INestBatchMining { /* ========== 价格查询 ========== */ - // /// @dev Get the latest trigger price - // /// @param channel 报价通道 - // /// @return blockNumber The block number of price - // /// @return price The token price. (1eth equivalent to (price) token) - // function _triggeredPrice(PriceChannel storage channel) internal view returns (uint blockNumber, uint price) { + /// @dev Get the latest trigger price + /// @param pair 报价对 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function _triggeredPrice(PricePair storage pair) internal view returns (uint blockNumber, uint price) { - // PriceInfo memory priceInfo = channel.price; + PriceInfo memory priceInfo = pair.price; - // if (uint(priceInfo.remainNum) > 0) { - // return (uint(priceInfo.height) + uint(_config.priceEffectSpan), _decodeFloat(priceInfo.priceFloat)); - // } + if (uint(priceInfo.remainNum) > 0) { + return (uint(priceInfo.height) + uint(_config.priceEffectSpan), _decodeFloat(priceInfo.priceFloat)); + } - // return (0, 0); - // } + return (0, 0); + } - // /// @dev Get the full information of latest trigger price - // /// @param channel 报价通道 - // /// @return blockNumber The block number of price - // /// @return price The token price. (1eth equivalent to (price) token) - // /// @return avgPrice Average price - // /// @return sigmaSQ The square of the volatility (18 decimal places). The current implementation assumes that - // /// the volatility cannot exceed 1. Correspondingly, when the return value is equal to 999999999999996447, - // /// it means that the volatility has exceeded the range that can be expressed - // function _triggeredPriceInfo(PriceChannel storage channel) internal view returns ( - // uint blockNumber, - // uint price, - // uint avgPrice, - // uint sigmaSQ - // ) { + /// @dev Get the full information of latest trigger price + /// @param pair 报价对 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + /// @return avgPrice Average price + /// @return sigmaSQ The square of the volatility (18 decimal places). The current implementation assumes that + /// the volatility cannot exceed 1. Correspondingly, when the return value is equal to 999999999999996447, + /// it means that the volatility has exceeded the range that can be expressed + function _triggeredPriceInfo(PricePair storage pair) internal view returns ( + uint blockNumber, + uint price, + uint avgPrice, + uint sigmaSQ + ) { + + PriceInfo memory priceInfo = pair.price; + + if (uint(priceInfo.remainNum) > 0) { + return ( + uint(priceInfo.height) + uint(_config.priceEffectSpan), + _decodeFloat(priceInfo.priceFloat), + _decodeFloat(priceInfo.avgFloat), + (uint(priceInfo.sigmaSQ) * 1 ether) >> 48 + ); + } - // PriceInfo memory priceInfo = channel.price; + return (0, 0, 0, 0); + } - // if (uint(priceInfo.remainNum) > 0) { - // return ( - // uint(priceInfo.height) + uint(_config.priceEffectSpan), - // _decodeFloat(priceInfo.priceFloat), - // _decodeFloat(priceInfo.avgFloat), - // (uint(priceInfo.sigmaSQ) * 1 ether) >> 48 - // ); - // } + /// @dev Find the price at block number + /// @param pair 报价对 + /// @param height Destination block number + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function _findPrice( + PricePair storage pair, + uint height + ) internal view returns (uint blockNumber, uint price) { - // return (0, 0, 0, 0); - // } + PriceSheet[] storage sheets = pair.sheets; + uint priceEffectSpan = uint(_config.priceEffectSpan); - // /// @dev Find the price at block number - // /// @param channel 报价通道 - // /// @param height Destination block number - // /// @return blockNumber The block number of price - // /// @return price The token price. (1eth equivalent to (price) token) - // function _findPrice( - // PriceChannel storage channel, - // uint height - // ) internal view returns (uint blockNumber, uint price) { - - // PriceSheet[] storage sheets = channel.sheets; - // uint priceEffectSpan = uint(_config.priceEffectSpan); - - // uint length = sheets.length; - // uint index = 0; - // uint sheetHeight; - // height -= priceEffectSpan; - // { - // // If there is no sheet in this channel, length is 0, length - 1 will overflow, - // uint right = length - 1; - // uint left = 0; - // // Find the index use Binary Search - // while (left < right) { - - // index = (left + right) >> 1; - // sheetHeight = uint(sheets[index].height); - // if (height > sheetHeight) { - // left = ++index; - // } else if (height < sheetHeight) { - // // When index = 0, this statement will have an underflow exception, which usually - // // indicates that the effective block height passed during the call is lower than - // // the block height of the first quotation - // right = --index; - // } else { - // break; - // } - // } - // } + uint length = sheets.length; + uint index = 0; + uint sheetHeight; + height -= priceEffectSpan; + { + // If there is no sheet in this channel, length is 0, length - 1 will overflow, + uint right = length - 1; + uint left = 0; + // Find the index use Binary Search + while (left < right) { + + index = (left + right) >> 1; + sheetHeight = uint(sheets[index].height); + if (height > sheetHeight) { + left = ++index; + } else if (height < sheetHeight) { + // When index = 0, this statement will have an underflow exception, which usually + // indicates that the effective block height passed during the call is lower than + // the block height of the first quotation + right = --index; + } else { + break; + } + } + } - // // Calculate price - // uint totalEthNum = 0; - // uint totalTokenValue = 0; - // uint h = 0; - // uint remainNum; - // PriceSheet memory sheet; - - // // Find sheets forward - // for (uint i = index; i < length;) { - - // sheet = sheets[i++]; - // sheetHeight = uint(sheet.height); - // if (height < sheetHeight) { - // break; - // } - // remainNum = uint(sheet.remainNum); - // if (remainNum > 0) { - // if (h == 0) { - // h = sheetHeight; - // } else if (h != sheetHeight) { - // break; - // } - // totalEthNum += remainNum; - // totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; - // } - // } + // Calculate price + uint totalEthNum = 0; + uint totalTokenValue = 0; + uint h = 0; + uint remainNum; + PriceSheet memory sheet; - // // Find sheets backward - // while (index > 0) { - - // sheet = sheets[--index]; - // remainNum = uint(sheet.remainNum); - // if (remainNum > 0) { - // sheetHeight = uint(sheet.height); - // if (h == 0) { - // h = sheetHeight; - // } else if (h != sheetHeight) { - // break; - // } - // totalEthNum += remainNum; - // totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; - // } - // } + // Find sheets forward + for (uint i = index; i < length;) { - // if (totalEthNum > 0) { - // return (h + priceEffectSpan, totalTokenValue / totalEthNum); - // } - // return (0, 0); - // } + sheet = sheets[i++]; + sheetHeight = uint(sheet.height); + if (height < sheetHeight) { + break; + } + remainNum = uint(sheet.remainNum); + if (remainNum > 0) { + if (h == 0) { + h = sheetHeight; + } else if (h != sheetHeight) { + break; + } + totalEthNum += remainNum; + totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; + } + } - // /// @dev Get the latest effective price - // /// @param channel 报价通道 - // /// @return blockNumber The block number of price - // /// @return price The token price. (1eth equivalent to (price) token) - // function _latestPrice(PriceChannel storage channel) internal view returns (uint blockNumber, uint price) { - - // PriceSheet[] storage sheets = channel.sheets; - // PriceSheet memory sheet; - - // uint priceEffectSpan = uint(_config.priceEffectSpan); - // //uint h = block.number - priceEffectSpan; - // uint index = sheets.length; - // uint totalEthNum = 0; - // uint totalTokenValue = 0; - // uint height = 0; - - // for (; ; ) { - - // bool flag = index == 0; - // if (flag || height != uint((sheet = sheets[--index]).height)) { - // if (totalEthNum > 0 && height + priceEffectSpan <= block.number) { - // return (height + priceEffectSpan, totalTokenValue / totalEthNum); - // } - // if (flag) { - // break; - // } - // totalEthNum = 0; - // totalTokenValue = 0; - // height = uint(sheet.height); - // } - - // uint remainNum = uint(sheet.remainNum); - // totalEthNum += remainNum; - // totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; - // } + // Find sheets backward + while (index > 0) { - // return (0, 0); - // } + sheet = sheets[--index]; + remainNum = uint(sheet.remainNum); + if (remainNum > 0) { + sheetHeight = uint(sheet.height); + if (h == 0) { + h = sheetHeight; + } else if (h != sheetHeight) { + break; + } + totalEthNum += remainNum; + totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; + } + } - // /// @dev Get the last (num) effective price - // /// @param channel 报价通道 - // /// @param count The number of prices that want to return - // /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price - // function _lastPriceList(PriceChannel storage channel, uint count) internal view returns (uint[] memory) { - - // PriceSheet[] storage sheets = channel.sheets; - // PriceSheet memory sheet; - // uint[] memory array = new uint[](count <<= 1); - - // uint priceEffectSpan = uint(_config.priceEffectSpan); - // //uint h = block.number - priceEffectSpan; - // uint index = sheets.length; - // uint totalEthNum = 0; - // uint totalTokenValue = 0; - // uint height = 0; - - // for (uint i = 0; i < count;) { - - // bool flag = index == 0; - // if (flag || height != uint((sheet = sheets[--index]).height)) { - // if (totalEthNum > 0 && height + priceEffectSpan <= block.number) { - // array[i++] = height + priceEffectSpan; - // array[i++] = totalTokenValue / totalEthNum; - // } - // if (flag) { - // break; - // } - // totalEthNum = 0; - // totalTokenValue = 0; - // height = uint(sheet.height); - // } - - // uint remainNum = uint(sheet.remainNum); - // totalEthNum += remainNum; - // totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; - // } + if (totalEthNum > 0) { + return (h + priceEffectSpan, totalTokenValue / totalEthNum); + } + return (0, 0); + } + + /// @dev Get the latest effective price + /// @param pair 报价对 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function _latestPrice(PricePair storage pair) internal view returns (uint blockNumber, uint price) { + + PriceSheet[] storage sheets = pair.sheets; + PriceSheet memory sheet; + + uint priceEffectSpan = uint(_config.priceEffectSpan); + //uint h = block.number - priceEffectSpan; + uint index = sheets.length; + uint totalEthNum = 0; + uint totalTokenValue = 0; + uint height = 0; + + for (; ; ) { + + bool flag = index == 0; + if (flag || height != uint((sheet = sheets[--index]).height)) { + if (totalEthNum > 0 && height + priceEffectSpan <= block.number) { + return (height + priceEffectSpan, totalTokenValue / totalEthNum); + } + if (flag) { + break; + } + totalEthNum = 0; + totalTokenValue = 0; + height = uint(sheet.height); + } + + uint remainNum = uint(sheet.remainNum); + totalEthNum += remainNum; + totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; + } + + return (0, 0); + } + + /// @dev Get the last (num) effective price + /// @param pair 报价对 + /// @param count The number of prices that want to return + /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + function _lastPriceList(PricePair storage pair, uint count) internal view returns (uint[] memory) { + + PriceSheet[] storage sheets = pair.sheets; + PriceSheet memory sheet; + uint[] memory array = new uint[](count <<= 1); + + uint priceEffectSpan = uint(_config.priceEffectSpan); + //uint h = block.number - priceEffectSpan; + uint index = sheets.length; + uint totalEthNum = 0; + uint totalTokenValue = 0; + uint height = 0; + + for (uint i = 0; i < count;) { - // return array; - // } + bool flag = index == 0; + if (flag || height != uint((sheet = sheets[--index]).height)) { + if (totalEthNum > 0 && height + priceEffectSpan <= block.number) { + array[i++] = height + priceEffectSpan; + array[i++] = totalTokenValue / totalEthNum; + } + if (flag) { + break; + } + totalEthNum = 0; + totalTokenValue = 0; + height = uint(sheet.height); + } + + uint remainNum = uint(sheet.remainNum); + totalEthNum += remainNum; + totalTokenValue += _decodeFloat(sheet.priceFloat) * remainNum; + } + + return array; + } // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() - // /// @param channel 报价通道 + // /// @param pair 报价对 // /// @return latestPriceBlockNumber The block number of latest price // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) // /// @return triggeredPriceBlockNumber The block number of triggered price @@ -1464,7 +1494,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed - // function _latestPriceAndTriggeredPriceInfo(PriceChannel storage channel) internal view + // function _latestPriceAndTriggeredPriceInfo(PricePair storage pair) internal view // returns ( // uint latestPriceBlockNumber, // uint latestPriceValue, @@ -1473,39 +1503,39 @@ contract NestBatchMining is NestBase, INestBatchMining { // uint triggeredAvgPrice, // uint triggeredSigmaSQ // ) { - // (latestPriceBlockNumber, latestPriceValue) = _latestPrice(channel); + // (latestPriceBlockNumber, latestPriceValue) = _latestPrice(pair); // ( // triggeredPriceBlockNumber, // triggeredPriceValue, // triggeredAvgPrice, // triggeredSigmaSQ - // ) = _triggeredPriceInfo(channel); + // ) = _triggeredPriceInfo(pair); // } - // /// @dev Returns lastPriceList and triggered price info - // /// @param channel 报价通道 - // /// @param count The number of prices that want to return - // /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price - // /// @return triggeredPriceBlockNumber The block number of triggered price - // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) - // /// @return triggeredAvgPrice Average price - // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation - // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to - // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed - // function _lastPriceListAndTriggeredPriceInfo(PriceChannel storage channel, uint count) internal view - // returns ( - // uint[] memory prices, - // uint triggeredPriceBlockNumber, - // uint triggeredPriceValue, - // uint triggeredAvgPrice, - // uint triggeredSigmaSQ - // ) { - // prices = _lastPriceList(channel, count); - // ( - // triggeredPriceBlockNumber, - // triggeredPriceValue, - // triggeredAvgPrice, - // triggeredSigmaSQ - // ) = _triggeredPriceInfo(channel); - // } + /// @dev Returns lastPriceList and triggered price info + /// @param pair 报价对 + /// @param count The number of prices that want to return + /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price + /// @return triggeredPriceBlockNumber The block number of triggered price + /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + /// @return triggeredAvgPrice Average price + /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + function _lastPriceListAndTriggeredPriceInfo(PricePair storage pair, uint count) internal view + returns ( + uint[] memory prices, + uint triggeredPriceBlockNumber, + uint triggeredPriceValue, + uint triggeredAvgPrice, + uint triggeredSigmaSQ + ) { + prices = _lastPriceList(pair, count); + ( + triggeredPriceBlockNumber, + triggeredPriceValue, + triggeredAvgPrice, + triggeredSigmaSQ + ) = _triggeredPriceInfo(pair); + } } \ No newline at end of file diff --git a/contracts/interface/INestBatchMining.sol b/contracts/interface/INestBatchMining.sol index aa66977..6932e72 100644 --- a/contracts/interface/INestBatchMining.sol +++ b/contracts/interface/INestBatchMining.sol @@ -138,7 +138,7 @@ interface INestBatchMining { // The information of mining fee // Low 128-bits represent fee per post // High 128-bits represent the current counter of no fee sheets (including settled) - uint fee; + uint rewards; // 计价代币地址, 0表示eth address token0; @@ -245,15 +245,14 @@ interface INestBatchMining { /// @notice Close a batch of price sheets passed VERIFICATION-PHASE /// @dev Empty sheets but in VERIFICATION-PHASE aren't allowed /// @param channelId 报价通道编号 - /// @param pairIndices 报价对编号数组 - /// @param indices A list of indices of sheets w.r.t. `token` - function close(uint channelId, uint[] calldata pairIndices, uint[] calldata indices) external; + /// @param indices 报价单二维数组,外层对应通道号,内层对应报价单号,如果仅关闭后面的报价对,则前面的报价对数组传空数组 + function close(uint channelId, uint[][] calldata indices) external; - /// @dev The function updates the statistics of price sheets - /// It calculates from priceInfo to the newest that is effective. - /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 - function stat(uint channelId, uint pairIndex) external; + // /// @dev The function updates the statistics of price sheets + // /// It calculates from priceInfo to the newest that is effective. + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // function stat(uint channelId, uint pairIndex) external; /// @dev View the number of assets specified by the user /// @param tokenAddress Destination token address @@ -268,19 +267,16 @@ interface INestBatchMining { /// @dev Estimated mining amount /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 /// @return Estimated mining amount - function estimate(uint channelId, uint pairIndex) external view returns (uint); + function estimate(uint channelId) external view returns (uint); /// @dev Query the quantity of the target quotation /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 /// @param index The index of the sheet /// @return minedBlocks Mined block period from previous block /// @return totalShares Total shares of sheets in the block function getMinedBlocks( uint channelId, - uint pairIndex, uint index ) external view returns (uint minedBlocks, uint totalShares); diff --git a/test/17.NestBatchMining.js b/test/17.NestBatchMining.js index 8bc7693..71f747b 100644 --- a/test/17.NestBatchMining.js +++ b/test/17.NestBatchMining.js @@ -116,9 +116,9 @@ describe('NestOpenMining', function() { console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestBatchMining.close(0, 0, [0]); - await nestBatchMining.close(0, 1, [0]); - await nestBatchMining.close(0, 2, [0]); + await nestBatchMining.close(0, [[0], [0], [0]]); + //await nestBatchMining.close(0, 1, [0]); + //await nestBatchMining.close(0, 2, [0]); } if (true) { diff --git a/test/18.NestBatchMining.js b/test/18.NestBatchMining.js index dab61c6..33d58f3 100644 --- a/test/18.NestBatchMining.js +++ b/test/18.NestBatchMining.js @@ -116,7 +116,7 @@ describe('NestOpenMining', function() { console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestBatchMining.close(0, [0, 1], [0]); + await nestBatchMining.close(0, [[0], [0]]); } if (true) { diff --git a/test/19.NestBatchMining.js b/test/19.NestBatchMining.js index af8608e..b65436c 100644 --- a/test/19.NestBatchMining.js +++ b/test/19.NestBatchMining.js @@ -116,7 +116,7 @@ describe('NestOpenMining', function() { console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestBatchMining.close(0, [0], [0]); + await nestBatchMining.close(0, [[0]]); } if (true) { From e2f2890a9b5224acb2a2fd0e62066f679aac364d Mon Sep 17 00:00:00 2001 From: chenf Date: Thu, 9 Dec 2021 11:49:59 +0800 Subject: [PATCH 04/41] Complete Test --- contracts/NestBatchMining.sol | 2 +- contracts/NestBatchPlatform.sol | 290 +++++++++ contracts/interface/INestBatchPrice.sol | 105 ++++ contracts/interface/INestBatchPriceView.sol | 97 +++ scripts/deploy.proxy.js | 4 +- test/0.NestOpenMining-price.js | 83 +-- test/1.NestOpenMining-test.js | 50 +- .../10.NestOpenMining-takeToken1-eth-token.js | 120 ++-- test/11.NestOpenMining-test2.js | 114 ++-- test/12.NestOpenMining-test3.js | 116 ++-- test/13.NestOpenMining-withdraw.js | 566 +++++++++--------- test/14.NestOpenMining-estimate.js | 366 +++++------ test/15.NestOpenMining-private.js | 38 +- test/2.NestOpenMining-post-token-token.js | 60 +- test/3.NestOpenMining-post-token-eth.js | 54 +- test/4.NestOpenMining-post-eth-token.js | 80 +-- ...5.NestOpenMining-takeToken0-token-token.js | 110 ++-- test/6.NestOpenMining-takeToken0-token-eth.js | 92 +-- test/7.NestOpenMining-takeToken0-eth-token.js | 92 +-- ...8.NestOpenMining-takeToken1-token-token.js | 128 ++-- test/9.NestOpenMining-takeToken1-token-eth.js | 108 ++-- test/deploy.js | 4 +- 22 files changed, 1605 insertions(+), 1074 deletions(-) create mode 100644 contracts/NestBatchPlatform.sol create mode 100644 contracts/interface/INestBatchPrice.sol create mode 100644 contracts/interface/INestBatchPriceView.sol diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index 3e117d3..15d9de6 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -673,7 +673,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // TODO: 后面的通道不出矿,不需要出矿逻辑 // 出矿按照第一个通道计算 - if (j == 0) { + if (j == 0 && uint(value.share) > 0) { //total.ntokenValue += value.ntokenValue; // 当开通者指定的rewardPerBlock非常大时,计算出矿可能会被截断,导致实际能够得到的出矿大大减少 diff --git a/contracts/NestBatchPlatform.sol b/contracts/NestBatchPlatform.sol new file mode 100644 index 0000000..42d0f9d --- /dev/null +++ b/contracts/NestBatchPlatform.sol @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.6; + +import "./lib/TransferHelper.sol"; + +import "./interface/INestBatchPriceView.sol"; +import "./interface/INestBatchPrice.sol"; + +import "./NestBatchMining.sol"; + +/// @dev This contract implemented the mining logic of nest +contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPrice { + + // TODO: 支持pairIndex数组,可以一次性查询多个价格 + + /// @dev Get the latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function triggeredPrice(uint channelId, uint pairIndex) external view override noContract returns (uint blockNumber, uint price) { + return _triggeredPrice(_channels[channelId].pairs[pairIndex]); + } + + /// @dev Get the full information of latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + /// @return avgPrice Average price + /// @return sigmaSQ The square of the volatility (18 decimal places). The current implementation assumes that + /// the volatility cannot exceed 1. Correspondingly, when the return value is equal to 999999999999996447, + /// it means that the volatility has exceeded the range that can be expressed + function triggeredPriceInfo(uint channelId, uint pairIndex) external view override noContract returns ( + uint blockNumber, + uint price, + uint avgPrice, + uint sigmaSQ + ) { + return _triggeredPriceInfo(_channels[channelId].pairs[pairIndex]); + } + + /// @dev Find the price at block number + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param height Destination block number + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function findPrice( + uint channelId, + uint pairIndex, + uint height + ) external view override noContract returns (uint blockNumber, uint price) { + return _findPrice(_channels[channelId].pairs[pairIndex], height); + } + + /// @dev Get the latest effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function latestPrice(uint channelId, uint pairIndex) external view override noContract returns (uint blockNumber, uint price) { + return _latestPrice(_channels[channelId].pairs[pairIndex]); + } + + /// @dev Get the last (num) effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + function lastPriceList(uint channelId, uint pairIndex, uint count) external view override noContract returns (uint[] memory) { + return _lastPriceList(_channels[channelId].pairs[pairIndex], count); + } + + // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @return latestPriceBlockNumber The block number of latest price + // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function latestPriceAndTriggeredPriceInfo(uint channelId, uint pairIndex) external view noContract + // returns ( + // uint latestPriceBlockNumber, + // uint latestPriceValue, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ) { + // return _latestPriceAndTriggeredPriceInfo(_channels[channelId].pairs[pairIndex]); + // } + + /// @dev Returns lastPriceList and triggered price info + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price + /// @return triggeredPriceBlockNumber The block number of triggered price + /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + /// @return triggeredAvgPrice Average price + /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + function lastPriceListAndTriggeredPriceInfo(uint channelId, uint pairIndex, uint count) external view override noContract + returns ( + uint[] memory prices, + uint triggeredPriceBlockNumber, + uint triggeredPriceValue, + uint triggeredAvgPrice, + uint triggeredSigmaSQ + ) { + return _lastPriceListAndTriggeredPriceInfo(_channels[channelId].pairs[pairIndex], count); + } + + // Payment of transfer fee + function _pay(PriceChannel storage channel, uint fee, address payback) private { + + fee = fee * DIMI_ETHER; + if (msg.value > fee) { + //payable(payback).transfer(msg.value - fee); + TransferHelper.safeTransferETH(payback, msg.value - fee); + } else { + require(msg.value == fee, "NOP:!fee"); + } + + channel.rewards += fee; + } + + /// @dev Get the latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function triggeredPrice( + uint channelId, + uint pairIndex, + address payback + ) external payable override returns ( + uint blockNumber, + uint price + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + return _triggeredPrice(channel.pairs[pairIndex]); + } + + /// @dev Get the full information of latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + /// @return avgPrice Average price + /// @return sigmaSQ The square of the volatility (18 decimal places). The current implementation assumes that + /// the volatility cannot exceed 1. Correspondingly, when the return value is equal to 999999999999996447, + /// it means that the volatility has exceeded the range that can be expressed + function triggeredPriceInfo( + uint channelId, + uint pairIndex, + address payback + ) external payable override returns ( + uint blockNumber, + uint price, + uint avgPrice, + uint sigmaSQ + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + return _triggeredPriceInfo(channel.pairs[pairIndex]); + } + + /// @dev Find the price at block number + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param height Destination block number + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function findPrice( + uint channelId, + uint pairIndex, + uint height, + address payback + ) external payable override returns ( + uint blockNumber, + uint price + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + return _findPrice(channel.pairs[pairIndex], height); + } + + /// @dev Get the latest effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function latestPrice( + uint channelId, + uint pairIndex, + address payback + ) external payable override returns ( + uint blockNumber, + uint price + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + return _latestPrice(channel.pairs[pairIndex]); + } + + /// @dev Get the last (num) effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + function lastPriceList( + uint channelId, + uint pairIndex, + uint count, + address payback + ) external payable override returns (uint[] memory) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + return _lastPriceList(channel.pairs[pairIndex], count); + } + + // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @param payback 如果费用有多余的,则退回到此地址 + // /// @return latestPriceBlockNumber The block number of latest price + // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function latestPriceAndTriggeredPriceInfo(uint channelId, uint pairIndex, address payback) external payable + // returns ( + // uint latestPriceBlockNumber, + // uint latestPriceValue, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ) { + // PriceChannel storage channel = _channels[channelId]; + // _pay(channel, uint(channel.singleFee), payback); + // return _latestPriceAndTriggeredPriceInfo(channel.pairs[pairIndex]); + // } + + /// @dev Returns lastPriceList and triggered price info + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price + /// @return triggeredPriceBlockNumber The block number of triggered price + /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + /// @return triggeredAvgPrice Average price + /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + function lastPriceListAndTriggeredPriceInfo( + uint channelId, + uint pairIndex, + uint count, + address payback + ) external payable override returns ( + uint[] memory prices, + uint triggeredPriceBlockNumber, + uint triggeredPriceValue, + uint triggeredAvgPrice, + uint triggeredSigmaSQ + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + return _lastPriceListAndTriggeredPriceInfo(channel.pairs[pairIndex], count); + } +} \ No newline at end of file diff --git a/contracts/interface/INestBatchPrice.sol b/contracts/interface/INestBatchPrice.sol new file mode 100644 index 0000000..9389a85 --- /dev/null +++ b/contracts/interface/INestBatchPrice.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.6; + +/// @dev This contract implemented the mining logic of nest +interface INestBatchPrice { + + /// @dev Get the latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function triggeredPrice(uint channelId, uint pairIndex, address payback) external payable returns (uint blockNumber, uint price); + + /// @dev Get the full information of latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + /// @return avgPrice Average price + /// @return sigmaSQ The square of the volatility (18 decimal places). The current implementation assumes that + /// the volatility cannot exceed 1. Correspondingly, when the return value is equal to 999999999999996447, + /// it means that the volatility has exceeded the range that can be expressed + function triggeredPriceInfo(uint channelId, uint pairIndex, address payback) external payable returns ( + uint blockNumber, + uint price, + uint avgPrice, + uint sigmaSQ + ); + + /// @dev Find the price at block number + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param height Destination block number + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function findPrice( + uint channelId, + uint pairIndex, + uint height, + address payback + ) external payable returns (uint blockNumber, uint price); + + /// @dev Get the latest effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function latestPrice(uint channelId, uint pairIndex, address payback) external payable returns (uint blockNumber, uint price); + + /// @dev Get the last (num) effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + function lastPriceList(uint channelId, uint pairIndex, uint count, address payback) external payable returns (uint[] memory); + + // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @param payback 如果费用有多余的,则退回到此地址 + // /// @return latestPriceBlockNumber The block number of latest price + // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function latestPriceAndTriggeredPriceInfo(uint channelId, uint pairIndex, address payback) external payable + // returns ( + // uint latestPriceBlockNumber, + // uint latestPriceValue, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ); + + /// @dev Returns lastPriceList and triggered price info + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price + /// @return triggeredPriceBlockNumber The block number of triggered price + /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + /// @return triggeredAvgPrice Average price + /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + function lastPriceListAndTriggeredPriceInfo(uint channelId, uint pairIndex, uint count, address payback) external payable + returns ( + uint[] memory prices, + uint triggeredPriceBlockNumber, + uint triggeredPriceValue, + uint triggeredAvgPrice, + uint triggeredSigmaSQ + ); +} \ No newline at end of file diff --git a/contracts/interface/INestBatchPriceView.sol b/contracts/interface/INestBatchPriceView.sol new file mode 100644 index 0000000..618710a --- /dev/null +++ b/contracts/interface/INestBatchPriceView.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.6; + +/// @dev This contract implemented the mining logic of nest +interface INestBatchPriceView { + + /// @dev Get the latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function triggeredPrice(uint channelId, uint pairIndex) external view returns (uint blockNumber, uint price); + + /// @dev Get the full information of latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + /// @return avgPrice Average price + /// @return sigmaSQ The square of the volatility (18 decimal places). The current implementation assumes that + /// the volatility cannot exceed 1. Correspondingly, when the return value is equal to 999999999999996447, + /// it means that the volatility has exceeded the range that can be expressed + function triggeredPriceInfo(uint channelId, uint pairIndex) external view returns ( + uint blockNumber, + uint price, + uint avgPrice, + uint sigmaSQ + ); + + /// @dev Find the price at block number + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param height Destination block number + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function findPrice( + uint channelId, + uint pairIndex, + uint height + ) external view returns (uint blockNumber, uint price); + + /// @dev Get the latest effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function latestPrice(uint channelId, uint pairIndex) external view returns (uint blockNumber, uint price); + + /// @dev Get the last (num) effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + function lastPriceList(uint channelId, uint pairIndex, uint count) external view returns (uint[] memory); + + // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @return latestPriceBlockNumber The block number of latest price + // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function latestPriceAndTriggeredPriceInfo(uint channelId) external view + // returns ( + // uint latestPriceBlockNumber, + // uint latestPriceValue, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ); + + /// @dev Returns lastPriceList and triggered price info + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price + /// @return triggeredPriceBlockNumber The block number of triggered price + /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + /// @return triggeredAvgPrice Average price + /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + function lastPriceListAndTriggeredPriceInfo(uint channelId, uint pairIndex, uint count) external view + returns ( + uint[] memory prices, + uint triggeredPriceBlockNumber, + uint triggeredPriceValue, + uint triggeredAvgPrice, + uint triggeredSigmaSQ + ); +} \ No newline at end of file diff --git a/scripts/deploy.proxy.js b/scripts/deploy.proxy.js index 3e41f6a..e90c341 100644 --- a/scripts/deploy.proxy.js +++ b/scripts/deploy.proxy.js @@ -19,7 +19,7 @@ exports.deploy = async function() { const NestGovernance = await ethers.getContractFactory('NestGovernance'); const NestLedger = await ethers.getContractFactory('NestLedger'); const NestOpenMining = await ethers.getContractFactory('NestOpenPlatform'); - const NestBatchMining = await ethers.getContractFactory('NestBatchMining'); + const NestBatchMining = await ethers.getContractFactory('NestBatchPlatform'); const NestVote = await ethers.getContractFactory('NestVote'); console.log('** 开始部署合约 deploy.proxy.js **'); @@ -140,7 +140,7 @@ exports.deploy = async function() { maxBiteNestedLevel: 4, // Price effective block interval. 20 - priceEffectSpan: 50, + priceEffectSpan: 20, // The amount of nest to pledge for each post (Unit: 1000). 100 pledgeNest: 100 diff --git a/test/0.NestOpenMining-price.js b/test/0.NestOpenMining-price.js index 1c7192e..0586651 100644 --- a/test/0.NestOpenMining-price.js +++ b/test/0.NestOpenMining-price.js @@ -11,7 +11,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -54,22 +54,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: hbtc.address, // 计价代币单位 unit: 1000000000000000000n, // 报价代币地址,0表示eth - token1: usdt.address, + //token1: usdt.address, // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -88,9 +88,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: [usdt.address] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); if (false) { @@ -108,10 +110,10 @@ describe('NestOpenMining', function() { if (false) { console.log('2. getConfig'); - let cfg = await nestOpenMining.getConfig(); + let cfg = await nestBatchMining.getConfig(); console.log(UI(cfg)); - await nestOpenMining.setConfig({ + await nestBatchMining.setConfig({ postEthUnit: 10, postFeeUnit: 2000, minerNestReward: 3000, @@ -123,7 +125,7 @@ describe('NestOpenMining', function() { pledgeNest: 900 }); - cfg = await nestOpenMining.getConfig(); + cfg = await nestBatchMining.getConfig(); console.log(UI(cfg)); } @@ -131,18 +133,17 @@ describe('NestOpenMining', function() { const POSTFEE = 0.1; if (true) { console.log('3. post'); - let receipt = await nestOpenMining.post(0, 1, 60000000000n, { + let receipt = await nestBatchMining.post(0, 1, [60000000000n], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT }); await showReceipt(receipt); let status = await showStatus(); } - if (false) { console.log('4. price'); - const np = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + const np = await ethers.getContractAt('INestPriceView', nestBatchMining.address); const test = async function() { console.log(UI(await np.latestPrice(0))); console.log(UI(await np.triggeredPrice(0))); @@ -160,12 +161,12 @@ describe('NestOpenMining', function() { await test(); console.log('触发'); - await nestOpenMining.stat(0); + await nestBatchMining.stat(0); await test(); console.log(); console.log('报新价格'); - await nestOpenMining.post(0, 1, toBigInt(65000, 6), { + await nestBatchMining.post(0, 1, toBigInt(65000, 6), { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT }); @@ -177,7 +178,7 @@ describe('NestOpenMining', function() { await test(); console.log('触发'); - await nestOpenMining.stat(0); + await nestBatchMining.stat(0); await test(); } @@ -185,17 +186,25 @@ describe('NestOpenMining', function() { console.log('4. price'); await showStatus(); - console.log('fee: ' + toDecimal((await nestOpenMining.getChannelInfo(0)).feeInfo)); + console.log('fee: ' + toDecimal((await nestBatchMining.getChannelInfo(0)).rewards)); - const np = await ethers.getContractAt('INestOpenPrice', nestOpenMining.address); + const np = await ethers.getContractAt('INestBatchPrice', nestBatchMining.address); + const nv = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); const test = async function() { const FEE = 0.010; - await np.latestPrice(0, owner.address, { value: toBigInt(FEE) }); - await np.triggeredPrice(0, owner.address, { value: toBigInt(FEE) }); - await np.latestPriceAndTriggeredPriceInfo(0, owner.address, { value: toBigInt(FEE) }); - await np.lastPriceListAndTriggeredPriceInfo(0, 2, owner.address, { value: toBigInt(FEE) }); - await np.lastPriceList(0, 2, owner.address, { value: toBigInt(FEE) }); - await np.findPrice(0, 85, owner.address, { value: toBigInt(FEE) }); + + let pi = await nv.latestPrice(0, 0); + console.log({ + blockNumber: pi.blockNumber.toString(), + price: pi.price.toString() + }); + + await np.latestPrice(0, 0, owner.address, { value: toBigInt(FEE) }); + await np.triggeredPrice(0, 0, owner.address, { value: toBigInt(FEE) }); + //await np.latestPriceAndTriggeredPriceInfo(0, 0, owner.address, { value: toBigInt(FEE) }); + await np.lastPriceListAndTriggeredPriceInfo(0, 0, 2, owner.address, { value: toBigInt(FEE) }); + await np.lastPriceList(0, 0, 2, owner.address, { value: toBigInt(FEE) }); + await np.findPrice(0, 0, 85, owner.address, { value: toBigInt(FEE) }); } console.log('没有等待'); @@ -205,13 +214,13 @@ describe('NestOpenMining', function() { await skipBlocks(20); await test(); - console.log('触发'); - await nestOpenMining.stat(0); - await test(); + // console.log('触发'); + // await nestBatchMining.stat(0); + // await test(); console.log(); console.log('报新价格'); - await nestOpenMining.post(0, 1, toBigInt(65000, 6), { + await nestBatchMining.post(0, 1, [toBigInt(65000, 6)], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT }); @@ -222,12 +231,12 @@ describe('NestOpenMining', function() { await skipBlocks(20); await test(); - console.log('触发'); - await nestOpenMining.stat(0); - await test(); + // console.log('触发'); + // await nestBatchMining.stat(0); + // await test(); await showStatus(); - console.log('fee: ' + toDecimal((await nestOpenMining.getChannelInfo(0)).feeInfo)); + console.log('fee: ' + toDecimal((await nestBatchMining.getChannelInfo(0)).rewards)); } }); }); diff --git a/test/1.NestOpenMining-test.js b/test/1.NestOpenMining-test.js index 2500502..46208c1 100644 --- a/test/1.NestOpenMining-test.js +++ b/test/1.NestOpenMining-test.js @@ -11,7 +11,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -54,22 +54,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: hbtc.address, // 计价代币单位 unit: 1000000000000000000n, // 报价代币地址,0表示eth - token1: usdt.address, + //token1: usdt.address, // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -88,9 +88,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: [usdt.address] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); if (false) { @@ -108,10 +110,10 @@ describe('NestOpenMining', function() { if (false) { console.log('2. getConfig'); - let cfg = await nestOpenMining.getConfig(); + let cfg = await nestBatchMining.getConfig(); console.log(UI(cfg)); - await nestOpenMining.setConfig({ + await nestBatchMining.setConfig({ postEthUnit: 10, postFeeUnit: 2000, minerNestReward: 3000, @@ -123,7 +125,7 @@ describe('NestOpenMining', function() { pledgeNest: 900 }); - cfg = await nestOpenMining.getConfig(); + cfg = await nestBatchMining.getConfig(); console.log(UI(cfg)); } @@ -131,7 +133,7 @@ describe('NestOpenMining', function() { const POSTFEE = 0.1; if (true) { console.log('3. post'); - let receipt = await nestOpenMining.post(0, 1, 60000000000n, { + let receipt = await nestBatchMining.post(0, 1, [60000000000n], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT }); await showReceipt(receipt); @@ -140,30 +142,30 @@ describe('NestOpenMining', function() { if (true) { console.log('4. changeGovernance'); - let ci = await nestOpenMining.getChannelInfo(0); + let ci = await nestBatchMining.getChannelInfo(0); console.log(UI(ci)); console.log('owner: ' + owner.address); expect(ci.governance).to.eq(owner.address); - await nestOpenMining.changeGovernance(0, addr1.address); - ci = await nestOpenMining.getChannelInfo(0); + await nestBatchMining.changeGovernance(0, addr1.address); + ci = await nestBatchMining.getChannelInfo(0); console.log(UI(ci)); console.log('addr1: ' + addr1.address); expect(ci.governance).to.eq(addr1.address); - await nestOpenMining.connect(addr1).changeGovernance(0, owner.address); - ci = await nestOpenMining.getChannelInfo(0); + await nestBatchMining.connect(addr1).changeGovernance(0, owner.address); + ci = await nestBatchMining.getChannelInfo(0); console.log(UI(ci)); expect(ci.governance).to.eq(owner.address); if (true) { console.log('5. pay'); - let rewards = await nestOpenMining.totalETHRewards(0); + let rewards = await nestBatchMining.totalETHRewards(0); console.log('rewards: ' + toDecimal(rewards)); - await nestOpenMining.pay(0, addr1.address, toBigInt(0.1)); + await nestBatchMining.pay(0, addr1.address, toBigInt(0.1)); console.log(await getStatus()); - rewards = await nestOpenMining.totalETHRewards(0); + rewards = await nestBatchMining.totalETHRewards(0); console.log('rewards: ' + toDecimal(rewards)); } } diff --git a/test/10.NestOpenMining-takeToken1-eth-token.js b/test/10.NestOpenMining-takeToken1-eth-token.js index 1670a9a..90d80d9 100644 --- a/test/10.NestOpenMining-takeToken1-eth-token.js +++ b/test/10.NestOpenMining-takeToken1-eth-token.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: usdt.address, // 计价代币单位 unit: 2000000000n, // 报价代币地址,0表示eth - token1: '0x0000000000000000000000000000000000000000', + //token1: '0x0000000000000000000000000000000000000000', // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: ['0x0000000000000000000000000000000000000000'] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, toBigInt(0.46), { + let receipt = await nestBatchMining.post(0, 1, [toBigInt(0.46)], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46) }); await showReceipt(receipt); @@ -111,25 +113,25 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46))); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 1, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 1, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('2. takeToken1'); if (false) { - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(0.1), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(0.1), { value: toBigInt(0) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -142,20 +144,20 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.1 * 2 - 0.46))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(0.5), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(0.5), { value: toBigInt(0.5 * 2 - 0.46) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -168,17 +170,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.5 * 2 - 0.46))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); if (false) { console.log('1. wait 20 and close'); await skipBlocks(50); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); + await nestBatchMining.close(0, [0]); + await nestBatchMining.close(0, [1]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); @@ -189,20 +191,20 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); let list = await nestPrice.lastPriceList(0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ @@ -212,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestOpenMining.takeToken1(0, 1, 2, toBigInt(0.6), { + await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(0.6), { value: toBigInt(0.6 * 4 - 0.5 * 2) }); status = await showStatus(); @@ -225,17 +227,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.5 * 2 - 0.46 + 0.6 * 4 - 0.5 * 2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); console.log('1. wait 20 and close'); await skipBlocks(50); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); - await nestOpenMining.close(0, [2]); + await nestBatchMining.close(0, [[0]]); + await nestBatchMining.close(0, [[1]]); + await nestBatchMining.close(0, [[2]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 - 2000 * 4 - 2000 * 2, 6), 6)); @@ -246,15 +248,15 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000 + 2000 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000 + 2000 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let list = await nestPrice.lastPriceList(0, 0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ bn: list[i].toString(), @@ -266,10 +268,10 @@ describe('NestOpenMining', function() { if (true) { console.log('3. withdraw'); let prev = await showStatus(); - await nestOpenMining.withdraw(usdt.address, toBigInt(2000 + 2000 + 2000 * 4, 6)); - await nestOpenMining.withdraw(nest.address, toBigInt(100000 + 400000 + 10)); - await nestOpenMining.connect(addr1).withdraw(usdt.address, toBigInt(2000 * 4, 6)); - await nestOpenMining.connect(addr1).withdraw(nest.address, toBigInt(200000)); + await nestBatchMining.withdraw(usdt.address, toBigInt(2000 + 2000 + 2000 * 4, 6)); + await nestBatchMining.withdraw(nest.address, toBigInt(100000 + 400000 + 10)); + await nestBatchMining.connect(addr1).withdraw(usdt.address, toBigInt(2000 * 4, 6)); + await nestBatchMining.connect(addr1).withdraw(nest.address, toBigInt(200000)); let now = await showStatus(); @@ -284,11 +286,11 @@ describe('NestOpenMining', function() { }) } - let count = await nestOpenMining.getAccountCount(); + let count = await nestBatchMining.getAccountCount(); console.log('getAccountCount: ' + count); for (var i = 0; i < count; ++i) { - let addr = await nestOpenMining.indexAddress(i); - let idex = await nestOpenMining.getAccountIndex(addr); + let addr = await nestBatchMining.indexAddress(i); + let idex = await nestBatchMining.getAccountIndex(addr); console.log('indexAddress' + i + ': ' + addr + ', ' + idex); } diff --git a/test/11.NestOpenMining-test2.js b/test/11.NestOpenMining-test2.js index 748ed50..e405ef7 100644 --- a/test/11.NestOpenMining-test2.js +++ b/test/11.NestOpenMining-test2.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: usdt.address, // 计价代币单位 unit: 2000000000n, // 报价代币地址,0表示eth - token1: '0x0000000000000000000000000000000000000000', + //token1: '0x0000000000000000000000000000000000000000', // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: ['0x0000000000000000000000000000000000000000'] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, toBigInt(0.46), { + let receipt = await nestBatchMining.post(0, 1, [toBigInt(0.46)], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46) }); await showReceipt(receipt); @@ -111,25 +113,25 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46))); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 1, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 1, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('2. takeToken1'); if (false) { - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(0.1), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(0.1), { value: toBigInt(0) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -142,20 +144,20 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + 1000 + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.1 * 2 - 0.46))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(0.5), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(0.5), { value: toBigInt(0.5 * 2 - 0.46) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -168,17 +170,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.5 * 2 - 0.46))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); if (false) { console.log('1. wait 20 and close'); await skipBlocks(50); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); + await nestBatchMining.close(0, [0]); + await nestBatchMining.close(0, [1]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); @@ -189,20 +191,20 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); let list = await nestPrice.lastPriceList(0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ @@ -212,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestOpenMining.takeToken1(0, 1, 2, toBigInt(0.6), { + await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(0.6), { value: toBigInt(0.6 * 4 - 0.5 * 2) }); status = await showStatus(); @@ -225,20 +227,20 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.5 * 2 - 0.46 + 0.6 * 4 - 0.5 * 2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); console.log('1. wait 20 and close'); - await skipBlocks(50); - // await nestOpenMining.close(0, [0]); - // await nestOpenMining.close(0, [1]); - // await nestOpenMining.close(0, [2]); + await skipBlocks(20); + // await nestBatchMining.close(0, [0]); + // await nestBatchMining.close(0, [1]); + // await nestBatchMining.close(0, [2]); - await nestOpenMining.close(0, [0, 2]); - await nestOpenMining.close(0, [1]); + await nestBatchMining.close(0, [[0, 2]]); + await nestBatchMining.close(0, [[1]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 - 2000 * 4 - 2000 * 2, 6), 6)); @@ -249,15 +251,15 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000 + 2000 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000 + 2000 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let list = await nestPrice.lastPriceList(0, 0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ bn: list[i].toString(), @@ -268,7 +270,7 @@ describe('NestOpenMining', function() { if (true) { console.log('3. list'); - let list = await nestOpenMining.list(0, 1, 2, 1); + let list = await nestBatchMining.list(0, 0, 1, 2, 1); for (var i = 0; i < list.length; ++i) { console.log(UI(list[i])); } diff --git a/test/12.NestOpenMining-test3.js b/test/12.NestOpenMining-test3.js index 0bf77b8..1536ac1 100644 --- a/test/12.NestOpenMining-test3.js +++ b/test/12.NestOpenMining-test3.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: '0x0000000000000000000000000000000000000000', // 计价代币单位 unit: 1000000000000000000n, // 报价代币地址,0表示eth - token1: usdt.address, + //token1: usdt.address, // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: [usdt.address] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, toBigInt(4300, 6), { + let receipt = await nestBatchMining.post(0, 1, [toBigInt(4300, 6)], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1) }); await showReceipt(receipt); @@ -111,25 +113,25 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1))); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 1, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 1, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('2. takeToken1'); if (false) { - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(1501, 6), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(1501, 6), { value: toBigInt(2 + 1) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -142,20 +144,20 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1 + 2 + 1))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4300 - 1501 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4300 - 1501 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(4400, 6), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(4400, 6), { value: toBigInt(2 + 1) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -168,17 +170,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1 + 2 + 1))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); if (false) { console.log('1. wait 20 and close'); await skipBlocks(50); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); + await nestBatchMining.close(0, [0]); + await nestBatchMining.close(0, [1]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 4300, 6), 6)); @@ -189,20 +191,20 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4400 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4400 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); let list = await nestPrice.lastPriceList(0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ @@ -212,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestOpenMining.takeToken1(0, 1, 2, toBigInt(4200, 6), { + await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(4200, 6), { value: toBigInt(2 * 2 + 2) }); status = await showStatus(); @@ -225,17 +227,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1 + 2 + 1 + 2 * 2 + 2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); console.log('1. wait 20 and close'); await skipBlocks(50); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); - await nestOpenMining.close(0, [2]); + await nestBatchMining.close(0, [[0]]); + await nestBatchMining.close(0, [[1]]); + await nestBatchMining.close(0, [[2]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 4300 - 4200 * 4 + 4400 * 2, 6), 6)); @@ -246,15 +248,15 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0 + 4200 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0 + 4200 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let list = await nestPrice.lastPriceList(0, 0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ bn: list[i].toString(), @@ -279,18 +281,18 @@ describe('NestOpenMining', function() { for (var i = 0; i < prices.length; ++i) { await skipBlocks(i); const price = prices[i]; - let receipt = await nestOpenMining.post(0, 1, price, { value: toBigInt(POSTFEE + 1) }); + let receipt = await nestBatchMining.post(0, 1, [price], { value: toBigInt(POSTFEE + 1) }); await showReceipt(receipt); } await skipBlocks(20); - await nestOpenMining.stat(0); + //await nestBatchMining.stat(0); - let nq = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let pi = await nq.triggeredPriceInfo(0); + let nq = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let pi = await nq.triggeredPriceInfo(0, 0); console.log(UI(pi)); - let list = await nestOpenMining.list(0, 0, (await nestOpenMining.list(0, 0, 1, 0))[0].index + 1, 1); + let list = await nestBatchMining.list(0, 0, 0, (await nestBatchMining.list(0, 0, 0, 1, 0))[0].index + 1, 1); for (var i = 0; i < list.length; ++i) { console.log(UI(list[i])); } diff --git a/test/13.NestOpenMining-withdraw.js b/test/13.NestOpenMining-withdraw.js index 12525aa..faff8c4 100644 --- a/test/13.NestOpenMining-withdraw.js +++ b/test/13.NestOpenMining-withdraw.js @@ -1,327 +1,329 @@ -const { expect } = require('chai'); -const { deploy } = require('../scripts/deploy.js'); -const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); +// const { expect } = require('chai'); +// const { deploy } = require('../scripts/deploy.js'); +// const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); -describe('NestOpenMining', function() { - it('First', async function() { - var [owner, addr1, addr2] = await ethers.getSigners(); - const NToken = await ethers.getContractFactory('NToken'); +// describe('NestOpenMining', function() { +// it('First', async function() { +// var [owner, addr1, addr2] = await ethers.getSigners(); +// const NToken = await ethers.getContractFactory('NToken'); - const { - nest, usdt, hbtc, +// const { +// nest, usdt, hbtc, - nestGovernance, nestLedger, - nestMining, nestOpenMining, - nestPriceFacade, nestVote, - nTokenController, nestRedeeming - } = await deploy(); - const nhbtc = await NToken.deploy('NToken001', 'N001'); - await nhbtc.initialize(nestGovernance.address); - await nhbtc.update(nestGovernance.address); +// nestGovernance, nestLedger, +// nestMining, nestBatchMining, +// nestPriceFacade, nestVote, +// nTokenController, nestRedeeming +// } = await deploy(); +// const nhbtc = await NToken.deploy('NToken001', 'N001'); +// await nhbtc.initialize(nestGovernance.address); +// await nhbtc.update(nestGovernance.address); - const getAccountInfo = async function(account) { - let acc = account; - account = account.address; - return { - eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), - usdt: toDecimal(await usdt.balanceOf(account), 6), - hbtc: toDecimal(await hbtc.balanceOf(account), 18), - nhbtc: toDecimal(await nhbtc.balanceOf(account), 18), - nest: toDecimal(await nest.balanceOf(account), 18), - }; - }; - const getStatus = async function() { - return { - height: await ethers.provider.getBlockNumber(), - owner: await getAccountInfo(owner), - addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) - }; - }; +// const getAccountInfo = async function(account) { +// let acc = account; +// account = account.address; +// return { +// eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), +// usdt: toDecimal(await usdt.balanceOf(account), 6), +// hbtc: toDecimal(await hbtc.balanceOf(account), 18), +// nhbtc: toDecimal(await nhbtc.balanceOf(account), 18), +// nest: toDecimal(await nest.balanceOf(account), 18), +// }; +// }; +// const getStatus = async function() { +// return { +// height: await ethers.provider.getBlockNumber(), +// owner: await getAccountInfo(owner), +// addr1: await getAccountInfo(addr1), +// mining: await getAccountInfo(nestBatchMining) +// }; +// }; - const showStatus = async function() { - let status = await getStatus(); - console.log(status); - return status; - } +// const showStatus = async function() { +// let status = await getStatus(); +// console.log(status); +// return status; +// } - const skipBlocks = async function(n) { - for (var i = 0; i < n; ++i) { - await usdt.transfer(owner.address, 0); - } - } +// const skipBlocks = async function(n) { +// for (var i = 0; i < n; ++i) { +// await usdt.transfer(owner.address, 0); +// } +// } - await usdt.transfer(owner.address, 10000000000000n); - await hbtc.transfer(owner.address, 10000000000000000000000000n); - await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); - await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); - await nest.transfer(addr1.address, 1000000000000000000000000000n); - console.log(await getStatus()); +// await usdt.transfer(owner.address, 10000000000000n); +// await hbtc.transfer(owner.address, 10000000000000000000000000n); +// await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); +// await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); +// await nest.transfer(addr1.address, 1000000000000000000000000000n); +// console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); +// await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); +// await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); +// await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); +// await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); +// await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); +// await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - await nestGovernance.setBuiltinAddress( - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', //nestMining.address, - owner.address, //nestMining.address, - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', //nestMining.address, - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000' - ); - await nhbtc.update(nestGovernance.address); - await nhbtc.increaseTotal(1); - await nhbtc.approve(nestOpenMining.address, 1); - await nestGovernance.setBuiltinAddress( - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', //nestMining.address, - nestOpenMining.address, //nestMining.address, - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', //nestMining.address, - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000' - ); - await nhbtc.update(nestGovernance.address); +// await nestGovernance.setBuiltinAddress( +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', //nestMining.address, +// owner.address, //nestMining.address, +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', //nestMining.address, +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000' +// ); +// await nhbtc.update(nestGovernance.address); +// await nhbtc.increaseTotal(1); +// await nhbtc.approve(nestBatchMining.address, 1); +// await nestGovernance.setBuiltinAddress( +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', //nestMining.address, +// nestBatchMining.address, //nestMining.address, +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', //nestMining.address, +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000' +// ); +// await nhbtc.update(nestGovernance.address); - await nestOpenMining.open({ - // 计价代币地址, 0表示eth - token0: usdt.address, - // 计价代币单位 - unit: 2000000000n, +// await nestBatchMining.open({ +// // 计价代币地址, 0表示eth +// token0: usdt.address, +// // 计价代币单位 +// unit: 2000000000n, - // 报价代币地址,0表示eth - token1: '0x0000000000000000000000000000000000000000', - // 每个区块的标准出矿量 - rewardPerBlock: 1000000000000000000n, +// // 报价代币地址,0表示eth +// //token1: '0x0000000000000000000000000000000000000000', +// // 每个区块的标准出矿量 +// rewardPerBlock: 1000000000000000000n, - // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 - // 出矿代币地址 - reward: nhbtc.address, - // 矿币总量 - //uint96 vault; +// // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 +// // 出矿代币地址 +// reward: nhbtc.address, +// // 矿币总量 +// //uint96 vault; - // 管理地址 - //address governance; - // 创世区块 - //uint32 genesisBlock; - // Post fee(0.0001eth,DIMI_ETHER). 1000 - postFeeUnit: 1000, - // Single query fee (0.0001 ether, DIMI_ETHER). 100 - singleFee: 100, - // 衰减系数,万分制。8000 - reductionRate: 8000 - }); - await nestOpenMining.increaseNToken(0, 5000000000000000000000000000n); - console.log(await getStatus()); +// // 管理地址 +// //address governance; +// // 创世区块 +// //uint32 genesisBlock; +// // Post fee(0.0001eth,DIMI_ETHER). 1000 +// postFeeUnit: 1000, +// // Single query fee (0.0001 ether, DIMI_ETHER). 100 +// singleFee: 100, +// // 衰减系数,万分制。8000 +// reductionRate: 8000, - const GASLIMIT = 400000n; - const POSTFEE = 0.1; - const OPEN_FEE = 0; - const EFFECT_BLOCK = 50; +// tokens: ['0x0000000000000000000000000000000000000000'] +// }); +// await nestBatchMining.increaseNToken(0, 5000000000000000000000000000n); +// console.log(await getStatus()); - if (true) { - console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, toBigInt(0.46), { - value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46) - }); - await showReceipt(receipt); - let status = await showStatus(); +// const GASLIMIT = 400000n; +// const POSTFEE = 0.1; +// const OPEN_FEE = 0; +// const EFFECT_BLOCK = 50; - expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); - expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000))); - expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000, 6), 6)); - expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000))); - expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46))); +// if (true) { +// console.log('1. post'); +// let receipt = await nestBatchMining.post(0, 1, [toBigInt(0.46)], { +// value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46) +// }); +// await showReceipt(receipt); +// let status = await showStatus(); + +// expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); +// expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000))); +// expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000, 6), 6)); +// expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000))); +// expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46))); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); +// expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 1, 0); - for (var i = 0; i < sheets.length; ++i) { - console.log(UI(sheets[i])); - } +// console.log('sheets: '); +// let sheets = await nestBatchMining.list(0, 0, 0, 1, 0); +// for (var i = 0; i < sheets.length; ++i) { +// console.log(UI(sheets[i])); +// } - console.log('2. takeToken1'); - if (false) { - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(0.1), { - value: toBigInt(0) - }); - status = await showStatus(); +// console.log('2. takeToken1'); +// if (false) { +// await nestBatchMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(0.1), { +// value: toBigInt(0) +// }); +// status = await showStatus(); - console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); - for (var i = 0; i < sheets.length; ++i) { - console.log(UI(sheets[i])); - } +// console.log('sheets: '); +// sheets = await nestBatchMining.list(0, 0, 2, 0); +// for (var i = 0; i < sheets.length; ++i) { +// console.log(UI(sheets[i])); +// } - expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); - expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000))); - expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); - expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); - expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000, 6), 6)); - expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000))); - expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.1 * 2 - 0.46))); +// expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); +// expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000))); +// expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); +// expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); +// expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000, 6), 6)); +// expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000))); +// expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.1 * 2 - 0.46))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); - return; - } - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(0.5), { - value: toBigInt(0.5 * 2 - 0.46) - }); - status = await showStatus(); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); +// return; +// } +// await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(0.5), { +// value: toBigInt(0.5 * 2 - 0.46) +// }); +// status = await showStatus(); - console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); - for (var i = 0; i < sheets.length; ++i) { - console.log(UI(sheets[i])); - } +// console.log('sheets: '); +// sheets = await nestBatchMining.list(0, 0, 0, 2, 0); +// for (var i = 0; i < sheets.length; ++i) { +// console.log(UI(sheets[i])); +// } - expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); - expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000))); - expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); - expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); - expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000, 6), 6)); - expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000))); - expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.5 * 2 - 0.46))); +// expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); +// expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000))); +// expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); +// expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); +// expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000, 6), 6)); +// expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000))); +// expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.5 * 2 - 0.46))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); - if (false) { - console.log('1. wait 20 and close'); - await skipBlocks(50); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); - status = await showStatus(); +// if (false) { +// console.log('1. wait 20 and close'); +// await skipBlocks(50); +// await nestBatchMining.close(0, [0]); +// await nestBatchMining.close(0, [1]); +// status = await showStatus(); - expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); - expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000))); - expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); - expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); - expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000, 6), 6)); - expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000))); - expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); +// expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); +// expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000))); +// expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); +// expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); +// expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000, 6), 6)); +// expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000))); +// expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000, 6), 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 2, 6), 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); - console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); - for (var i = 0; i < sheets.length; ++i) { - console.log(UI(sheets[i])); - } +// console.log('sheets: '); +// sheets = await nestBatchMining.list(0, 0, 2, 0); +// for (var i = 0; i < sheets.length; ++i) { +// console.log(UI(sheets[i])); +// } - console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); - for (var i = 0; i < list.length; i += 2) { - console.log({ - bn: list[i].toString(), - price: list[i+1].toString() - }); - } - } else { - console.log('2. 吃单链'); - await nestOpenMining.takeToken1(0, 1, 2, toBigInt(0.6), { - value: toBigInt(0.6 * 4 - 0.5 * 2) - }); - status = await showStatus(); +// console.log('price: '); +// let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); +// let list = await nestPrice.lastPriceList(0, 3); +// for (var i = 0; i < list.length; i += 2) { +// console.log({ +// bn: list[i].toString(), +// price: list[i+1].toString() +// }); +// } +// } else { +// console.log('2. 吃单链'); +// await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(0.6), { +// value: toBigInt(0.6 * 4 - 0.5 * 2) +// }); +// status = await showStatus(); - expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 - 2000 * 4 - 2000 * 2, 6), 6)); - expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000 - 400000))); - expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); - expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); - expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000 + 2000 * 4 + 2000 * 2, 6), 6)); - expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000 + 400000))); - expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.5 * 2 - 0.46 + 0.6 * 4 - 0.5 * 2))); +// expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 - 2000 * 4 - 2000 * 2, 6), 6)); +// expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000 - 400000))); +// expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); +// expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); +// expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000 + 2000 * 4 + 2000 * 2, 6), 6)); +// expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000 + 400000))); +// expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46 + 0.5 * 2 - 0.46 + 0.6 * 4 - 0.5 * 2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); - console.log('1. wait 20 and close'); - await skipBlocks(50); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); - await nestOpenMining.close(0, [2]); - status = await showStatus(); +// console.log('1. wait 20 and close'); +// await skipBlocks(50); +// await nestBatchMining.close(0, [[0]]); +// await nestBatchMining.close(0, [[1]]); +// await nestBatchMining.close(0, [[2]]); +// status = await showStatus(); - expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 - 2000 * 4 - 2000 * 2, 6), 6)); - expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000 - 400000))); - expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); - expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); - expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000 + 2000 * 4 + 2000 * 2, 6), 6)); - expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000 + 400000))); - expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); +// expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 - 2000 * 4 - 2000 * 2, 6), 6)); +// expect(status.owner.nest).to.eq(toDecimal(toBigInt(9000000000 - OPEN_FEE - 100000 - 400000))); +// expect(status.addr1.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 * 2 - 2000, 6), 6)); +// expect(status.addr1.nest).to.eq(toDecimal(toBigInt(1000000000 - 200000))); +// expect(status.mining.usdt).to.eq(toDecimal(toBigInt(2000 + 2000 * 2 + 2000 + 2000 * 4 + 2000 * 2, 6), 6)); +// expect(status.mining.nest).to.eq(toDecimal(toBigInt(OPEN_FEE + 100000 + 200000 + 400000))); +// expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000 + 2000 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000))); - expect(toDecimal(await nestOpenMining.balanceOf(nhbtc.address, owner.address))).eq(toDecimal(toBigInt(10))); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 + 2000 + 2000 * 4, 6), 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000))); +// expect(toDecimal(await nestBatchMining.balanceOf(nhbtc.address, owner.address))).eq(toDecimal(toBigInt(10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); - expect(toDecimal(await nestOpenMining.balanceOf(nhbtc.address, addr1.address))).eq(toDecimal(toBigInt(0))); +// expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); +// expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); +// expect(toDecimal(await nestBatchMining.balanceOf(nhbtc.address, addr1.address))).eq(toDecimal(toBigInt(0))); - console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); - for (var i = 0; i < list.length; i += 2) { - console.log({ - bn: list[i].toString(), - price: list[i+1].toString() - }); - } - } +// console.log('price: '); +// let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); +// let list = await nestPrice.lastPriceList(0, 0, 3); +// for (var i = 0; i < list.length; i += 2) { +// console.log({ +// bn: list[i].toString(), +// price: list[i+1].toString() +// }); +// } +// } - if (true) { - console.log('3. withdraw'); - let prev = await showStatus(); - await nestOpenMining.withdraw(usdt.address, toBigInt(2000 + 2000 + 2000 * 4, 6)); - await nestOpenMining.withdraw(nest.address, toBigInt(100000 + 400000)); - await nestOpenMining.withdraw(nhbtc.address, toBigInt(10)); - await nestOpenMining.connect(addr1).withdraw(usdt.address, toBigInt(2000 * 4, 6)); - await nestOpenMining.connect(addr1).withdraw(nest.address, toBigInt(200000)); - await nestOpenMining.connect(addr1).withdraw(nhbtc.address, toBigInt(0)); +// if (true) { +// console.log('3. withdraw'); +// let prev = await showStatus(); +// await nestBatchMining.withdraw(usdt.address, toBigInt(2000 + 2000 + 2000 * 4, 6)); +// await nestBatchMining.withdraw(nest.address, toBigInt(100000 + 400000)); +// await nestBatchMining.withdraw(nhbtc.address, toBigInt(10)); +// await nestBatchMining.connect(addr1).withdraw(usdt.address, toBigInt(2000 * 4, 6)); +// await nestBatchMining.connect(addr1).withdraw(nest.address, toBigInt(200000)); +// await nestBatchMining.connect(addr1).withdraw(nhbtc.address, toBigInt(0)); - let now = await showStatus(); +// let now = await showStatus(); - expect(toDecimal(toBigInt(parseFloat(now.owner.usdt) - parseFloat(prev.owner.usdt), 6), 6)).eq(toDecimal(toBigInt(2000 + 2000 + 2000 * 4, 6), 6)); - expect(toDecimal(toBigInt(parseFloat(now.owner.nest) - parseFloat(prev.owner.nest)))).eq(toDecimal(toBigInt(100000 + 400000))); - expect(toDecimal(toBigInt(parseFloat(now.owner.nhbtc) - parseFloat(prev.owner.nhbtc)))).eq(toDecimal(toBigInt(10))); - expect(toDecimal(toBigInt(parseFloat(now.addr1.usdt) - parseFloat(prev.addr1.usdt), 6), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); - expect(toDecimal(toBigInt(parseFloat(now.addr1.nest) - parseFloat(prev.addr1.nest)))).eq(toDecimal(toBigInt(200000))); - expect(toDecimal(toBigInt(parseFloat(now.addr1.nhbtc) - parseFloat(prev.addr1.nhbtc)))).eq(toDecimal(toBigInt(0))); +// expect(toDecimal(toBigInt(parseFloat(now.owner.usdt) - parseFloat(prev.owner.usdt), 6), 6)).eq(toDecimal(toBigInt(2000 + 2000 + 2000 * 4, 6), 6)); +// expect(toDecimal(toBigInt(parseFloat(now.owner.nest) - parseFloat(prev.owner.nest)))).eq(toDecimal(toBigInt(100000 + 400000))); +// expect(toDecimal(toBigInt(parseFloat(now.owner.nhbtc) - parseFloat(prev.owner.nhbtc)))).eq(toDecimal(toBigInt(10))); +// expect(toDecimal(toBigInt(parseFloat(now.addr1.usdt) - parseFloat(prev.addr1.usdt), 6), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); +// expect(toDecimal(toBigInt(parseFloat(now.addr1.nest) - parseFloat(prev.addr1.nest)))).eq(toDecimal(toBigInt(200000))); +// expect(toDecimal(toBigInt(parseFloat(now.addr1.nhbtc) - parseFloat(prev.addr1.nhbtc)))).eq(toDecimal(toBigInt(0))); - console.log({ - a: toDecimal(toBigInt(parseFloat(now.owner.nest) - parseFloat(prev.owner.nest))), - b: toDecimal(toBigInt(100000 + 400000 + 10)) - }) - } - } - }); -}); +// console.log({ +// a: toDecimal(toBigInt(parseFloat(now.owner.nest) - parseFloat(prev.owner.nest))), +// b: toDecimal(toBigInt(100000 + 400000 + 10)) +// }) +// } +// } +// }); +// }); diff --git a/test/14.NestOpenMining-estimate.js b/test/14.NestOpenMining-estimate.js index a6c903e..133a1cf 100644 --- a/test/14.NestOpenMining-estimate.js +++ b/test/14.NestOpenMining-estimate.js @@ -1,185 +1,187 @@ -const { expect } = require('chai'); -const { deploy } = require('../scripts/deploy.js'); -const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); - -describe('NestOpenMining', function() { - it('First', async function() { - var [owner, addr1, addr2] = await ethers.getSigners(); - const NToken = await ethers.getContractFactory('NToken'); - - const { - nest, usdt, hbtc, - - nestGovernance, nestLedger, - nestMining, nestOpenMining, - nestPriceFacade, nestVote, - nTokenController, nestRedeeming - } = await deploy(); - const nhbtc = await NToken.deploy('NToken001', 'N001'); - await nhbtc.initialize(nestGovernance.address); - await nhbtc.update(nestGovernance.address); - - const getAccountInfo = async function(account) { - let acc = account; - account = account.address; - return { - eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), - usdt: toDecimal(await usdt.balanceOf(account), 6), - hbtc: toDecimal(await hbtc.balanceOf(account), 18), - nhbtc: toDecimal(await nhbtc.balanceOf(account), 18), - nest: toDecimal(await nest.balanceOf(account), 18), - }; - }; - const getStatus = async function() { - return { - height: await ethers.provider.getBlockNumber(), - owner: await getAccountInfo(owner), - addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) - }; - }; - - const showStatus = async function() { - let status = await getStatus(); - console.log(status); - return status; - } - - const skipBlocks = async function(n) { - for (var i = 0; i < n; ++i) { - await usdt.transfer(owner.address, 0); - } - } - - await usdt.transfer(owner.address, 10000000000000n); - await hbtc.transfer(owner.address, 10000000000000000000000000n); - await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); - await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); - await nest.transfer(addr1.address, 1000000000000000000000000000n); - console.log(await getStatus()); - - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - - await nestGovernance.setBuiltinAddress( - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', //nestMining.address, - owner.address, //nestMining.address, - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', //nestMining.address, - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000' - ); - await nhbtc.update(nestGovernance.address); - await nhbtc.increaseTotal(1); - await nhbtc.approve(nestOpenMining.address, 1); - await nestGovernance.setBuiltinAddress( - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', //nestMining.address, - nestOpenMining.address, //nestMining.address, - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', //nestMining.address, - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000' - ); - await nhbtc.update(nestGovernance.address); - - await nestOpenMining.open({ - // 计价代币地址, 0表示eth - token0: usdt.address, - // 计价代币单位 - unit: 2000000000n, +// const { expect } = require('chai'); +// const { deploy } = require('../scripts/deploy.js'); +// const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); + +// describe('NestOpenMining', function() { +// it('First', async function() { +// var [owner, addr1, addr2] = await ethers.getSigners(); +// const NToken = await ethers.getContractFactory('NToken'); + +// const { +// nest, usdt, hbtc, + +// nestGovernance, nestLedger, +// nestMining, nestBatchMining, +// nestPriceFacade, nestVote, +// nTokenController, nestRedeeming +// } = await deploy(); +// const nhbtc = await NToken.deploy('NToken001', 'N001'); +// await nhbtc.initialize(nestGovernance.address); +// await nhbtc.update(nestGovernance.address); + +// const getAccountInfo = async function(account) { +// let acc = account; +// account = account.address; +// return { +// eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), +// usdt: toDecimal(await usdt.balanceOf(account), 6), +// hbtc: toDecimal(await hbtc.balanceOf(account), 18), +// nhbtc: toDecimal(await nhbtc.balanceOf(account), 18), +// nest: toDecimal(await nest.balanceOf(account), 18), +// }; +// }; +// const getStatus = async function() { +// return { +// height: await ethers.provider.getBlockNumber(), +// owner: await getAccountInfo(owner), +// addr1: await getAccountInfo(addr1), +// mining: await getAccountInfo(nestBatchMining) +// }; +// }; + +// const showStatus = async function() { +// let status = await getStatus(); +// console.log(status); +// return status; +// } + +// const skipBlocks = async function(n) { +// for (var i = 0; i < n; ++i) { +// await usdt.transfer(owner.address, 0); +// } +// } + +// await usdt.transfer(owner.address, 10000000000000n); +// await hbtc.transfer(owner.address, 10000000000000000000000000n); +// await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); +// await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); +// await nest.transfer(addr1.address, 1000000000000000000000000000n); +// console.log(await getStatus()); + +// await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); +// await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); +// await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); +// await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); +// await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); +// await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + +// await nestGovernance.setBuiltinAddress( +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', //nestMining.address, +// owner.address, //nestMining.address, +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', //nestMining.address, +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000' +// ); +// await nhbtc.update(nestGovernance.address); +// await nhbtc.increaseTotal(1); +// await nhbtc.approve(nestBatchMining.address, 1); +// await nestGovernance.setBuiltinAddress( +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', //nestMining.address, +// nestBatchMining.address, //nestMining.address, +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000', //nestMining.address, +// '0x0000000000000000000000000000000000000000', +// '0x0000000000000000000000000000000000000000' +// ); +// await nhbtc.update(nestGovernance.address); + +// await nestBatchMining.open({ +// // 计价代币地址, 0表示eth +// token0: usdt.address, +// // 计价代币单位 +// unit: 2000000000n, - // 报价代币地址,0表示eth - token1: '0x0000000000000000000000000000000000000000', - // 每个区块的标准出矿量 - rewardPerBlock: 1000000000000000000n, +// // 报价代币地址,0表示eth +// //token1: '0x0000000000000000000000000000000000000000', +// // 每个区块的标准出矿量 +// rewardPerBlock: 1000000000000000000n, - // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 - // 出矿代币地址 - reward: nhbtc.address, - // 矿币总量 - //uint96 vault; +// // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 +// // 出矿代币地址 +// reward: nhbtc.address, +// // 矿币总量 +// //uint96 vault; - // 管理地址 - //address governance; - // 创世区块 - //uint32 genesisBlock; - // Post fee(0.0001eth,DIMI_ETHER). 1000 - postFeeUnit: 1000, - // Single query fee (0.0001 ether, DIMI_ETHER). 100 - singleFee: 100, - // 衰减系数,万分制。8000 - reductionRate: 8000 - }); - await nestOpenMining.increaseNToken(0, 5000000000000000000000000000n); - console.log(await getStatus()); - - const GASLIMIT = 400000n; - const POSTFEE = 0.1; - const OPEN_FEE = 0; - const EFFECT_BLOCK = 50; - - let prev = BigInt(await nestOpenMining.balanceOf(nhbtc.address, owner.address)); - for (var i = 0; i < 10; ++i) { - if (true) { - console.log('1. post0'); - let es = await nestOpenMining.estimate(0); - let receipt = await nestOpenMining.post(0, 1, toBigInt(0.46), { - value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46) - }); - await showReceipt(receipt); - let status = await showStatus(); - - await skipBlocks(EFFECT_BLOCK); - console.log('(i << 1): ' + (i << 1)) - await nestOpenMining.close(0, [0 + (i << 1)]); - let now = BigInt(await nestOpenMining.balanceOf(nhbtc.address, owner.address)); - let mi = now - prev; - prev = now; - console.log(UI({ - es: toDecimal(es), - mi: toDecimal(mi) - })); - expect(toDecimal(es)).to.eq(toDecimal(mi)); - } - - if (true) { - console.log('2. post1'); - let es = await nestOpenMining.estimate(0); - let receipt = await nestOpenMining.post(0, 1, toBigInt(0.46), { - value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46) - }); - await showReceipt(receipt); - let status = await showStatus(); - - await skipBlocks(EFFECT_BLOCK + 1); - await nestOpenMining.close(0, [1 + (i << 1)]); - let now = BigInt(await nestOpenMining.balanceOf(nhbtc.address, owner.address)); - let mi = now - prev; - prev = now; - console.log(UI({ - es: toDecimal(es), - mi: toDecimal(mi) - })); - expect(toDecimal(es)).to.eq(toDecimal(mi)); - } - } - - let count = (await nestOpenMining.list(0, 0, 1, 0))[0].index + 1; - let list = await nestOpenMining.list(0, 0, count, 0); - for (var i = 0; i < list.length; ++i) { - console.log(UI(await nestOpenMining.getMinedBlocks(0, i))); - } - }); -}); +// // 管理地址 +// //address governance; +// // 创世区块 +// //uint32 genesisBlock; +// // Post fee(0.0001eth,DIMI_ETHER). 1000 +// postFeeUnit: 1000, +// // Single query fee (0.0001 ether, DIMI_ETHER). 100 +// singleFee: 100, +// // 衰减系数,万分制。8000 +// reductionRate: 8000, + +// tokens: ['0x0000000000000000000000000000000000000000'] +// }); +// await nestBatchMining.increaseNToken(0, 5000000000000000000000000000n); +// console.log(await getStatus()); + +// const GASLIMIT = 400000n; +// const POSTFEE = 0.1; +// const OPEN_FEE = 0; +// const EFFECT_BLOCK = 50; + +// let prev = BigInt(await nestBatchMining.balanceOf(nhbtc.address, owner.address)); +// for (var i = 0; i < 10; ++i) { +// if (true) { +// console.log('1. post0'); +// let es = await nestBatchMining.estimate(0); +// let receipt = await nestBatchMining.post(0, 1, toBigInt(0.46), { +// value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46) +// }); +// await showReceipt(receipt); +// let status = await showStatus(); + +// await skipBlocks(EFFECT_BLOCK); +// console.log('(i << 1): ' + (i << 1)) +// await nestBatchMining.close(0, [0 + (i << 1)]); +// let now = BigInt(await nestBatchMining.balanceOf(nhbtc.address, owner.address)); +// let mi = now - prev; +// prev = now; +// console.log(UI({ +// es: toDecimal(es), +// mi: toDecimal(mi) +// })); +// expect(toDecimal(es)).to.eq(toDecimal(mi)); +// } + +// if (true) { +// console.log('2. post1'); +// let es = await nestBatchMining.estimate(0); +// let receipt = await nestBatchMining.post(0, 1, toBigInt(0.46), { +// value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.46) +// }); +// await showReceipt(receipt); +// let status = await showStatus(); + +// await skipBlocks(EFFECT_BLOCK + 1); +// await nestBatchMining.close(0, [1 + (i << 1)]); +// let now = BigInt(await nestBatchMining.balanceOf(nhbtc.address, owner.address)); +// let mi = now - prev; +// prev = now; +// console.log(UI({ +// es: toDecimal(es), +// mi: toDecimal(mi) +// })); +// expect(toDecimal(es)).to.eq(toDecimal(mi)); +// } +// } + +// let count = (await nestBatchMining.list(0, 0, 1, 0))[0].index + 1; +// let list = await nestBatchMining.list(0, 0, count, 0); +// for (var i = 0; i < list.length; ++i) { +// console.log(UI(await nestBatchMining.getMinedBlocks(0, i))); +// } +// }); +// }); diff --git a/test/15.NestOpenMining-private.js b/test/15.NestOpenMining-private.js index 70fa8d0..0ddbc0b 100644 --- a/test/15.NestOpenMining-private.js +++ b/test/15.NestOpenMining-private.js @@ -11,7 +11,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -35,7 +35,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -58,12 +58,12 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); await nestGovernance.setBuiltinAddress( '0x0000000000000000000000000000000000000000', @@ -79,13 +79,13 @@ describe('NestOpenMining', function() { ); await nhbtc.update(nestGovernance.address); await nhbtc.increaseTotal(1); - await nhbtc.approve(nestOpenMining.address, 1); + await nhbtc.approve(nestBatchMining.address, 1); await nestGovernance.setBuiltinAddress( '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', //nestMining.address, - nestOpenMining.address, //nestMining.address, + nestBatchMining.address, //nestMining.address, '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', //nestMining.address, @@ -94,14 +94,14 @@ describe('NestOpenMining', function() { ); await nhbtc.update(nestGovernance.address); - await nestOpenMining.open({ + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: usdt.address, // 计价代币单位 unit: 2000000000n, // 报价代币地址,0表示eth - token1: '0x0000000000000000000000000000000000000000', + //token1: '0x0000000000000000000000000000000000000000', // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -120,21 +120,23 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: ['0x0000000000000000000000000000000000000000'] }); - await nestOpenMining.increaseNToken(0, 5000000000000000000000000000n); + //await nestBatchMining.increaseNToken(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; const POSTFEE = 0.1; - let prev = BigInt(await nestOpenMining.balanceOf(nhbtc.address, owner.address)); + let prev = BigInt(await nestBatchMining.balanceOf(nhbtc.address, owner.address)); const TEST_PRIVATE = false; if (TEST_PRIVATE) { console.log('1. _reduction'); const test = async function(bn, rt) { - let n = await nestOpenMining._reduction(bn, rt); + let n = await nestBatchMining._reduction(bn, rt); console.log('_reduction(' + bn + ', ' + rt + '): ' + n); } @@ -157,8 +159,8 @@ describe('NestOpenMining', function() { if (TEST_PRIVATE) { console.log('1. _encodeFloat'); const test = async function test(n) { - let e = BigInt(await nestOpenMining._encodeFloat(n)); - let d = BigInt(await nestOpenMining._decodeFloat(e)); + let e = BigInt(await nestBatchMining._encodeFloat(n)); + let d = BigInt(await nestBatchMining._decodeFloat(e)); console.log(UI({ n, e, d diff --git a/test/2.NestOpenMining-post-token-token.js b/test/2.NestOpenMining-post-token-token.js index 67166db..c2f2d42 100644 --- a/test/2.NestOpenMining-post-token-token.js +++ b/test/2.NestOpenMining-post-token-token.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: hbtc.address, // 计价代币单位 unit: 1000000000000000000n, // 报价代币地址,0表示eth - token1: usdt.address, + //token1: usdt.address, // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: [usdt.address] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, 60000000000n, { + let receipt = await nestBatchMining.post(0, 1, [60000000000n], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT }); await showReceipt(receipt); @@ -113,18 +115,18 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 2, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('1. close'); - await nestOpenMining.close(0, [0]); + await nestBatchMining.close(0, [[0]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 60000000000n, 6)); expect(status.owner.hbtc).to.eq(toDecimal(10000000000000000000000000n - 1000000000000000000n)); @@ -134,13 +136,13 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); + await nestBatchMining.close(0, [[0]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 60000000000n, 6)); expect(status.owner.hbtc).to.eq(toDecimal(10000000000000000000000000n - 1000000000000000000n)); @@ -150,19 +152,19 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(1000000000000000000n)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(60000000000n, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n + 10000000000000000000n)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(1000000000000000000n)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(60000000000n, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n + 10000000000000000000n)); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let price = await nestPrice.triggeredPriceInfo(0); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let price = await nestPrice.triggeredPriceInfo(0, 0); console.log(UI(price)); } }); diff --git a/test/3.NestOpenMining-post-token-eth.js b/test/3.NestOpenMining-post-token-eth.js index 0b6f641..48b49f1 100644 --- a/test/3.NestOpenMining-post-token-eth.js +++ b/test/3.NestOpenMining-post-token-eth.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: '0x0000000000000000000000000000000000000000', // 计价代币单位 unit: 1000000000000000000n, // 报价代币地址,0表示eth - token1: usdt.address, + //token1: usdt.address, // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: [usdt.address] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, 4300000000n, { + let receipt = await nestBatchMining.post(0, 1, [4300000000n], { value: toBigInt(POSTFEE + 1) + 1000000000n * GASLIMIT }); await showReceipt(receipt); @@ -110,17 +112,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 2, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('1. close'); - await nestOpenMining.close(0, [0]); + await nestBatchMining.close(0, [[0]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 4300000000n, 6)); expect(status.owner.nest).to.eq(toDecimal(4000000000000000000000000000n - OPEN_FEE - 100000000000000000000000n)); @@ -128,12 +130,12 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); + await nestBatchMining.close(0, [[0]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 4300000000n, 6)); expect(status.owner.nest).to.eq(toDecimal(4000000000000000000000000000n - OPEN_FEE - 100000000000000000000000n)); @@ -141,18 +143,18 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(4300000000n, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n + 10000000000000000000n)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(4300000000n, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n + 10000000000000000000n)); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let price = await nestPrice.triggeredPriceInfo(0); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let price = await nestPrice.triggeredPriceInfo(0, 0); console.log(UI(price)); } }); diff --git a/test/4.NestOpenMining-post-eth-token.js b/test/4.NestOpenMining-post-eth-token.js index 185fa64..49882d2 100644 --- a/test/4.NestOpenMining-post-eth-token.js +++ b/test/4.NestOpenMining-post-eth-token.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: usdt.address, // 计价代币单位 unit: 2000000000n, // 报价代币地址,0表示eth - token1: '0x0000000000000000000000000000000000000000', + //token1: '0x0000000000000000000000000000000000000000', // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: ['0x0000000000000000000000000000000000000000'] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (false) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 2, toBigInt(0.465), { + let receipt = await nestBatchMining.post(0, 2, toBigInt(0.465), { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + 2n * toBigInt(0.465) }); await showReceipt(receipt); @@ -110,17 +112,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + 2n * toBigInt(0.465))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 2, 0); + let sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('1. close'); - await nestOpenMining.close(0, [0]); + await nestBatchMining.close(0, [0]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 4000000000n, 6)); expect(status.owner.nest).to.eq(toDecimal(4000000000000000000000000000n - OPEN_FEE - 100000000000000000000000n)); @@ -128,12 +130,12 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + 2n * toBigInt(0.465))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); + await nestBatchMining.close(0, [0]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 4000000000n, 6)); expect(status.owner.nest).to.eq(toDecimal(4000000000000000000000000000n - OPEN_FEE - 100000000000000000000000n)); @@ -141,24 +143,24 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(4000000000n, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n + 10000000000000000000n)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(4000000000n, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n + 10000000000000000000n)); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); let price = await nestPrice.triggeredPriceInfo(0); console.log(UI(price)); } if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, toBigInt(0.465), { + let receipt = await nestBatchMining.post(0, 1, [toBigInt(0.465)], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + 1n * toBigInt(0.465) }); await showReceipt(receipt); @@ -169,17 +171,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + 1n * toBigInt(0.465))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 2, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('1. close'); - await nestOpenMining.close(0, [0]); + await nestBatchMining.close(0, [[0]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 2000000000n, 6)); expect(status.owner.nest).to.eq(toDecimal(4000000000000000000000000000n - OPEN_FEE - 100000000000000000000000n)); @@ -187,12 +189,12 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + 1n * toBigInt(0.465))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); + await nestBatchMining.close(0, [[0]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 2000000000n, 6)); expect(status.owner.nest).to.eq(toDecimal(4000000000000000000000000000n - OPEN_FEE - 100000000000000000000000n)); @@ -200,21 +202,21 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(2000000000n, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n + 10000000000000000000n)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(2000000000n, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n + 10000000000000000000n)); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let price = await nestPrice.triggeredPriceInfo(0); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let price = await nestPrice.triggeredPriceInfo(0, 0); console.log(UI(price)); } - console.log('getAccountCount: ' + await nestOpenMining.getAccountCount()); + console.log('getAccountCount: ' + await nestBatchMining.getAccountCount()); }); }); diff --git a/test/5.NestOpenMining-takeToken0-token-token.js b/test/5.NestOpenMining-takeToken0-token-token.js index 8192ec9..ec94d22 100644 --- a/test/5.NestOpenMining-takeToken0-token-token.js +++ b/test/5.NestOpenMining-takeToken0-token-token.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: hbtc.address, // 计价代币单位 unit: 1000000000000000000n, // 报价代币地址,0表示eth - token1: usdt.address, + //token1: usdt.address, // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: [usdt.address] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, 60000000000n, { + let receipt = await nestBatchMining.post(0, 1, [60000000000n], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT }); await showReceipt(receipt); @@ -113,24 +115,24 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 1, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 1, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('2. takeToken0'); - await nestOpenMining.connect(addr1).takeToken0(0, 0, 1, 70000000000n, { + await nestBatchMining.connect(addr1).takeToken0(0, 0, 0, 1, 70000000000n, { value: 0 }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } @@ -146,19 +148,19 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n + 100000000000000000000000n * 2n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); if (false) { console.log('1. wait 20 and close'); await skipBlocks(20); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); + await nestBatchMining.close(0, [0]); + await nestBatchMining.close(0, [1]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 60000000000n, 6)); @@ -172,22 +174,22 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n + 100000000000000000000000n * 2n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(60000 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n * 1n + 10000000000000000000n)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(0))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(60000 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(100000000000000000000000n * 1n + 10000000000000000000n)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2 * 70000, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(2))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2 * 70000, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); let list = await nestPrice.lastPriceList(0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ @@ -197,7 +199,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestOpenMining.takeToken0(0, 1, 2, 65000000000n); + await nestBatchMining.takeToken0(0, 0, 1, 2, 65000000000n); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 60000000000n - 65000000000n * 4n - 70000000000n * 2n, 6)); @@ -211,19 +213,19 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n + 100000000000000000000000n * 2n + toBigInt(100000 * 4))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(0))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(0))); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(0))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(0))); console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); - await nestOpenMining.close(0, [2]); + await nestBatchMining.close(0, [[0]]); + await nestBatchMining.close(0, [[1]]); + await nestBatchMining.close(0, [[2]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 60000000000n - 65000000000n * 4n - 70000000000n * 2n, 6)); @@ -237,17 +239,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + OPEN_FEE + 100000000000000000000000n + 100000000000000000000000n * 2n + toBigInt(100000 * 4))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(4))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(65000*4+60000*2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(4))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(65000*4+60000*2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(70000 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(0))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(70000 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let list = await nestPrice.lastPriceList(0, 0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ bn: list[i].toString(), diff --git a/test/6.NestOpenMining-takeToken0-token-eth.js b/test/6.NestOpenMining-takeToken0-token-eth.js index 28c0625..1362ef2 100644 --- a/test/6.NestOpenMining-takeToken0-token-eth.js +++ b/test/6.NestOpenMining-takeToken0-token-eth.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: '0x0000000000000000000000000000000000000000', // 计价代币单位 unit: 1000000000000000000n, // 报价代币地址,0表示eth - token1: usdt.address, + //token1: usdt.address, // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: [usdt.address] }); - await nestOpenMining.increase(0, toBigInt(5000000000)); + await nestBatchMining.increase(0, toBigInt(5000000000)); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, toBigInt(4300, 6), { + let receipt = await nestBatchMining.post(0, 1, [toBigInt(4300, 6)], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1) }); await showReceipt(receipt); @@ -111,23 +113,23 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 1, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 1, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('2. takeToken0'); - await nestOpenMining.connect(addr1).takeToken0(0, 0, 1, toBigInt(4400, 6), { + await nestBatchMining.connect(addr1).takeToken0(0, 0, 0, 1, toBigInt(4400, 6), { value: toBigInt(2 - 1) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -140,16 +142,16 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1 + 1))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); if (false) { console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); + await nestBatchMining.close(0, [0]); + await nestBatchMining.close(0, [1]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 4300, 6), 6)); @@ -160,19 +162,19 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(4300 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4400 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(4300 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4400 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); let list = await nestPrice.lastPriceList(0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ @@ -182,7 +184,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestOpenMining.takeToken0(0, 1, 2, toBigInt(4150, 6), { value: toBigInt(2) }); + await nestBatchMining.takeToken0(0, 0, 1, 2, toBigInt(4150, 6), { value: toBigInt(2) }); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 4300 - 4150 * 4 - 4400 * 2, 6), 6)); @@ -193,17 +195,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1 + 1 + 2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(0))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(0))); console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); - await nestOpenMining.close(0, [2]); + await nestBatchMining.close(0, [[0]]); + await nestBatchMining.close(0, [[1]]); + await nestBatchMining.close(0, [[2]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 4300 - 4150 * 4 - 4400 * 2, 6), 6)); @@ -214,15 +216,15 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(4300 * 2 + 4150 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(4300 * 2 + 4150 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4400 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4400 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let list = await nestPrice.lastPriceList(0, 0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ bn: list[i].toString(), diff --git a/test/7.NestOpenMining-takeToken0-eth-token.js b/test/7.NestOpenMining-takeToken0-eth-token.js index 270df0a..8d64d39 100644 --- a/test/7.NestOpenMining-takeToken0-eth-token.js +++ b/test/7.NestOpenMining-takeToken0-eth-token.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: usdt.address, // 计价代币单位 unit: 2000000000n, // 报价代币地址,0表示eth - token1: '0x0000000000000000000000000000000000000000', + //token1: '0x0000000000000000000000000000000000000000', // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: ['0x0000000000000000000000000000000000000000'] }); - await nestOpenMining.increase(0, toBigInt(5000000000)); + await nestBatchMining.increase(0, toBigInt(5000000000)); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, toBigInt(0.459), { + let receipt = await nestBatchMining.post(0, 1, [toBigInt(0.459)], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.459) }); await showReceipt(receipt); @@ -111,23 +113,23 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0.459))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 1, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 1, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('2. takeToken0'); - await nestOpenMining.connect(addr1).takeToken0(0, 0, 1, toBigInt(0.5), { + await nestBatchMining.connect(addr1).takeToken0(0, 0, 0, 1, toBigInt(0.5), { value: toBigInt(0.5 * 2 + 0.459) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -140,16 +142,16 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1.918))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); if (false) { console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); + await nestBatchMining.close(0, [0]); + await nestBatchMining.close(0, [1]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000, 6), 6)); @@ -160,19 +162,19 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(2000 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); let list = await nestPrice.lastPriceList(0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ @@ -182,7 +184,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestOpenMining.takeToken0(0, 1, 2, toBigInt(0.4), { value: toBigInt(0.4 * 4 + 0.5 * 2) }); + await nestBatchMining.takeToken0(0, 0, 1, 2, toBigInt(0.4), { value: toBigInt(0.4 * 4 + 0.5 * 2) }); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 - 2000 * 4 + 2000 * 2, 6), 6)); @@ -193,17 +195,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1.918 + 0.4 * 4 + 0.5 * 2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(0))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(0))); console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); - await nestOpenMining.close(0, [2]); + await nestBatchMining.close(0, [[0]]); + await nestBatchMining.close(0, [[1]]); + await nestBatchMining.close(0, [[2]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 - 2000 * 4 + 2000 * 2, 6), 6)); @@ -214,15 +216,15 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(2000 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let list = await nestPrice.lastPriceList(0, 0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ bn: list[i].toString(), diff --git a/test/8.NestOpenMining-takeToken1-token-token.js b/test/8.NestOpenMining-takeToken1-token-token.js index a83bece..11fb2c3 100644 --- a/test/8.NestOpenMining-takeToken1-token-token.js +++ b/test/8.NestOpenMining-takeToken1-token-token.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: hbtc.address, // 计价代币单位 unit: 1000000000000000000n, // 报价代币地址,0表示eth - token1: usdt.address, + //token1: usdt.address, // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: [usdt.address] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, 60000000000n, { + let receipt = await nestBatchMining.post(0, 1, [60000000000n], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT }); await showReceipt(receipt); @@ -113,25 +115,25 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(5000000000000000000000000000n + toBigInt(OPEN_FEE) + 100000000000000000000000n)); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 1, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 1, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('2. takeToken1'); if (false) { - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(15001, 6), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(15001, 6), { value: 0 }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } @@ -147,22 +149,22 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + 1000 + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(29998, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(29998, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(50000, 6), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(50000, 6), { value: 0 }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } @@ -178,19 +180,19 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); if (false) { console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); + await nestBatchMining.close(0, [0]); + await nestBatchMining.close(0, [1]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 60000000000n, 6)); @@ -204,22 +206,22 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(2))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(50000 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(2))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(50000 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(sheets[i]); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); let list = await nestPrice.lastPriceList(0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ @@ -229,7 +231,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestOpenMining.takeToken1(0, 1, 2, toBigInt(70000, 6)); + await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(70000, 6)); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 60000 - 70000 * 4 + 50000 * 2, 6), 6)); @@ -243,19 +245,19 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); - await nestOpenMining.close(0, [2]); + await nestBatchMining.close(0, [[0]]); + await nestBatchMining.close(0, [[1]]); + await nestBatchMining.close(0, [[2]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 60000 - 70000 * 4 + 50000 * 2, 6), 6)); @@ -269,17 +271,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT)); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(2 + 4))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0 + 4 * 70000, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(toBigInt(2 + 4))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0 + 4 * 70000, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(2 + 2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, addr1.address))).eq(toDecimal(toBigInt(2 + 2))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let list = await nestPrice.lastPriceList(0, 0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ bn: list[i].toString(), @@ -288,7 +290,7 @@ describe('NestOpenMining', function() { } } - console.log('getAccountCount: ' + await nestOpenMining.getAccountCount()); + console.log('getAccountCount: ' + await nestBatchMining.getAccountCount()); } }); }); diff --git a/test/9.NestOpenMining-takeToken1-token-eth.js b/test/9.NestOpenMining-takeToken1-token-eth.js index 5caa428..35f6e21 100644 --- a/test/9.NestOpenMining-takeToken1-token-eth.js +++ b/test/9.NestOpenMining-takeToken1-token-eth.js @@ -10,7 +10,7 @@ describe('NestOpenMining', function() { nest, usdt, hbtc, nestGovernance, nestLedger, - nestMining, nestOpenMining, + nestMining, nestBatchMining, nestPriceFacade, nestVote, nTokenController, nestRedeeming } = await deploy(); @@ -30,7 +30,7 @@ describe('NestOpenMining', function() { height: await ethers.provider.getBlockNumber(), owner: await getAccountInfo(owner), addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestOpenMining) + mining: await getAccountInfo(nestBatchMining) }; }; @@ -53,22 +53,22 @@ describe('NestOpenMining', function() { await nest.transfer(addr1.address, 1000000000000000000000000000n); console.log(await getStatus()); - await nest.approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.approve(nestOpenMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestOpenMining.address, 10000000000000000000000000n); + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestOpenMining.open({ + //await nestBatchMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ // 计价代币地址, 0表示eth token0: '0x0000000000000000000000000000000000000000', // 计价代币单位 unit: 1000000000000000000n, // 报价代币地址,0表示eth - token1: usdt.address, + //token1: usdt.address, // 每个区块的标准出矿量 rewardPerBlock: 1000000000000000000n, @@ -87,9 +87,11 @@ describe('NestOpenMining', function() { // Single query fee (0.0001 ether, DIMI_ETHER). 100 singleFee: 100, // 衰减系数,万分制。8000 - reductionRate: 8000 + reductionRate: 8000, + + tokens: [usdt.address] }); - await nestOpenMining.increase(0, 5000000000000000000000000000n); + await nestBatchMining.increase(0, 5000000000000000000000000000n); console.log(await getStatus()); const GASLIMIT = 400000n; @@ -99,7 +101,7 @@ describe('NestOpenMining', function() { if (true) { console.log('1. post'); - let receipt = await nestOpenMining.post(0, 1, toBigInt(4300, 6), { + let receipt = await nestBatchMining.post(0, 1, [toBigInt(4300, 6)], { value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1) }); await showReceipt(receipt); @@ -111,25 +113,25 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1))); - expect(toDecimal(await nestOpenMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(hbtc.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); console.log('sheets: '); - let sheets = await nestOpenMining.list(0, 0, 1, 0); + let sheets = await nestBatchMining.list(0, 0, 0, 1, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('2. takeToken1'); if (false) { - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(1501, 6), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(1501, 6), { value: toBigInt(2 + 1) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -142,20 +144,20 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1 + 2 + 1))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4300 - 1501 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4300 - 1501 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestOpenMining.connect(addr1).takeToken1(0, 0, 1, toBigInt(4400, 6), { + await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(4400, 6), { value: toBigInt(2 + 1) }); status = await showStatus(); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } @@ -168,17 +170,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1 + 2 + 1))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); if (false) { console.log('1. wait 20 and close'); await skipBlocks(EFFECT_BLOCK); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); + await nestBatchMining.close(0, [0]); + await nestBatchMining.close(0, [1]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 4300, 6), 6)); @@ -189,20 +191,20 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4400 * 2, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(4400 * 2, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('sheets: '); - sheets = await nestOpenMining.list(0, 0, 2, 0); + sheets = await nestBatchMining.list(0, 0, 2, 0); for (var i = 0; i < sheets.length; ++i) { console.log(UI(sheets[i])); } console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); + let nestPrice = await ethers.getContractAt('INestPriceView', nestBatchMining.address); let list = await nestPrice.lastPriceList(0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ @@ -212,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestOpenMining.takeToken1(0, 1, 2, toBigInt(4200, 6), { + await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(4200, 6), { value: toBigInt(2 * 2 + 2) }); status = await showStatus(); @@ -225,17 +227,17 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(1 + 2 + 1 + 2 * 2 + 2))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(0, 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(0)); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); console.log('1. wait 20 and close'); await skipBlocks(50); - await nestOpenMining.close(0, [0]); - await nestOpenMining.close(0, [1]); - await nestOpenMining.close(0, [2]); + await nestBatchMining.close(0, [[0]]); + await nestBatchMining.close(0, [[1]]); + await nestBatchMining.close(0, [[2]]); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 4300 - 4200 * 4 + 4400 * 2, 6), 6)); @@ -246,15 +248,15 @@ describe('NestOpenMining', function() { expect(status.mining.nest).to.eq(toDecimal(toBigInt(5000000000 + OPEN_FEE + 100000 + 200000 + 400000))); expect(status.mining.eth).to.eq(toDecimal(toBigInt(POSTFEE) + 1000000000n * GASLIMIT + toBigInt(0))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0 + 4200 * 4, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, owner.address), 6)).eq(toDecimal(toBigInt(0 + 4200 * 4, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, owner.address))).eq(toDecimal(toBigInt(100000 + 400000 + 10))); - expect(toDecimal(await nestOpenMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); - expect(toDecimal(await nestOpenMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); + expect(toDecimal(await nestBatchMining.balanceOf(usdt.address, addr1.address), 6)).eq(toDecimal(toBigInt(0, 6), 6)); + expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(toBigInt(200000))); console.log('price: '); - let nestPrice = await ethers.getContractAt('INestPriceView', nestOpenMining.address); - let list = await nestPrice.lastPriceList(0, 3); + let nestPrice = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); + let list = await nestPrice.lastPriceList(0, 0, 3); for (var i = 0; i < list.length; i += 2) { console.log({ bn: list[i].toString(), @@ -263,7 +265,7 @@ describe('NestOpenMining', function() { } } - console.log('getAccountCount: ' + await nestOpenMining.getAccountCount()); + console.log('getAccountCount: ' + await nestBatchMining.getAccountCount()); } }); }); diff --git a/test/deploy.js b/test/deploy.js index 275d344..e09191f 100644 --- a/test/deploy.js +++ b/test/deploy.js @@ -49,8 +49,8 @@ describe('NestOpenMining', function() { // reductionRate: 8000 // }); - await nest.approve(nestOpenMining.address, toBigInt(20000000)); - await nestOpenMining.increase(1, toBigInt(20000000)); + //await nest.approve(nestOpenMining.address, toBigInt(20000000)); + //await nestOpenMining.increase(1, toBigInt(20000000)); //console.log(await nest.balanceOf(owner.address) + 'nest'); }); }); From 2fa187a9a8d2247126ab215ade2b274bd2a87813 Mon Sep 17 00:00:00 2001 From: chenf Date: Thu, 9 Dec 2021 15:13:17 +0800 Subject: [PATCH 05/41] Optimize code --- contracts/NestBatchMining.sol | 124 ++++--------- contracts/NestBatchPlatform.sol | 20 +- contracts/NestBatchPlatform2.sol | 308 +++++++++++++++++++++++++++++++ 3 files changed, 360 insertions(+), 92 deletions(-) create mode 100644 contracts/NestBatchPlatform2.sol diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index 15d9de6..ae3e0bb 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -623,22 +623,21 @@ contract NestBatchMining is NestBase, INestBatchMining { //Config memory config = _config; PriceChannel storage channel = _channels[channelId]; - // // Call _closeList() method to close price sheets - // ( - // uint accountIndex, - // Tuple memory total - // ) = _closeList(_config, channel, pair, indices); - - //uint rewardPerBlock = uint(channel.rewardPerBlock); - //uint genesisBlock = uint(channel.genesisBlock); - //uint reductionRate = uint(channel.reductionRate); - uint reward = 0; - uint accountIndex = 0; - // TODO: storage变量必须在定义时初始化,因此在此处赋值,但是由于accountIndex此时为0,此赋值没有意义 - mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; - // TODO: 不用Tuple? - Tuple memory total; + uint reward = 0; + // storage变量必须在定义时初始化,因此在此处赋值,但是由于accountIndex此时为0,此赋值没有意义 + mapping(address=>UINT) storage balances = _accounts[0/*accountIndex*/].balances; + uint[6] memory vars = [ + uint(channel.rewardPerBlock), + uint(channel.genesisBlock), + uint(channel.reductionRate), + // nestNum1k + 0, + // ethNum + 0, + // tokenValue + 0 + ]; for (uint j = indices.length; j > 0;) { PricePair storage pair = channel.pairs[--j]; @@ -651,15 +650,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // Because too many variables need to be returned, too many variables will be defined, // so the structure of tuple is defined - (uint minerIndex, Tuple memory value) = _close( - _config, - sheets, - indices[j][--i]//, - // TODO:优化之 - // rewardPerBlock, - // genesisBlock, - // reductionRate - ); + (uint minerIndex, Tuple memory value) = _close(_config, sheets, indices[j][--i]); // Batch closing quotation can only close sheet of the same user if (accountIndex == 0) { // accountIndex == 0 means the first sheet, and the number of this sheet is taken @@ -671,67 +662,49 @@ contract NestBatchMining is NestBase, INestBatchMining { require(accountIndex == minerIndex, "NM:!miner"); } - // TODO: 后面的通道不出矿,不需要出矿逻辑 + // 后面的通道不出矿,不需要出矿逻辑 // 出矿按照第一个通道计算 if (j == 0 && uint(value.share) > 0) { - //total.ntokenValue += value.ntokenValue; - // 当开通者指定的rewardPerBlock非常大时,计算出矿可能会被截断,导致实际能够得到的出矿大大减少 // 这种情况是不合理的,需要由开通者负责 reward += ( uint(value.mined) * uint(value.share) - * _reduction(uint(value.height) - uint(channel.genesisBlock), uint(channel.reductionRate)) - * uint(channel.rewardPerBlock) + * _reduction(uint(value.height) - vars[1], vars[2]) + * vars[0] / uint(value.totalShares) / 400 ); } - total.nestNum1k += value.nestNum1k; - total.ethNum += value.ethNum; - total.tokenValue += value.tokenValue; + vars[3] += uint(value.nestNum1k); + vars[4] += uint(value.ethNum); + vars[5] += uint(value.tokenValue); } _stat(_config, pair, sheets); /////////////////////////////////////////////////////////////////////////////////////// // 解冻token1 - _unfreeze(balances, pair.target, uint(total.tokenValue), accountIndex); - total.tokenValue = 0; + _unfreeze(balances, pair.target, vars[5], accountIndex); + vars[5] = 0; } // 解冻token0 - _unfreeze(balances, channel.token0, uint(total.ethNum) * uint(channel.unit), accountIndex); + _unfreeze(balances, channel.token0, vars[4] * uint(channel.unit), accountIndex); // 解冻nest - _unfreeze(balances, NEST_TOKEN_ADDRESS, uint(total.nestNum1k) * 1000 ether, accountIndex); + _unfreeze(balances, NEST_TOKEN_ADDRESS, vars[3] * 1000 ether, accountIndex); uint vault = uint(channel.vault); - //uint ntokenValue = uint(total.ntokenValue); if (reward > vault) { reward = vault; } // 记录每个通道矿币的数量,防止开通者不打币,直接用资金池内的资金 channel.vault = uint96(vault - reward); - // if (total.ntokenValue > channel.vault) { - // total.ntokenValue = channel.vault; - // channel.vault = uint96(0); - // } else { - // channel.vault -= total.ntokenValue; - // } // 奖励矿币 _unfreeze(balances, channel.reward, reward, accountIndex); } - // /// @dev The function updates the statistics of price sheets - // /// It calculates from priceInfo to the newest that is effective. - // /// @param channelId 报价通道编号 - // /// @param pairIndex 报价对编号 - // function stat(uint channelId, uint pairIndex) external override { - // PricePair storage pair = _channels[channelId].pairs[pairIndex]; - // _stat(_config, pair, pair.sheets); - // } - /// @dev View the number of assets specified by the user /// @param tokenAddress Destination token address /// @param addr Destination address @@ -1030,13 +1003,12 @@ contract NestBatchMining is NestBase, INestBatchMining { // This structure is for the _close() method to return multiple values struct Tuple { uint tokenValue; - uint64 ethNum; - uint24 nestNum1k; - //uint96 ntokenValue; uint32 mined; uint32 share; uint32 totalShares; uint32 height; + uint32 ethNum; + uint24 nestNum1k; } // Close price sheet @@ -1079,7 +1051,7 @@ contract NestBatchMining is NestBase, INestBatchMining { } value.nestNum1k = sheet.nestNum1k; //uint96(uint(sheet.nestNum1k) * 1000 ether); - value.ethNum = uint64(sheet.ethNumBal); + value.ethNum = sheet.ethNumBal; value.tokenValue = _decodeFloat(sheet.priceFloat) * uint(sheet.tokenNumBal); // Set sheet.miner to 0, express the sheet is closed @@ -1484,26 +1456,25 @@ contract NestBatchMining is NestBase, INestBatchMining { return array; } - // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // /// @dev Returns lastPriceList and triggered price info // /// @param pair 报价对 - // /// @return latestPriceBlockNumber The block number of latest price - // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // /// @param count The number of prices that want to return + // /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price // /// @return triggeredPriceBlockNumber The block number of triggered price // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) // /// @return triggeredAvgPrice Average price // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed - // function _latestPriceAndTriggeredPriceInfo(PricePair storage pair) internal view + // function _lastPriceListAndTriggeredPriceInfo(PricePair storage pair, uint count) internal view // returns ( - // uint latestPriceBlockNumber, - // uint latestPriceValue, + // uint[] memory prices, // uint triggeredPriceBlockNumber, // uint triggeredPriceValue, // uint triggeredAvgPrice, // uint triggeredSigmaSQ // ) { - // (latestPriceBlockNumber, latestPriceValue) = _latestPrice(pair); + // prices = _lastPriceList(pair, count); // ( // triggeredPriceBlockNumber, // triggeredPriceValue, @@ -1511,31 +1482,4 @@ contract NestBatchMining is NestBase, INestBatchMining { // triggeredSigmaSQ // ) = _triggeredPriceInfo(pair); // } - - /// @dev Returns lastPriceList and triggered price info - /// @param pair 报价对 - /// @param count The number of prices that want to return - /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price - /// @return triggeredPriceBlockNumber The block number of triggered price - /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) - /// @return triggeredAvgPrice Average price - /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation - /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to - /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed - function _lastPriceListAndTriggeredPriceInfo(PricePair storage pair, uint count) internal view - returns ( - uint[] memory prices, - uint triggeredPriceBlockNumber, - uint triggeredPriceValue, - uint triggeredAvgPrice, - uint triggeredSigmaSQ - ) { - prices = _lastPriceList(pair, count); - ( - triggeredPriceBlockNumber, - triggeredPriceValue, - triggeredAvgPrice, - triggeredSigmaSQ - ) = _triggeredPriceInfo(pair); - } } \ No newline at end of file diff --git a/contracts/NestBatchPlatform.sol b/contracts/NestBatchPlatform.sol index 42d0f9d..224bd56 100644 --- a/contracts/NestBatchPlatform.sol +++ b/contracts/NestBatchPlatform.sol @@ -115,7 +115,15 @@ contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPr uint triggeredAvgPrice, uint triggeredSigmaSQ ) { - return _lastPriceListAndTriggeredPriceInfo(_channels[channelId].pairs[pairIndex], count); + //return _lastPriceListAndTriggeredPriceInfo(_channels[channelId].pairs[pairIndex], count); + PricePair storage pair = _channels[channelId].pairs[pairIndex]; + prices = _lastPriceList(pair, count); + ( + triggeredPriceBlockNumber, + triggeredPriceValue, + triggeredAvgPrice, + triggeredSigmaSQ + ) = _triggeredPriceInfo(pair); } // Payment of transfer fee @@ -285,6 +293,14 @@ contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPr ) { PriceChannel storage channel = _channels[channelId]; _pay(channel, uint(channel.singleFee), payback); - return _lastPriceListAndTriggeredPriceInfo(channel.pairs[pairIndex], count); + //return _lastPriceListAndTriggeredPriceInfo(channel.pairs[pairIndex], count); + PricePair storage pair = _channels[channelId].pairs[pairIndex]; + prices = _lastPriceList(pair, count); + ( + triggeredPriceBlockNumber, + triggeredPriceValue, + triggeredAvgPrice, + triggeredSigmaSQ + ) = _triggeredPriceInfo(pair); } } \ No newline at end of file diff --git a/contracts/NestBatchPlatform2.sol b/contracts/NestBatchPlatform2.sol new file mode 100644 index 0000000..fe3d4c2 --- /dev/null +++ b/contracts/NestBatchPlatform2.sol @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.6; + +import "./lib/TransferHelper.sol"; + +import "./interface/INestBatchPriceView.sol"; +import "./interface/INestBatchPrice.sol"; + +import "./NestBatchMining.sol"; + +/// @dev This contract implemented the mining logic of nest +contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { + + // TODO: 支持pairIndex数组,可以一次性查询多个价格 + + /// @dev Get the latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function triggeredPrice(uint channelId, uint pairIndex) external view override noContract returns (uint blockNumber, uint price) { + return _triggeredPrice(_channels[channelId].pairs[pairIndex]); + } + + /// @dev Get the full information of latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + /// @return avgPrice Average price + /// @return sigmaSQ The square of the volatility (18 decimal places). The current implementation assumes that + /// the volatility cannot exceed 1. Correspondingly, when the return value is equal to 999999999999996447, + /// it means that the volatility has exceeded the range that can be expressed + function triggeredPriceInfo(uint channelId, uint pairIndex) external view override noContract returns ( + uint blockNumber, + uint price, + uint avgPrice, + uint sigmaSQ + ) { + return _triggeredPriceInfo(_channels[channelId].pairs[pairIndex]); + } + + /// @dev Find the price at block number + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param height Destination block number + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function findPrice( + uint channelId, + uint pairIndex, + uint height + ) external view override noContract returns (uint blockNumber, uint price) { + return _findPrice(_channels[channelId].pairs[pairIndex], height); + } + + /// @dev Get the latest effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function latestPrice(uint channelId, uint pairIndex) external view override noContract returns (uint blockNumber, uint price) { + return _latestPrice(_channels[channelId].pairs[pairIndex]); + } + + /// @dev Get the last (num) effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + function lastPriceList(uint channelId, uint pairIndex, uint count) external view override noContract returns (uint[] memory) { + return _lastPriceList(_channels[channelId].pairs[pairIndex], count); + } + + // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @return latestPriceBlockNumber The block number of latest price + // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function latestPriceAndTriggeredPriceInfo(uint channelId, uint pairIndex) external view noContract + // returns ( + // uint latestPriceBlockNumber, + // uint latestPriceValue, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ) { + // return _latestPriceAndTriggeredPriceInfo(_channels[channelId].pairs[pairIndex]); + // } + + /// @dev Returns lastPriceList and triggered price info + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price + /// @return triggeredPriceBlockNumber The block number of triggered price + /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + /// @return triggeredAvgPrice Average price + /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + function lastPriceListAndTriggeredPriceInfo(uint channelId, uint pairIndex, uint count) external view override noContract + returns ( + uint[] memory prices, + uint triggeredPriceBlockNumber, + uint triggeredPriceValue, + uint triggeredAvgPrice, + uint triggeredSigmaSQ + ) { + //return _lastPriceListAndTriggeredPriceInfo(_channels[channelId].pairs[pairIndex], count); + PricePair storage pair = _channels[channelId].pairs[pairIndex]; + prices = _lastPriceList(pair, count); + ( + triggeredPriceBlockNumber, + triggeredPriceValue, + triggeredAvgPrice, + triggeredSigmaSQ + ) = _triggeredPriceInfo(pair); + } + + // Payment of transfer fee + function _pay(PriceChannel storage channel, uint fee, address payback) private { + + fee = fee * DIMI_ETHER; + if (msg.value > fee) { + //payable(payback).transfer(msg.value - fee); + TransferHelper.safeTransferETH(payback, msg.value - fee); + } else { + require(msg.value == fee, "NOP:!fee"); + } + + channel.rewards += fee; + } + + /// @dev Get the latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 2 为第i个价格所在区块, i * 2 + 1 为第i个价格 + function triggeredPrice( + uint channelId, + uint[] calldata pairIndices, + address payback + ) external payable returns ( + uint[] memory prices + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + + uint n = pairIndices.length << 1; + prices = new uint[](n); + while (n > 0) { + n -= 2; + (prices[n], prices[n + 1]) = _triggeredPrice(channel.pairs[n >> 1]); + } + } + + /// @dev Get the full information of latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 4 为第i个价格所在区块, i * 4 + 1 为第i个价格, i * 4 + 2 为第i个平均价格, i * 4 + 3 为第i个波动率 + function triggeredPriceInfo( + uint channelId, + uint[] calldata pairIndices, + address payback + ) external payable returns ( + uint[] memory prices + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + + uint n = pairIndices.length << 2; + prices = new uint[](n); + while (n > 0) { + n -= 2; + (prices[n], prices[n + 1], prices[n + 2], prices[n + 3]) = _triggeredPriceInfo(channel.pairs[n >> 2]); + } + } + + /// @dev Find the price at block number + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param height Destination block number + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function findPrice( + uint channelId, + uint pairIndex, + uint height, + address payback + ) external payable returns ( + uint blockNumber, + uint price + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + return _findPrice(channel.pairs[pairIndex], height); + } + + /// @dev Get the latest effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return blockNumber The block number of price + /// @return price The token price. (1eth equivalent to (price) token) + function latestPrice( + uint channelId, + uint pairIndex, + address payback + ) external payable returns ( + uint blockNumber, + uint price + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + return _latestPrice(channel.pairs[pairIndex]); + } + + /// @dev Get the last (num) effective price + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + function lastPriceList( + uint channelId, + uint pairIndex, + uint count, + address payback + ) external payable returns (uint[] memory) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + return _lastPriceList(channel.pairs[pairIndex], count); + } + + // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @param payback 如果费用有多余的,则退回到此地址 + // /// @return latestPriceBlockNumber The block number of latest price + // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function latestPriceAndTriggeredPriceInfo(uint channelId, uint pairIndex, address payback) external payable + // returns ( + // uint latestPriceBlockNumber, + // uint latestPriceValue, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ) { + // PriceChannel storage channel = _channels[channelId]; + // _pay(channel, uint(channel.singleFee), payback); + // return _latestPriceAndTriggeredPriceInfo(channel.pairs[pairIndex]); + // } + + /// @dev Returns lastPriceList and triggered price info + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price + /// @return triggeredPriceBlockNumber The block number of triggered price + /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + /// @return triggeredAvgPrice Average price + /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + function lastPriceListAndTriggeredPriceInfo( + uint channelId, + uint pairIndex, + uint count, + address payback + ) external payable returns ( + uint[] memory prices, + uint triggeredPriceBlockNumber, + uint triggeredPriceValue, + uint triggeredAvgPrice, + uint triggeredSigmaSQ + ) { + PriceChannel storage channel = _channels[channelId]; + _pay(channel, uint(channel.singleFee), payback); + //return _lastPriceListAndTriggeredPriceInfo(channel.pairs[pairIndex], count); + PricePair storage pair = _channels[channelId].pairs[pairIndex]; + prices = _lastPriceList(pair, count); + ( + triggeredPriceBlockNumber, + triggeredPriceValue, + triggeredAvgPrice, + triggeredSigmaSQ + ) = _triggeredPriceInfo(pair); + } +} \ No newline at end of file From 27885d98ce70d15e03a935826461564741688630 Mon Sep 17 00:00:00 2001 From: chenf Date: Thu, 9 Dec 2021 15:45:40 +0800 Subject: [PATCH 06/41] Merger takeToken0 and takeToken1 --- contracts/NestBatchMining.sol | 312 ++++++++++++------ contracts/interface/INestBatchMining.sol | 31 +- .../10.NestOpenMining-takeToken1-eth-token.js | 4 +- test/11.NestOpenMining-test2.js | 4 +- test/12.NestOpenMining-test3.js | 4 +- ...5.NestOpenMining-takeToken0-token-token.js | 4 +- test/6.NestOpenMining-takeToken0-token-eth.js | 4 +- test/7.NestOpenMining-takeToken0-eth-token.js | 4 +- ...8.NestOpenMining-takeToken1-token-token.js | 4 +- test/9.NestOpenMining-takeToken1-token-eth.js | 4 +- 10 files changed, 247 insertions(+), 128 deletions(-) diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index ae3e0bb..80fe766 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -389,14 +389,105 @@ contract NestBatchMining is NestBase, INestBatchMining { } } + // /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet + // /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @param index The position of the sheet in priceSheetList[token] + // /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth + // /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth + // function takeToken0(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { + + // Config memory config = _config; + + // // 1. Check arguments + // require(takeNum > 0, "NM:!takeNum"); + // require(newEquivalent > 0, "NM:!price"); + + // // 2. Load price sheet + // PriceChannel storage channel = _channels[channelId]; + // PricePair storage pair = channel.pairs[pairIndex]; + // PriceSheet[] storage sheets = pair.sheets; + // PriceSheet memory sheet = sheets[index]; + + // // 3. Check state + // require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); + // require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); + + // uint accountIndex = _addressIndex(msg.sender); + // // Number of nest to be pledged + // //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); + // // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum + // uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); + + // // 4. Deposit fee + // // 5. Calculate the number of eth, token and nest needed, and freeze them + // uint needEthNum; + // { + // uint level = uint(sheet.level); + + // // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled + // if (level < uint(config.maxBiteNestedLevel)) { + // // Double scale sheet + // needEthNum = takeNum << 1; + // ++level; + // } + // // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not + // else { + // // Single scale sheet + // needEthNum = takeNum; + // // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 + // // or more, there is no logical dependence on the specific value of the contract, and the count will + // // not increase after it is accumulated to 255 + // if (level < 255) ++level; + // } + + // // 7. Calculate the price + // // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price + // // is placed before the sheet is added, which can reduce unnecessary traversal + // _stat(config, pair, sheets); + + // // 8. Create price sheet + // //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); + // _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); + // } + + // // Freeze nest and token + // { + // // 冻结资产:token0, token1, nest + // mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + // uint fee = msg.value; + + // // 冻结nest + // fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); + // // 冻结token0 + // fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); + // // 冻结token1 + // fee = _freeze( + // balances, + // pair.target, + // needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, + // fee + // ); + + // require(fee == 0, "NOM:!fee"); + // } + + // // 6. Update the bitten sheet + // sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); + // sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); + // sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); + // sheets[index] = sheet; + // } + /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 + /// @param pairIndex 报价对编号。当吃单方向为拿走计价代币时,直接传报价对编号,当吃单方向为拿走报价代币时,传报价对编号减65536 /// @param index The position of the sheet in priceSheetList[token] /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth - function takeToken0(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { + function take(uint channelId, int pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { Config memory config = _config; @@ -406,7 +497,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // 2. Load price sheet PriceChannel storage channel = _channels[channelId]; - PricePair storage pair = channel.pairs[pairIndex]; + PricePair storage pair = channel.pairs[uint(pairIndex < 0 ? pairIndex + 0xFFFF : pairIndex)]; PriceSheet[] storage sheets = pair.sheets; PriceSheet memory sheet = sheets[index]; @@ -436,7 +527,7 @@ contract NestBatchMining is NestBase, INestBatchMining { else { // Single scale sheet needEthNum = takeNum; - // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 + // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 // or more, there is no logical dependence on the specific value of the contract, and the count will // not increase after it is accumulated to 255 if (level < 255) ++level; @@ -458,115 +549,134 @@ contract NestBatchMining is NestBase, INestBatchMining { mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; uint fee = msg.value; - // 冻结token0 - fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); - // 冻结token1 - fee = _freeze( - balances, - pair.target, - needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, - fee - ); // 冻结nest fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); + if (pairIndex >= 0) { + // 冻结token0 + fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); + // 冻结token1 + fee = _freeze( + balances, + pair.target, + needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, + fee + ); + + sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); + sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); + } else { + // 冻结token0 + fee = _freeze(balances, channel.token0, (needEthNum + takeNum) * uint(channel.unit), fee); + // 冻结token1 + uint backTokenValue = _decodeFloat(sheet.priceFloat) * takeNum; + if (needEthNum * newEquivalent > backTokenValue) { + fee = _freeze(balances, pair.target, needEthNum * newEquivalent - backTokenValue, fee); + } else { + _unfreeze(balances, pair.target, backTokenValue - needEthNum * newEquivalent, msg.sender); + } + + sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); + sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); + } + require(fee == 0, "NOM:!fee"); } // 6. Update the bitten sheet sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); - sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); - sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); sheets[index] = sheet; } - /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet - /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) - /// @param channelId The address of token(ntoken) - /// @param pairIndex 报价对编号 - /// @param index The position of the sheet in priceSheetList[token] - /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth - /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth - function takeToken1(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { - - Config memory config = _config; - - // 1. Check arguments - require(takeNum > 0, "NM:!takeNum"); - require(newEquivalent > 0, "NM:!price"); - - // 2. Load price sheet - PriceChannel storage channel = _channels[channelId]; - PricePair storage pair = channel.pairs[pairIndex]; - PriceSheet[] storage sheets = pair.sheets; - PriceSheet memory sheet = sheets[index]; - - // 3. Check state - require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); - require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); - - uint accountIndex = _addressIndex(msg.sender); - // Number of nest to be pledged - //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); - // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum - uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); - - // 4. Deposit fee - // 5. Calculate the number of eth, token and nest needed, and freeze them - uint needEthNum; - { - uint level = uint(sheet.level); - - // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled - if (level < uint(config.maxBiteNestedLevel)) { - // Double scale sheet - needEthNum = takeNum << 1; - ++level; - } - // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not - else { - // Single scale sheet - needEthNum = takeNum; - // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 - // or more, there is no logical dependence on the specific value of the contract, and the count will - // not increase after it is accumulated to 255 - if (level < 255) ++level; - } - - // 7. Calculate the price - // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price - // is placed before the sheet is added, which can reduce unnecessary traversal - _stat(config, pair, sheets); - - // 8. Create price sheet - //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); - _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); - } - - // Freeze nest and token - { - // 冻结资产:token0, token1, nest - mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + // /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet + // /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) + // /// @param channelId The address of token(ntoken) + // /// @param pairIndex 报价对编号 + // /// @param index The position of the sheet in priceSheetList[token] + // /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth + // /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth + // function takeToken1(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { + + // Config memory config = _config; + + // // 1. Check arguments + // require(takeNum > 0, "NM:!takeNum"); + // require(newEquivalent > 0, "NM:!price"); + + // // 2. Load price sheet + // PriceChannel storage channel = _channels[channelId]; + // PricePair storage pair = channel.pairs[pairIndex]; + // PriceSheet[] storage sheets = pair.sheets; + // PriceSheet memory sheet = sheets[index]; + + // // 3. Check state + // require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); + // require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); + + // uint accountIndex = _addressIndex(msg.sender); + // // Number of nest to be pledged + // //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); + // // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum + // uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); + + // // 4. Deposit fee + // // 5. Calculate the number of eth, token and nest needed, and freeze them + // uint needEthNum; + // { + // uint level = uint(sheet.level); + + // // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled + // if (level < uint(config.maxBiteNestedLevel)) { + // // Double scale sheet + // needEthNum = takeNum << 1; + // ++level; + // } + // // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not + // else { + // // Single scale sheet + // needEthNum = takeNum; + // // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 + // // or more, there is no logical dependence on the specific value of the contract, and the count will + // // not increase after it is accumulated to 255 + // if (level < 255) ++level; + // } + + // // 7. Calculate the price + // // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price + // // is placed before the sheet is added, which can reduce unnecessary traversal + // _stat(config, pair, sheets); + + // // 8. Create price sheet + // //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); + // _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); + // } - uint fee = msg.value; - // 冻结token0 - fee = _freeze(balances, channel.token0, (needEthNum + takeNum) * uint(channel.unit), fee); - // 冻结token1 - uint backTokenValue = _decodeFloat(sheet.priceFloat) * takeNum; - if (needEthNum * newEquivalent > backTokenValue) { - fee = _freeze(balances, pair.target, needEthNum * newEquivalent - backTokenValue, fee); - } else { - _unfreeze(balances, pair.target, backTokenValue - needEthNum * newEquivalent, msg.sender); - } - fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); - require(fee == 0, "NOM:!fee"); - } + // // Freeze nest and token + // { + // // 冻结资产:token0, token1, nest + // mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; + // uint fee = msg.value; + + // // 冻结nest + // fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); + // // 冻结token0 + // fee = _freeze(balances, channel.token0, (needEthNum + takeNum) * uint(channel.unit), fee); + // // 冻结token1 + // uint backTokenValue = _decodeFloat(sheet.priceFloat) * takeNum; + // if (needEthNum * newEquivalent > backTokenValue) { + // fee = _freeze(balances, pair.target, needEthNum * newEquivalent - backTokenValue, fee); + // } else { + // _unfreeze(balances, pair.target, backTokenValue - needEthNum * newEquivalent, msg.sender); + // } + + // require(fee == 0, "NOM:!fee"); + // } - // 6. Update the bitten sheet - sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); - sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); - sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); - sheets[index] = sheet; - } + // // 6. Update the bitten sheet + // sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); + // sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); + // sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); + // sheets[index] = sheet; + // } /// @dev List sheets by page /// @param channelId 报价通道编号 diff --git a/contracts/interface/INestBatchMining.sol b/contracts/interface/INestBatchMining.sol index 6932e72..835b6a5 100644 --- a/contracts/interface/INestBatchMining.sol +++ b/contracts/interface/INestBatchMining.sol @@ -215,23 +215,32 @@ interface INestBatchMining { /// @param equivalent 与单位token0等价的token1数量 function post(uint channelId, uint scale, uint[] calldata equivalent) external payable; - /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet - /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) - /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 - /// @param index The position of the sheet in priceSheetList[token] - /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth - /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth - function takeToken0(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable; + // /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet + // /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @param index The position of the sheet in priceSheetList[token] + // /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth + // /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth + // function takeToken0(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable; + + // /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet + // /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) + // /// @param channelId The address of token(ntoken) + // /// @param pairIndex 报价对编号 + // /// @param index The position of the sheet in priceSheetList[token] + // /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth + // /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth + // function takeToken1(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable; /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) - /// @param channelId The address of token(ntoken) - /// @param pairIndex 报价对编号 + /// @param channelId 报价通道编号 + /// @param pairIndex 报价对编号。当吃单方向为拿走计价代币时,直接传报价对编号,当吃单方向为拿走报价代币时,传报价对编号减65536 /// @param index The position of the sheet in priceSheetList[token] /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth - function takeToken1(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable; + function take(uint channelId, int pairIndex, uint index, uint takeNum, uint newEquivalent) external payable; /// @dev List sheets by page /// @param channelId 报价通道编号 diff --git a/test/10.NestOpenMining-takeToken1-eth-token.js b/test/10.NestOpenMining-takeToken1-eth-token.js index 90d80d9..67559e9 100644 --- a/test/10.NestOpenMining-takeToken1-eth-token.js +++ b/test/10.NestOpenMining-takeToken1-eth-token.js @@ -151,7 +151,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(0.5), { + await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(0.5), { value: toBigInt(0.5 * 2 - 0.46) }); status = await showStatus(); @@ -214,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(0.6), { + await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(0.6), { value: toBigInt(0.6 * 4 - 0.5 * 2) }); status = await showStatus(); diff --git a/test/11.NestOpenMining-test2.js b/test/11.NestOpenMining-test2.js index e405ef7..1bbf92d 100644 --- a/test/11.NestOpenMining-test2.js +++ b/test/11.NestOpenMining-test2.js @@ -151,7 +151,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(0.5), { + await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(0.5), { value: toBigInt(0.5 * 2 - 0.46) }); status = await showStatus(); @@ -214,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(0.6), { + await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(0.6), { value: toBigInt(0.6 * 4 - 0.5 * 2) }); status = await showStatus(); diff --git a/test/12.NestOpenMining-test3.js b/test/12.NestOpenMining-test3.js index 1536ac1..1da0daa 100644 --- a/test/12.NestOpenMining-test3.js +++ b/test/12.NestOpenMining-test3.js @@ -151,7 +151,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(4400, 6), { + await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(4400, 6), { value: toBigInt(2 + 1) }); status = await showStatus(); @@ -214,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(4200, 6), { + await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(4200, 6), { value: toBigInt(2 * 2 + 2) }); status = await showStatus(); diff --git a/test/5.NestOpenMining-takeToken0-token-token.js b/test/5.NestOpenMining-takeToken0-token-token.js index ec94d22..e33e84c 100644 --- a/test/5.NestOpenMining-takeToken0-token-token.js +++ b/test/5.NestOpenMining-takeToken0-token-token.js @@ -126,7 +126,7 @@ describe('NestOpenMining', function() { } console.log('2. takeToken0'); - await nestBatchMining.connect(addr1).takeToken0(0, 0, 0, 1, 70000000000n, { + await nestBatchMining.connect(addr1).take(0, 0, 0, 1, 70000000000n, { value: 0 }); status = await showStatus(); @@ -199,7 +199,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.takeToken0(0, 0, 1, 2, 65000000000n); + await nestBatchMining.take(0, 0, 1, 2, 65000000000n); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(10000000000000n - 60000000000n - 65000000000n * 4n - 70000000000n * 2n, 6)); diff --git a/test/6.NestOpenMining-takeToken0-token-eth.js b/test/6.NestOpenMining-takeToken0-token-eth.js index 1362ef2..9bf596f 100644 --- a/test/6.NestOpenMining-takeToken0-token-eth.js +++ b/test/6.NestOpenMining-takeToken0-token-eth.js @@ -123,7 +123,7 @@ describe('NestOpenMining', function() { } console.log('2. takeToken0'); - await nestBatchMining.connect(addr1).takeToken0(0, 0, 0, 1, toBigInt(4400, 6), { + await nestBatchMining.connect(addr1).take(0, 0, 0, 1, toBigInt(4400, 6), { value: toBigInt(2 - 1) }); status = await showStatus(); @@ -184,7 +184,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.takeToken0(0, 0, 1, 2, toBigInt(4150, 6), { value: toBigInt(2) }); + await nestBatchMining.take(0, 0, 1, 2, toBigInt(4150, 6), { value: toBigInt(2) }); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 4300 - 4150 * 4 - 4400 * 2, 6), 6)); diff --git a/test/7.NestOpenMining-takeToken0-eth-token.js b/test/7.NestOpenMining-takeToken0-eth-token.js index 8d64d39..95a3665 100644 --- a/test/7.NestOpenMining-takeToken0-eth-token.js +++ b/test/7.NestOpenMining-takeToken0-eth-token.js @@ -123,7 +123,7 @@ describe('NestOpenMining', function() { } console.log('2. takeToken0'); - await nestBatchMining.connect(addr1).takeToken0(0, 0, 0, 1, toBigInt(0.5), { + await nestBatchMining.connect(addr1).take(0, 0, 0, 1, toBigInt(0.5), { value: toBigInt(0.5 * 2 + 0.459) }); status = await showStatus(); @@ -184,7 +184,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.takeToken0(0, 0, 1, 2, toBigInt(0.4), { value: toBigInt(0.4 * 4 + 0.5 * 2) }); + await nestBatchMining.take(0, 0, 1, 2, toBigInt(0.4), { value: toBigInt(0.4 * 4 + 0.5 * 2) }); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 2000 - 2000 * 4 + 2000 * 2, 6), 6)); diff --git a/test/8.NestOpenMining-takeToken1-token-token.js b/test/8.NestOpenMining-takeToken1-token-token.js index 11fb2c3..1af8538 100644 --- a/test/8.NestOpenMining-takeToken1-token-token.js +++ b/test/8.NestOpenMining-takeToken1-token-token.js @@ -158,7 +158,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(50000, 6), { + await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(50000, 6), { value: 0 }); status = await showStatus(); @@ -231,7 +231,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(70000, 6)); + await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(70000, 6)); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 60000 - 70000 * 4 + 50000 * 2, 6), 6)); diff --git a/test/9.NestOpenMining-takeToken1-token-eth.js b/test/9.NestOpenMining-takeToken1-token-eth.js index 35f6e21..f5f9dd2 100644 --- a/test/9.NestOpenMining-takeToken1-token-eth.js +++ b/test/9.NestOpenMining-takeToken1-token-eth.js @@ -151,7 +151,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).takeToken1(0, 0, 0, 1, toBigInt(4400, 6), { + await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(4400, 6), { value: toBigInt(2 + 1) }); status = await showStatus(); @@ -214,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.takeToken1(0, 0, 1, 2, toBigInt(4200, 6), { + await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(4200, 6), { value: toBigInt(2 * 2 + 2) }); status = await showStatus(); From d9a4ca299a3e6991f5b0f1f0052aa115ffc820c9 Mon Sep 17 00:00:00 2001 From: chenf Date: Thu, 9 Dec 2021 16:21:09 +0800 Subject: [PATCH 07/41] Multiple prices can be queried at one time --- contracts/NestBatchMining.sol | 32 ++++---- contracts/NestBatchPlatform2.sol | 137 ++++++++++++++++--------------- 2 files changed, 90 insertions(+), 79 deletions(-) diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index 80fe766..7bd53be 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -551,20 +551,9 @@ contract NestBatchMining is NestBase, INestBatchMining { // 冻结nest fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); - if (pairIndex >= 0) { - // 冻结token0 - fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); - // 冻结token1 - fee = _freeze( - balances, - pair.target, - needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, - fee - ); - - sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); - sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); - } else { + // 当吃单方向为拿走计价代币时,直接传报价对编号,当吃单方向为拿走报价代币时,传报价对编号减65536 + // pairIndex < 0,吃单方向为拿走报价代币 + if (pairIndex < 0) { // 冻结token0 fee = _freeze(balances, channel.token0, (needEthNum + takeNum) * uint(channel.unit), fee); // 冻结token1 @@ -577,6 +566,21 @@ contract NestBatchMining is NestBase, INestBatchMining { sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); + } + // pairIndex >= 0,吃单方向为拿走计价代币 + else { + // 冻结token0 + fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); + // 冻结token1 + fee = _freeze( + balances, + pair.target, + needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, + fee + ); + + sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); + sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); } require(fee == 0, "NOM:!fee"); diff --git a/contracts/NestBatchPlatform2.sol b/contracts/NestBatchPlatform2.sol index fe3d4c2..f09f5dd 100644 --- a/contracts/NestBatchPlatform2.sol +++ b/contracts/NestBatchPlatform2.sol @@ -127,9 +127,10 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { } // Payment of transfer fee - function _pay(PriceChannel storage channel, uint fee, address payback) private { + function _pay(uint channelId, address payback) private returns (PriceChannel storage channel) { - fee = fee * DIMI_ETHER; + channel = _channels[channelId]; + uint fee = uint(channel.singleFee) * DIMI_ETHER; if (msg.value > fee) { //payable(payback).transfer(msg.value - fee); TransferHelper.safeTransferETH(payback, msg.value - fee); @@ -149,11 +150,8 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { uint channelId, uint[] calldata pairIndices, address payback - ) external payable returns ( - uint[] memory prices - ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); + ) external payable returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); uint n = pairIndices.length << 1; prices = new uint[](n); @@ -175,8 +173,7 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { ) external payable returns ( uint[] memory prices ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); + PriceChannel storage channel = _pay(channelId, payback); uint n = pairIndices.length << 2; prices = new uint[](n); @@ -188,59 +185,70 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { /// @dev Find the price at block number /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 + /// @param pairIndices 报价对编号 /// @param height Destination block number /// @param payback 如果费用有多余的,则退回到此地址 - /// @return blockNumber The block number of price - /// @return price The token price. (1eth equivalent to (price) token) + /// @return prices 价格数组, i * 2 为第i个价格所在区块, i * 2 + 1 为第i个价格 function findPrice( uint channelId, - uint pairIndex, + uint[] calldata pairIndices, uint height, address payback - ) external payable returns ( - uint blockNumber, - uint price - ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - return _findPrice(channel.pairs[pairIndex], height); + ) external payable returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); + + uint n = pairIndices.length << 1; + prices = new uint[](n); + while (n > 0) { + n -= 2; + (prices[n], prices[n + 1]) = _findPrice(channel.pairs[n >> 1], height); + } } /// @dev Get the latest effective price /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 + /// @param pairIndices 报价对编号 /// @param payback 如果费用有多余的,则退回到此地址 - /// @return blockNumber The block number of price - /// @return price The token price. (1eth equivalent to (price) token) + /// @return prices 价格数组, i * 2 为第i个价格所在区块, i * 2 + 1 为第i个价格 function latestPrice( uint channelId, - uint pairIndex, + uint[] calldata pairIndices, address payback - ) external payable returns ( - uint blockNumber, - uint price - ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - return _latestPrice(channel.pairs[pairIndex]); + ) external payable returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); + + uint n = pairIndices.length << 1; + prices = new uint[](n); + while (n > 0) { + n -= 2; + (prices[n], prices[n + 1]) = _latestPrice(channel.pairs[n >> 1]); + } } /// @dev Get the last (num) effective price /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 + /// @param pairIndices 报价对编号 /// @param count The number of prices that want to return /// @param payback 如果费用有多余的,则退回到此地址 - /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + /// @return prices 结果数组,第 i * count * 2 到 (i + 1) * count * 2 - 1为第i组报价对的价格结果 function lastPriceList( uint channelId, - uint pairIndex, + uint[] calldata pairIndices, uint count, address payback - ) external payable returns (uint[] memory) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - return _lastPriceList(channel.pairs[pairIndex], count); + ) external payable returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); + + uint row = count << 1; + uint n = pairIndices.length * row; + prices = new uint[](n); + while (n > 0) { + n -= row; + uint[] memory pi = _lastPriceList(channel.pairs[n / row], count); + for (uint i = 0; i < row; ++i) { + prices[n + i] = pi[i]; + } + } } // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() @@ -271,38 +279,37 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { /// @dev Returns lastPriceList and triggered price info /// @param channelId 报价通道编号 - /// @param pairIndex 报价对编号 + /// @param pairIndices 报价对编号 /// @param count The number of prices that want to return /// @param payback 如果费用有多余的,则退回到此地址 - /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price - /// @return triggeredPriceBlockNumber The block number of triggered price - /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) - /// @return triggeredAvgPrice Average price - /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation - /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to - /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + /// @return prices 结果数组,第 i * (count * 2 + 4)到 (i + 1) * (count * 2 + 4)- 1为第i组报价对的价格结果 + /// 其中前count * 2个为最新价格,后4个依次为:触发价格区块号,触发价格,平均价格,波动率 function lastPriceListAndTriggeredPriceInfo( uint channelId, - uint pairIndex, + uint[] calldata pairIndices, uint count, address payback - ) external payable returns ( - uint[] memory prices, - uint triggeredPriceBlockNumber, - uint triggeredPriceValue, - uint triggeredAvgPrice, - uint triggeredSigmaSQ - ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - //return _lastPriceListAndTriggeredPriceInfo(channel.pairs[pairIndex], count); - PricePair storage pair = _channels[channelId].pairs[pairIndex]; - prices = _lastPriceList(pair, count); - ( - triggeredPriceBlockNumber, - triggeredPriceValue, - triggeredAvgPrice, - triggeredSigmaSQ - ) = _triggeredPriceInfo(pair); + ) external payable returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); + + uint row = (count << 1) + 4; + uint n = pairIndices.length * row; + prices = new uint[](n); + while (n > 0) { + n -= row; + + PricePair storage pair = channel.pairs[n / row]; + uint[] memory pi = _lastPriceList(pair, count); + for (uint i = 0; i + 4 < row; ++i) { + prices[n + i] = pi[i]; + } + uint j = n + row - 4; + ( + prices[j], + prices[j + 1], + prices[j + 2], + prices[j + 3] + ) = _triggeredPriceInfo(pair); + } } } \ No newline at end of file From 27d5d99cdd28021ca9c5c947f3213ba8d9fc67f1 Mon Sep 17 00:00:00 2001 From: chenf Date: Thu, 9 Dec 2021 16:26:18 +0800 Subject: [PATCH 08/41] Fix bug --- contracts/NestBatchMining.sol | 2 +- test/10.NestOpenMining-takeToken1-eth-token.js | 4 ++-- test/11.NestOpenMining-test2.js | 4 ++-- test/12.NestOpenMining-test3.js | 4 ++-- test/8.NestOpenMining-takeToken1-token-token.js | 4 ++-- test/9.NestOpenMining-takeToken1-token-eth.js | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index 7bd53be..d371ee1 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -497,7 +497,7 @@ contract NestBatchMining is NestBase, INestBatchMining { // 2. Load price sheet PriceChannel storage channel = _channels[channelId]; - PricePair storage pair = channel.pairs[uint(pairIndex < 0 ? pairIndex + 0xFFFF : pairIndex)]; + PricePair storage pair = channel.pairs[uint(pairIndex < 0 ? pairIndex + 0x10000 : pairIndex)]; PriceSheet[] storage sheets = pair.sheets; PriceSheet memory sheet = sheets[index]; diff --git a/test/10.NestOpenMining-takeToken1-eth-token.js b/test/10.NestOpenMining-takeToken1-eth-token.js index 67559e9..8980bf5 100644 --- a/test/10.NestOpenMining-takeToken1-eth-token.js +++ b/test/10.NestOpenMining-takeToken1-eth-token.js @@ -151,7 +151,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(0.5), { + await nestBatchMining.connect(addr1).take(0, 0 - 0x10000, 0, 1, toBigInt(0.5), { value: toBigInt(0.5 * 2 - 0.46) }); status = await showStatus(); @@ -214,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(0.6), { + await nestBatchMining.take(0, 0 - 0x10000, 1, 2, toBigInt(0.6), { value: toBigInt(0.6 * 4 - 0.5 * 2) }); status = await showStatus(); diff --git a/test/11.NestOpenMining-test2.js b/test/11.NestOpenMining-test2.js index 1bbf92d..33a17ed 100644 --- a/test/11.NestOpenMining-test2.js +++ b/test/11.NestOpenMining-test2.js @@ -151,7 +151,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(0.5), { + await nestBatchMining.connect(addr1).take(0, 0 - 0x10000, 0, 1, toBigInt(0.5), { value: toBigInt(0.5 * 2 - 0.46) }); status = await showStatus(); @@ -214,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(0.6), { + await nestBatchMining.take(0, 0 - 0x10000, 1, 2, toBigInt(0.6), { value: toBigInt(0.6 * 4 - 0.5 * 2) }); status = await showStatus(); diff --git a/test/12.NestOpenMining-test3.js b/test/12.NestOpenMining-test3.js index 1da0daa..616997d 100644 --- a/test/12.NestOpenMining-test3.js +++ b/test/12.NestOpenMining-test3.js @@ -151,7 +151,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(4400, 6), { + await nestBatchMining.connect(addr1).take(0, 0 - 0x10000, 0, 1, toBigInt(4400, 6), { value: toBigInt(2 + 1) }); status = await showStatus(); @@ -214,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(4200, 6), { + await nestBatchMining.take(0, 0 - 0x10000, 1, 2, toBigInt(4200, 6), { value: toBigInt(2 * 2 + 2) }); status = await showStatus(); diff --git a/test/8.NestOpenMining-takeToken1-token-token.js b/test/8.NestOpenMining-takeToken1-token-token.js index 1af8538..3e8cd2b 100644 --- a/test/8.NestOpenMining-takeToken1-token-token.js +++ b/test/8.NestOpenMining-takeToken1-token-token.js @@ -158,7 +158,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(50000, 6), { + await nestBatchMining.connect(addr1).take(0, 0 - 0x10000, 0, 1, toBigInt(50000, 6), { value: 0 }); status = await showStatus(); @@ -231,7 +231,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(70000, 6)); + await nestBatchMining.take(0, 0 - 0x10000, 1, 2, toBigInt(70000, 6)); status = await showStatus(); expect(status.owner.usdt).to.eq(toDecimal(toBigInt(10000000 - 60000 - 70000 * 4 + 50000 * 2, 6), 6)); diff --git a/test/9.NestOpenMining-takeToken1-token-eth.js b/test/9.NestOpenMining-takeToken1-token-eth.js index f5f9dd2..8670c49 100644 --- a/test/9.NestOpenMining-takeToken1-token-eth.js +++ b/test/9.NestOpenMining-takeToken1-token-eth.js @@ -151,7 +151,7 @@ describe('NestOpenMining', function() { expect(toDecimal(await nestBatchMining.balanceOf(nest.address, addr1.address))).eq(toDecimal(0)); return; } - await nestBatchMining.connect(addr1).take(0, 0 - 0xFFFF, 0, 1, toBigInt(4400, 6), { + await nestBatchMining.connect(addr1).take(0, 0 - 0x10000, 0, 1, toBigInt(4400, 6), { value: toBigInt(2 + 1) }); status = await showStatus(); @@ -214,7 +214,7 @@ describe('NestOpenMining', function() { } } else { console.log('2. 吃单链'); - await nestBatchMining.take(0, 0 - 0xFFFF, 1, 2, toBigInt(4200, 6), { + await nestBatchMining.take(0, 0 - 0x10000, 1, 2, toBigInt(4200, 6), { value: toBigInt(2 * 2 + 2) }); status = await showStatus(); From 102cc74962112befa7f5361206be9316d45471f9 Mon Sep 17 00:00:00 2001 From: chenf Date: Thu, 9 Dec 2021 17:12:44 +0800 Subject: [PATCH 09/41] Add comment --- contracts/NestBatchMining.sol | 1 + contracts/NestBatchPlatform.sol | 32 +++++++++----------------------- contracts/NestBatchPlatform2.sol | 1 + 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index d371ee1..58f7b4f 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -543,6 +543,7 @@ contract NestBatchMining is NestBase, INestBatchMining { _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); } + // TODO: 将创建报价单操作放到冻结资产前面,是否可能导致重入攻击,超额吃单? // Freeze nest and token { // 冻结资产:token0, token1, nest diff --git a/contracts/NestBatchPlatform.sol b/contracts/NestBatchPlatform.sol index 224bd56..c768757 100644 --- a/contracts/NestBatchPlatform.sol +++ b/contracts/NestBatchPlatform.sol @@ -12,8 +12,6 @@ import "./NestBatchMining.sol"; /// @dev This contract implemented the mining logic of nest contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPrice { - // TODO: 支持pairIndex数组,可以一次性查询多个价格 - /// @dev Get the latest trigger price /// @param channelId 报价通道编号 /// @param pairIndex 报价对编号 @@ -127,9 +125,10 @@ contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPr } // Payment of transfer fee - function _pay(PriceChannel storage channel, uint fee, address payback) private { + function _pay(uint channelId, address payback) private returns (PriceChannel storage channel) { - fee = fee * DIMI_ETHER; + channel = _channels[channelId]; + uint fee = uint(channel.singleFee) * DIMI_ETHER; if (msg.value > fee) { //payable(payback).transfer(msg.value - fee); TransferHelper.safeTransferETH(payback, msg.value - fee); @@ -154,9 +153,7 @@ contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPr uint blockNumber, uint price ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - return _triggeredPrice(channel.pairs[pairIndex]); + return _triggeredPrice(_pay(channelId, payback).pairs[pairIndex]); } /// @dev Get the full information of latest trigger price @@ -179,9 +176,7 @@ contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPr uint avgPrice, uint sigmaSQ ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - return _triggeredPriceInfo(channel.pairs[pairIndex]); + return _triggeredPriceInfo(_pay(channelId, payback).pairs[pairIndex]); } /// @dev Find the price at block number @@ -200,9 +195,7 @@ contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPr uint blockNumber, uint price ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - return _findPrice(channel.pairs[pairIndex], height); + return _findPrice(_pay(channelId, payback).pairs[pairIndex], height); } /// @dev Get the latest effective price @@ -219,9 +212,7 @@ contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPr uint blockNumber, uint price ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - return _latestPrice(channel.pairs[pairIndex]); + return _latestPrice(_pay(channelId, payback).pairs[pairIndex]); } /// @dev Get the last (num) effective price @@ -236,9 +227,7 @@ contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPr uint count, address payback ) external payable override returns (uint[] memory) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - return _lastPriceList(channel.pairs[pairIndex], count); + return _lastPriceList(_pay(channelId, payback).pairs[pairIndex], count); } // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() @@ -291,10 +280,7 @@ contract NestBatchPlatform is NestBatchMining, INestBatchPriceView, INestBatchPr uint triggeredAvgPrice, uint triggeredSigmaSQ ) { - PriceChannel storage channel = _channels[channelId]; - _pay(channel, uint(channel.singleFee), payback); - //return _lastPriceListAndTriggeredPriceInfo(channel.pairs[pairIndex], count); - PricePair storage pair = _channels[channelId].pairs[pairIndex]; + PricePair storage pair = _pay(channelId, payback).pairs[pairIndex]; prices = _lastPriceList(pair, count); ( triggeredPriceBlockNumber, diff --git a/contracts/NestBatchPlatform2.sol b/contracts/NestBatchPlatform2.sol index f09f5dd..48b3a35 100644 --- a/contracts/NestBatchPlatform2.sol +++ b/contracts/NestBatchPlatform2.sol @@ -9,6 +9,7 @@ import "./interface/INestBatchPrice.sol"; import "./NestBatchMining.sol"; +// 支持pairIndex数组,可以一次性查询多个价格 /// @dev This contract implemented the mining logic of nest contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { From 3e7b51697933cb7c059ea52f4a5c8a81a4316a83 Mon Sep 17 00:00:00 2001 From: chenf Date: Sat, 11 Dec 2021 11:12:48 +0800 Subject: [PATCH 10/41] Test query price --- contracts/NestBatchPlatform2.sol | 14 +- contracts/NestBatchPlatform3.sol | 316 +++++++++++++++++++++++++++++++ scripts/deploy.proxy.js | 2 +- test/20.NestBatchMining.js | 193 +++++++++++++++++++ 4 files changed, 517 insertions(+), 8 deletions(-) create mode 100644 contracts/NestBatchPlatform3.sol create mode 100644 test/20.NestBatchMining.js diff --git a/contracts/NestBatchPlatform2.sol b/contracts/NestBatchPlatform2.sol index 48b3a35..c64fcf3 100644 --- a/contracts/NestBatchPlatform2.sol +++ b/contracts/NestBatchPlatform2.sol @@ -158,7 +158,7 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { prices = new uint[](n); while (n > 0) { n -= 2; - (prices[n], prices[n + 1]) = _triggeredPrice(channel.pairs[n >> 1]); + (prices[n], prices[n + 1]) = _triggeredPrice(channel.pairs[pairIndices[n >> 1]]); } } @@ -179,8 +179,8 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { uint n = pairIndices.length << 2; prices = new uint[](n); while (n > 0) { - n -= 2; - (prices[n], prices[n + 1], prices[n + 2], prices[n + 3]) = _triggeredPriceInfo(channel.pairs[n >> 2]); + n -= 4; + (prices[n], prices[n + 1], prices[n + 2], prices[n + 3]) = _triggeredPriceInfo(channel.pairs[pairIndices[n >> 2]]); } } @@ -202,7 +202,7 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { prices = new uint[](n); while (n > 0) { n -= 2; - (prices[n], prices[n + 1]) = _findPrice(channel.pairs[n >> 1], height); + (prices[n], prices[n + 1]) = _findPrice(channel.pairs[pairIndices[n >> 1]], height); } } @@ -222,7 +222,7 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { prices = new uint[](n); while (n > 0) { n -= 2; - (prices[n], prices[n + 1]) = _latestPrice(channel.pairs[n >> 1]); + (prices[n], prices[n + 1]) = _latestPrice(channel.pairs[pairIndices[n >> 1]]); } } @@ -245,7 +245,7 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { prices = new uint[](n); while (n > 0) { n -= row; - uint[] memory pi = _lastPriceList(channel.pairs[n / row], count); + uint[] memory pi = _lastPriceList(channel.pairs[pairIndices[n / row]], count); for (uint i = 0; i < row; ++i) { prices[n + i] = pi[i]; } @@ -299,7 +299,7 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { while (n > 0) { n -= row; - PricePair storage pair = channel.pairs[n / row]; + PricePair storage pair = channel.pairs[pairIndices[n / row]]; uint[] memory pi = _lastPriceList(pair, count); for (uint i = 0; i + 4 < row; ++i) { prices[n + i] = pi[i]; diff --git a/contracts/NestBatchPlatform3.sol b/contracts/NestBatchPlatform3.sol new file mode 100644 index 0000000..b0ead41 --- /dev/null +++ b/contracts/NestBatchPlatform3.sol @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.6; + +import "./lib/TransferHelper.sol"; + +import "./interface/INestBatchPriceView.sol"; +import "./interface/INestBatchPrice.sol"; + +import "./NestBatchMining.sol"; + +// 支持pairIndex数组,可以一次性查询多个价格 +/// @dev This contract implemented the mining logic of nest +contract NestBatchPlatform3 is NestBatchMining { + + // TODO: 支持pairIndex数组,可以一次性查询多个价格 + + // /// @dev Get the latest trigger price + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @return blockNumber The block number of price + // /// @return price The token price. (1eth equivalent to (price) token) + // function triggeredPrice(uint channelId, uint pairIndex) external view override noContract returns (uint blockNumber, uint price) { + // return _triggeredPrice(_channels[channelId].pairs[pairIndex]); + // } + + // /// @dev Get the full information of latest trigger price + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @return blockNumber The block number of price + // /// @return price The token price. (1eth equivalent to (price) token) + // /// @return avgPrice Average price + // /// @return sigmaSQ The square of the volatility (18 decimal places). The current implementation assumes that + // /// the volatility cannot exceed 1. Correspondingly, when the return value is equal to 999999999999996447, + // /// it means that the volatility has exceeded the range that can be expressed + // function triggeredPriceInfo(uint channelId, uint pairIndex) external view override noContract returns ( + // uint blockNumber, + // uint price, + // uint avgPrice, + // uint sigmaSQ + // ) { + // return _triggeredPriceInfo(_channels[channelId].pairs[pairIndex]); + // } + + // /// @dev Find the price at block number + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @param height Destination block number + // /// @return blockNumber The block number of price + // /// @return price The token price. (1eth equivalent to (price) token) + // function findPrice( + // uint channelId, + // uint pairIndex, + // uint height + // ) external view override noContract returns (uint blockNumber, uint price) { + // return _findPrice(_channels[channelId].pairs[pairIndex], height); + // } + + // /// @dev Get the latest effective price + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @return blockNumber The block number of price + // /// @return price The token price. (1eth equivalent to (price) token) + // function latestPrice(uint channelId, uint pairIndex) external view override noContract returns (uint blockNumber, uint price) { + // return _latestPrice(_channels[channelId].pairs[pairIndex]); + // } + + // /// @dev Get the last (num) effective price + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @param count The number of prices that want to return + // /// @return An array which length is num * 2, each two element expresses one price like blockNumber|price + // function lastPriceList(uint channelId, uint pairIndex, uint count) external view override noContract returns (uint[] memory) { + // return _lastPriceList(_channels[channelId].pairs[pairIndex], count); + // } + + // // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // // /// @param channelId 报价通道编号 + // // /// @param pairIndex 报价对编号 + // // /// @return latestPriceBlockNumber The block number of latest price + // // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // // /// @return triggeredPriceBlockNumber The block number of triggered price + // // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // // /// @return triggeredAvgPrice Average price + // // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // // function latestPriceAndTriggeredPriceInfo(uint channelId, uint pairIndex) external view noContract + // // returns ( + // // uint latestPriceBlockNumber, + // // uint latestPriceValue, + // // uint triggeredPriceBlockNumber, + // // uint triggeredPriceValue, + // // uint triggeredAvgPrice, + // // uint triggeredSigmaSQ + // // ) { + // // return _latestPriceAndTriggeredPriceInfo(_channels[channelId].pairs[pairIndex]); + // // } + + // /// @dev Returns lastPriceList and triggered price info + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @param count The number of prices that want to return + // /// @return prices An array which length is num * 2, each two element expresses one price like blockNumber|price + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function lastPriceListAndTriggeredPriceInfo(uint channelId, uint pairIndex, uint count) external view override noContract + // returns ( + // uint[] memory prices, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ) { + // //return _lastPriceListAndTriggeredPriceInfo(_channels[channelId].pairs[pairIndex], count); + // PricePair storage pair = _channels[channelId].pairs[pairIndex]; + // prices = _lastPriceList(pair, count); + // ( + // triggeredPriceBlockNumber, + // triggeredPriceValue, + // triggeredAvgPrice, + // triggeredSigmaSQ + // ) = _triggeredPriceInfo(pair); + // } + + // Payment of transfer fee + function _pay(uint channelId, address payback) private view returns (PriceChannel storage channel) { + + channel = _channels[channelId]; + // uint fee = uint(channel.singleFee) * DIMI_ETHER; + // if (msg.value > fee) { + // //payable(payback).transfer(msg.value - fee); + // TransferHelper.safeTransferETH(payback, msg.value - fee); + // } else { + // require(msg.value == fee, "NOP:!fee"); + // } + + // channel.rewards += fee; + } + + /// @dev Get the latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 2 为第i个价格所在区块, i * 2 + 1 为第i个价格 + function triggeredPrice( + uint channelId, + uint[] calldata pairIndices, + address payback + ) external view returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); + + uint n = pairIndices.length << 1; + prices = new uint[](n); + while (n > 0) { + n -= 2; + (prices[n], prices[n + 1]) = _triggeredPrice(channel.pairs[pairIndices[n >> 1]]); + } + } + + /// @dev Get the full information of latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 4 为第i个价格所在区块, i * 4 + 1 为第i个价格, i * 4 + 2 为第i个平均价格, i * 4 + 3 为第i个波动率 + function triggeredPriceInfo( + uint channelId, + uint[] calldata pairIndices, + address payback + ) external view returns ( + uint[] memory prices + ) { + PriceChannel storage channel = _pay(channelId, payback); + + uint n = pairIndices.length << 2; + prices = new uint[](n); + while (n > 0) { + n -= 4; + (prices[n], prices[n + 1], prices[n + 2], prices[n + 3]) = _triggeredPriceInfo(channel.pairs[pairIndices[n >> 2]]); + } + } + + /// @dev Find the price at block number + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param height Destination block number + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 2 为第i个价格所在区块, i * 2 + 1 为第i个价格 + function findPrice( + uint channelId, + uint[] calldata pairIndices, + uint height, + address payback + ) external view returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); + + uint n = pairIndices.length << 1; + prices = new uint[](n); + while (n > 0) { + n -= 2; + (prices[n], prices[n + 1]) = _findPrice(channel.pairs[pairIndices[n >> 1]], height); + } + } + + /// @dev Get the latest effective price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 2 为第i个价格所在区块, i * 2 + 1 为第i个价格 + function latestPrice( + uint channelId, + uint[] calldata pairIndices, + address payback + ) external view returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); + + uint n = pairIndices.length << 1; + prices = new uint[](n); + while (n > 0) { + n -= 2; + (prices[n], prices[n + 1]) = _latestPrice(channel.pairs[pairIndices[n >> 1]]); + } + } + + /// @dev Get the last (num) effective price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 结果数组,第 i * count * 2 到 (i + 1) * count * 2 - 1为第i组报价对的价格结果 + function lastPriceList( + uint channelId, + uint[] calldata pairIndices, + uint count, + address payback + ) external view returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); + + uint row = count << 1; + uint n = pairIndices.length * row; + prices = new uint[](n); + while (n > 0) { + n -= row; + uint[] memory pi = _lastPriceList(channel.pairs[pairIndices[n / row]], count); + for (uint i = 0; i < row; ++i) { + prices[n + i] = pi[i]; + } + } + } + + // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() + // /// @param channelId 报价通道编号 + // /// @param pairIndex 报价对编号 + // /// @param payback 如果费用有多余的,则退回到此地址 + // /// @return latestPriceBlockNumber The block number of latest price + // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) + // /// @return triggeredPriceBlockNumber The block number of triggered price + // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) + // /// @return triggeredAvgPrice Average price + // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation + // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to + // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed + // function latestPriceAndTriggeredPriceInfo(uint channelId, uint pairIndex, address payback) external payable + // returns ( + // uint latestPriceBlockNumber, + // uint latestPriceValue, + // uint triggeredPriceBlockNumber, + // uint triggeredPriceValue, + // uint triggeredAvgPrice, + // uint triggeredSigmaSQ + // ) { + // PriceChannel storage channel = _channels[channelId]; + // _pay(channel, uint(channel.singleFee), payback); + // return _latestPriceAndTriggeredPriceInfo(channel.pairs[pairIndex]); + // } + + /// @dev Returns lastPriceList and triggered price info + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 结果数组,第 i * (count * 2 + 4)到 (i + 1) * (count * 2 + 4)- 1为第i组报价对的价格结果 + /// 其中前count * 2个为最新价格,后4个依次为:触发价格区块号,触发价格,平均价格,波动率 + function lastPriceListAndTriggeredPriceInfo( + uint channelId, + uint[] calldata pairIndices, + uint count, + address payback + ) external view returns (uint[] memory prices) { + PriceChannel storage channel = _pay(channelId, payback); + + uint row = (count << 1) + 4; + uint n = pairIndices.length * row; + prices = new uint[](n); + while (n > 0) { + n -= row; + + PricePair storage pair = channel.pairs[pairIndices[n / row]]; + uint[] memory pi = _lastPriceList(pair, count); + for (uint i = 0; i + 4 < row; ++i) { + prices[n + i] = pi[i]; + } + uint j = n + row - 4; + ( + prices[j], + prices[j + 1], + prices[j + 2], + prices[j + 3] + ) = _triggeredPriceInfo(pair); + } + } +} \ No newline at end of file diff --git a/scripts/deploy.proxy.js b/scripts/deploy.proxy.js index e90c341..74c8bd2 100644 --- a/scripts/deploy.proxy.js +++ b/scripts/deploy.proxy.js @@ -19,7 +19,7 @@ exports.deploy = async function() { const NestGovernance = await ethers.getContractFactory('NestGovernance'); const NestLedger = await ethers.getContractFactory('NestLedger'); const NestOpenMining = await ethers.getContractFactory('NestOpenPlatform'); - const NestBatchMining = await ethers.getContractFactory('NestBatchPlatform'); + const NestBatchMining = await ethers.getContractFactory('NestBatchPlatform3'); const NestVote = await ethers.getContractFactory('NestVote'); console.log('** 开始部署合约 deploy.proxy.js **'); diff --git a/test/20.NestBatchMining.js b/test/20.NestBatchMining.js new file mode 100644 index 0000000..af96e4b --- /dev/null +++ b/test/20.NestBatchMining.js @@ -0,0 +1,193 @@ +const { expect } = require('chai'); +const { deploy } = require('../scripts/deploy.js'); +const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); + +describe('NestOpenMining', function() { + it('First', async function() { + var [owner, addr1, addr2] = await ethers.getSigners(); + + const { + nest, usdt, hbtc, usdc, cofi, + + nestGovernance, nestLedger, + nestMining, nestOpenMining, nestBatchMining, + nestPriceFacade, nestVote, + nTokenController, nestRedeeming + } = await deploy(); + + const getAccountInfo = async function(account) { + let acc = account; + account = account.address; + return { + eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), + usdt: toDecimal(await usdt.balanceOf(account), 6), + hbtc: toDecimal(await hbtc.balanceOf(account), 18), + nest: toDecimal(await nest.balanceOf(account), 18), + }; + }; + const getStatus = async function() { + return { + height: await ethers.provider.getBlockNumber(), + owner: await getAccountInfo(owner), + addr1: await getAccountInfo(addr1), + mining: await getAccountInfo(nestBatchMining) + }; + }; + + const showStatus = async function() { + let status = await getStatus(); + //console.log(status); + return status; + } + + const skipBlocks = async function(n) { + for (var i = 0; i < n; ++i) { + await usdt.transfer(owner.address, 0); + } + } + + await usdt.transfer(owner.address, 10000000000000n); + await usdc.transfer(owner.address, 10000000000000n); + await cofi.transfer(owner.address, 10000000000000n); + await hbtc.transfer(owner.address, 10000000000000000000000000n); + await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); + await usdc.connect(addr1).transfer(addr1.address, 10000000000000n); + await cofi.connect(addr1).transfer(addr1.address, 10000000000000n); + await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); + await nest.transfer(addr1.address, 1000000000000000000000000000n); + console.log(await getStatus()); + + await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); + await usdc.approve(nestBatchMining.address, 10000000000000000000000000n); + await cofi.approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); + await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); + await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await usdc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await cofi.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + + //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); + await nestBatchMining.open({ + // 计价代币地址, 0表示eth + token0: hbtc.address, + // 计价代币单位 + unit: 1000000000000000000n, + + // 报价代币地址,0表示eth + //token1: usdt.address, + // 每个区块的标准出矿量 + rewardPerBlock: 1000000000000000000n, + + // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 + // 出矿代币地址 + reward: nest.address, + // 矿币总量 + //uint96 vault; + + // 管理地址 + //address governance; + // 创世区块 + //uint32 genesisBlock; + // Post fee(0.0001eth,DIMI_ETHER). 1000 + postFeeUnit: 1000, + // Single query fee (0.0001 ether, DIMI_ETHER). 100 + singleFee: 100, + // 衰减系数,万分制。8000 + reductionRate: 8000, + + tokens: [usdt.address, usdc.address, cofi.address] + }); + await nestBatchMining.increase(0, 5000000000000000000000000000n); + //console.log(await getStatus()); + + const GASLIMIT = 400000n; + const POSTFEE = 0.1; + const OPEN_FEE = 0n; + const EFFECT_BLOCK = 50; + + if (true) { + console.log('1. post'); + let receipt = await nestBatchMining.post(0, 1, [71000000000n, 72000000000n, 73000000000n], { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + + console.log('1. wait 20 and close'); + await skipBlocks(EFFECT_BLOCK); + await nestBatchMining.close(0, [[0], [0], [0]]); + //await nestBatchMining.close(0, 1, [0]); + //await nestBatchMining.close(0, 2, [0]); + } + + if (true) { + console.log('2. post'); + let receipt = await nestBatchMining.post(0, 1, [61000000000n, 62000000000n, 63000000000n], { + value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT + }); + await showReceipt(receipt); + } + + if (true) { + await skipBlocks(EFFECT_BLOCK); + await nestBatchMining.close(0, [[1], [1], [1]]); + } + + if (true) { + console.log('3. triggeredPrice'); + let p = await nestBatchMining.triggeredPrice(0, [1, 2, 0], owner.address); + for (var i = 0; i < p.length; ++i) { + console.log(p[i].toString()); + } + } + + if (true) { + console.log('4. triggeredPriceInfo'); + let p = await nestBatchMining.triggeredPriceInfo(0, [1, 2, 0], owner.address); + for (var i = 0; i < p.length; ++i) { + console.log(p[i].toString()); + } + } + + if (true) { + console.log('5. findPrice'); + let p = await nestBatchMining.findPrice(0, [1, 2, 0], 99, owner.address); + for (var i = 0; i < p.length; ++i) { + console.log(p[i].toString()); + } + } + + if (true) { + console.log('6. latestPrice'); + let p = await nestBatchMining.latestPrice(0, [1, 2, 0], owner.address); + for (var i = 0; i < p.length; ++i) { + console.log(p[i].toString()); + } + } + + if (true) { + console.log('7. lastPriceList'); + let p = await nestBatchMining.lastPriceList(0, [1, 2, 0], 2, owner.address); + for (var i = 0; i < p.length; ++i) { + console.log(p[i].toString()); + } + } + + if (true) { + console.log('8. lastPriceListAndTriggeredPriceInfo'); + let p = await nestBatchMining.lastPriceListAndTriggeredPriceInfo(0, [1, 2, 0], 2, owner.address); + for (var i = 0; i < p.length; ) { + console.log('height1: ' + p[i++].toString()); + console.log('price1: ' + p[i++].toString()); + console.log('height0: ' + p[i++].toString()); + console.log('price0: ' + p[i++].toString()); + console.log('triggeredPriceBlockNumber: ' + p[i++].toString()); + console.log('triggeredPriceValue: ' + p[i++].toString()); + console.log('triggeredAvgPrice: ' + p[i++].toString()); + console.log('triggeredSigmaSQ: ' + p[i++].toString()); + console.log(); + } + } + }); +}); From 22109b75e09b04235c15ce8ec8c3174d7a6b08cd Mon Sep 17 00:00:00 2001 From: chenf Date: Sat, 11 Dec 2021 14:19:47 +0800 Subject: [PATCH 11/41] Add interface INestBatchPrice2 --- contracts/NestBase.sol | 22 +- contracts/NestBatchMining.sol | 230 ++---------- contracts/NestBatchPlatform2.sol | 124 ++----- contracts/interface/INestBatchPrice2.sol | 80 +++++ contracts/{ => test}/NestBatchPlatform3.sol | 12 +- scripts/deploy.proxy.js | 2 +- test/0.NestOpenMining-price.js | 12 +- test/20.NestBatchMining.js | 374 ++++++++++---------- 8 files changed, 348 insertions(+), 508 deletions(-) create mode 100644 contracts/interface/INestBatchPrice2.sol rename contracts/{ => test}/NestBatchPlatform3.sol (97%) diff --git a/contracts/NestBase.sol b/contracts/NestBase.sol index 75550ba..809515a 100644 --- a/contracts/NestBase.sol +++ b/contracts/NestBase.sol @@ -43,18 +43,18 @@ contract NestBase { NEST_TOKEN_ADDRESS = INestGovernance(nestGovernanceAddress).getNestTokenAddress(); } - /// @dev Migrate funds from current contract to NestLedger - /// @param tokenAddress Destination token address.(0 means eth) - /// @param value Migrate amount - function migrate(address tokenAddress, uint value) external onlyGovernance { + // /// @dev Migrate funds from current contract to NestLedger + // /// @param tokenAddress Destination token address.(0 means eth) + // /// @param value Migrate amount + // function migrate(address tokenAddress, uint value) external onlyGovernance { - address to = INestGovernance(_governance).getNestLedgerAddress(); - if (tokenAddress == address(0)) { - INestLedger(to).addETHReward { value: value } (0); - } else { - TransferHelper.safeTransfer(tokenAddress, to, value); - } - } + // address to = INestGovernance(_governance).getNestLedgerAddress(); + // if (tokenAddress == address(0)) { + // INestLedger(to).addETHReward { value: value } (0); + // } else { + // TransferHelper.safeTransfer(tokenAddress, to, value); + // } + // } //---------modifier------------ diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index 58f7b4f..36aae83 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -389,97 +389,6 @@ contract NestBatchMining is NestBase, INestBatchMining { } } - // /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet - // /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) - // /// @param channelId 报价通道编号 - // /// @param pairIndex 报价对编号 - // /// @param index The position of the sheet in priceSheetList[token] - // /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth - // /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth - // function takeToken0(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { - - // Config memory config = _config; - - // // 1. Check arguments - // require(takeNum > 0, "NM:!takeNum"); - // require(newEquivalent > 0, "NM:!price"); - - // // 2. Load price sheet - // PriceChannel storage channel = _channels[channelId]; - // PricePair storage pair = channel.pairs[pairIndex]; - // PriceSheet[] storage sheets = pair.sheets; - // PriceSheet memory sheet = sheets[index]; - - // // 3. Check state - // require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); - // require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); - - // uint accountIndex = _addressIndex(msg.sender); - // // Number of nest to be pledged - // //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); - // // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum - // uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); - - // // 4. Deposit fee - // // 5. Calculate the number of eth, token and nest needed, and freeze them - // uint needEthNum; - // { - // uint level = uint(sheet.level); - - // // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled - // if (level < uint(config.maxBiteNestedLevel)) { - // // Double scale sheet - // needEthNum = takeNum << 1; - // ++level; - // } - // // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not - // else { - // // Single scale sheet - // needEthNum = takeNum; - // // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 - // // or more, there is no logical dependence on the specific value of the contract, and the count will - // // not increase after it is accumulated to 255 - // if (level < 255) ++level; - // } - - // // 7. Calculate the price - // // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price - // // is placed before the sheet is added, which can reduce unnecessary traversal - // _stat(config, pair, sheets); - - // // 8. Create price sheet - // //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); - // _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); - // } - - // // Freeze nest and token - // { - // // 冻结资产:token0, token1, nest - // mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; - // uint fee = msg.value; - - // // 冻结nest - // fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); - // // 冻结token0 - // fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); - // // 冻结token1 - // fee = _freeze( - // balances, - // pair.target, - // needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, - // fee - // ); - - // require(fee == 0, "NOM:!fee"); - // } - - // // 6. Update the bitten sheet - // sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); - // sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); - // sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); - // sheets[index] = sheet; - // } - /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) /// @param channelId 报价通道编号 @@ -502,8 +411,10 @@ contract NestBatchMining is NestBase, INestBatchMining { PriceSheet memory sheet = sheets[index]; // 3. Check state - require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); + //require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); + // 6. Update the bitten sheet + sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); uint accountIndex = _addressIndex(msg.sender); // Number of nest to be pledged @@ -513,24 +424,15 @@ contract NestBatchMining is NestBase, INestBatchMining { // 4. Deposit fee // 5. Calculate the number of eth, token and nest needed, and freeze them - uint needEthNum; + uint needEthNum = takeNum; { uint level = uint(sheet.level); - - // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled - if (level < uint(config.maxBiteNestedLevel)) { - // Double scale sheet - needEthNum = takeNum << 1; + if (level < 255) { + if (level < uint(config.maxBiteNestedLevel)) { + // Double scale sheet + needEthNum <<= 1; + } ++level; - } - // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not - else { - // Single scale sheet - needEthNum = takeNum; - // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 - // or more, there is no logical dependence on the specific value of the contract, and the count will - // not increase after it is accumulated to 255 - if (level < 255) ++level; } // 7. Calculate the price @@ -550,11 +452,13 @@ contract NestBatchMining is NestBase, INestBatchMining { mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; uint fee = msg.value; - // 冻结nest - fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); // 当吃单方向为拿走计价代币时,直接传报价对编号,当吃单方向为拿走报价代币时,传报价对编号减65536 // pairIndex < 0,吃单方向为拿走报价代币 if (pairIndex < 0) { + sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); + sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); + sheets[index] = sheet; + // 冻结token0 fee = _freeze(balances, channel.token0, (needEthNum + takeNum) * uint(channel.unit), fee); // 冻结token1 @@ -564,12 +468,13 @@ contract NestBatchMining is NestBase, INestBatchMining { } else { _unfreeze(balances, pair.target, backTokenValue - needEthNum * newEquivalent, msg.sender); } - - sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); - sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); } // pairIndex >= 0,吃单方向为拿走计价代币 else { + sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); + sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); + sheets[index] = sheet; + // 冻结token0 fee = _freeze(balances, channel.token0, (needEthNum - takeNum) * uint(channel.unit), fee); // 冻结token1 @@ -579,110 +484,15 @@ contract NestBatchMining is NestBase, INestBatchMining { needEthNum * newEquivalent + _decodeFloat(sheet.priceFloat) * takeNum, fee ); - - sheet.ethNumBal = uint32(uint(sheet.ethNumBal) - takeNum); - sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) + takeNum); } + // 冻结nest + fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); + require(fee == 0, "NOM:!fee"); } - - // 6. Update the bitten sheet - sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); - sheets[index] = sheet; } - // /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet - // /// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal) - // /// @param channelId The address of token(ntoken) - // /// @param pairIndex 报价对编号 - // /// @param index The position of the sheet in priceSheetList[token] - // /// @param takeNum The amount of biting (in the unit of ETH), realAmount = takeNum * newTokenAmountPerEth - // /// @param newEquivalent The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth - // function takeToken1(uint channelId, uint pairIndex, uint index, uint takeNum, uint newEquivalent) external payable override { - - // Config memory config = _config; - - // // 1. Check arguments - // require(takeNum > 0, "NM:!takeNum"); - // require(newEquivalent > 0, "NM:!price"); - - // // 2. Load price sheet - // PriceChannel storage channel = _channels[channelId]; - // PricePair storage pair = channel.pairs[pairIndex]; - // PriceSheet[] storage sheets = pair.sheets; - // PriceSheet memory sheet = sheets[index]; - - // // 3. Check state - // require(uint(sheet.remainNum) >= takeNum, "NM:!remainNum"); - // require(uint(sheet.height) + uint(config.priceEffectSpan) >= block.number, "NM:!state"); - - // uint accountIndex = _addressIndex(msg.sender); - // // Number of nest to be pledged - // //uint needNest1k = ((takeNum << 1) / uint(config.postEthUnit)) * uint(config.pledgeNest); - // // sheet.ethNumBal + sheet.tokenNumBal is always two times to sheet.ethNum - // uint needNest1k = (takeNum << 2) * uint(sheet.nestNum1k) / (uint(sheet.ethNumBal) + uint(sheet.tokenNumBal)); - - // // 4. Deposit fee - // // 5. Calculate the number of eth, token and nest needed, and freeze them - // uint needEthNum; - // { - // uint level = uint(sheet.level); - - // // When the level of the sheet is less than 4, both the nest and the scale of the offer are doubled - // if (level < uint(config.maxBiteNestedLevel)) { - // // Double scale sheet - // needEthNum = takeNum << 1; - // ++level; - // } - // // When the level of the sheet reaches 4 or more, nest doubles, but the scale does not - // else { - // // Single scale sheet - // needEthNum = takeNum; - // // It is possible that the length of a single chain exceeds 255. When the length of a chain reaches 4 - // // or more, there is no logical dependence on the specific value of the contract, and the count will - // // not increase after it is accumulated to 255 - // if (level < 255) ++level; - // } - - // // 7. Calculate the price - // // According to the current mechanism, the newly added sheet cannot take effect, so the calculated price - // // is placed before the sheet is added, which can reduce unnecessary traversal - // _stat(config, pair, sheets); - - // // 8. Create price sheet - // //emit Post(channelId, msg.sender, sheets.length, needEthNum, newEquivalent); - // _createPriceSheet(sheets, accountIndex, uint32(needEthNum), needNest1k, level << 8, newEquivalent); - // } - - // // Freeze nest and token - // { - // // 冻结资产:token0, token1, nest - // mapping(address=>UINT) storage balances = _accounts[accountIndex].balances; - // uint fee = msg.value; - - // // 冻结nest - // fee = _freeze(balances, NEST_TOKEN_ADDRESS, needNest1k * 1000 ether, fee); - // // 冻结token0 - // fee = _freeze(balances, channel.token0, (needEthNum + takeNum) * uint(channel.unit), fee); - // // 冻结token1 - // uint backTokenValue = _decodeFloat(sheet.priceFloat) * takeNum; - // if (needEthNum * newEquivalent > backTokenValue) { - // fee = _freeze(balances, pair.target, needEthNum * newEquivalent - backTokenValue, fee); - // } else { - // _unfreeze(balances, pair.target, backTokenValue - needEthNum * newEquivalent, msg.sender); - // } - - // require(fee == 0, "NOM:!fee"); - // } - - // // 6. Update the bitten sheet - // sheet.remainNum = uint32(uint(sheet.remainNum) - takeNum); - // sheet.ethNumBal = uint32(uint(sheet.ethNumBal) + takeNum); - // sheet.tokenNumBal = uint32(uint(sheet.tokenNumBal) - takeNum); - // sheets[index] = sheet; - // } - /// @dev List sheets by page /// @param channelId 报价通道编号 /// @param pairIndex 报价对编号 diff --git a/contracts/NestBatchPlatform2.sol b/contracts/NestBatchPlatform2.sol index c64fcf3..e9f6e6c 100644 --- a/contracts/NestBatchPlatform2.sol +++ b/contracts/NestBatchPlatform2.sol @@ -5,15 +5,15 @@ pragma solidity ^0.8.6; import "./lib/TransferHelper.sol"; import "./interface/INestBatchPriceView.sol"; -import "./interface/INestBatchPrice.sol"; +import "./interface/INestBatchPrice2.sol"; import "./NestBatchMining.sol"; // 支持pairIndex数组,可以一次性查询多个价格 /// @dev This contract implemented the mining logic of nest -contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { +contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView, INestBatchPrice2 { - // TODO: 支持pairIndex数组,可以一次性查询多个价格 + /* ========== INestBatchPriceView ========== */ /// @dev Get the latest trigger price /// @param channelId 报价通道编号 @@ -74,29 +74,6 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { return _lastPriceList(_channels[channelId].pairs[pairIndex], count); } - // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() - // /// @param channelId 报价通道编号 - // /// @param pairIndex 报价对编号 - // /// @return latestPriceBlockNumber The block number of latest price - // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) - // /// @return triggeredPriceBlockNumber The block number of triggered price - // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) - // /// @return triggeredAvgPrice Average price - // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation - // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to - // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed - // function latestPriceAndTriggeredPriceInfo(uint channelId, uint pairIndex) external view noContract - // returns ( - // uint latestPriceBlockNumber, - // uint latestPriceValue, - // uint triggeredPriceBlockNumber, - // uint triggeredPriceValue, - // uint triggeredAvgPrice, - // uint triggeredSigmaSQ - // ) { - // return _latestPriceAndTriggeredPriceInfo(_channels[channelId].pairs[pairIndex]); - // } - /// @dev Returns lastPriceList and triggered price info /// @param channelId 报价通道编号 /// @param pairIndex 报价对编号 @@ -127,20 +104,7 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { ) = _triggeredPriceInfo(pair); } - // Payment of transfer fee - function _pay(uint channelId, address payback) private returns (PriceChannel storage channel) { - - channel = _channels[channelId]; - uint fee = uint(channel.singleFee) * DIMI_ETHER; - if (msg.value > fee) { - //payable(payback).transfer(msg.value - fee); - TransferHelper.safeTransferETH(payback, msg.value - fee); - } else { - require(msg.value == fee, "NOP:!fee"); - } - - channel.rewards += fee; - } + /* ========== INestBatchPrice ========== */ /// @dev Get the latest trigger price /// @param channelId 报价通道编号 @@ -151,14 +115,14 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { uint channelId, uint[] calldata pairIndices, address payback - ) external payable returns (uint[] memory prices) { - PriceChannel storage channel = _pay(channelId, payback); + ) external payable override returns (uint[] memory prices) { + PricePair[0xFFFF] storage pairs = _pay(channelId, payback).pairs; uint n = pairIndices.length << 1; prices = new uint[](n); while (n > 0) { n -= 2; - (prices[n], prices[n + 1]) = _triggeredPrice(channel.pairs[pairIndices[n >> 1]]); + (prices[n], prices[n + 1]) = _triggeredPrice(pairs[pairIndices[n >> 1]]); } } @@ -171,16 +135,14 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { uint channelId, uint[] calldata pairIndices, address payback - ) external payable returns ( - uint[] memory prices - ) { - PriceChannel storage channel = _pay(channelId, payback); + ) external payable override returns (uint[] memory prices) { + PricePair[0xFFFF] storage pairs = _pay(channelId, payback).pairs; uint n = pairIndices.length << 2; prices = new uint[](n); while (n > 0) { n -= 4; - (prices[n], prices[n + 1], prices[n + 2], prices[n + 3]) = _triggeredPriceInfo(channel.pairs[pairIndices[n >> 2]]); + (prices[n], prices[n + 1], prices[n + 2], prices[n + 3]) = _triggeredPriceInfo(pairs[pairIndices[n >> 2]]); } } @@ -195,14 +157,14 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { uint[] calldata pairIndices, uint height, address payback - ) external payable returns (uint[] memory prices) { - PriceChannel storage channel = _pay(channelId, payback); + ) external payable override returns (uint[] memory prices) { + PricePair[0xFFFF] storage pairs = _pay(channelId, payback).pairs; uint n = pairIndices.length << 1; prices = new uint[](n); while (n > 0) { n -= 2; - (prices[n], prices[n + 1]) = _findPrice(channel.pairs[pairIndices[n >> 1]], height); + (prices[n], prices[n + 1]) = _findPrice(pairs[pairIndices[n >> 1]], height); } } @@ -215,14 +177,14 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { uint channelId, uint[] calldata pairIndices, address payback - ) external payable returns (uint[] memory prices) { - PriceChannel storage channel = _pay(channelId, payback); + ) external payable override returns (uint[] memory prices) { + PricePair[0xFFFF] storage pairs = _pay(channelId, payback).pairs; uint n = pairIndices.length << 1; prices = new uint[](n); while (n > 0) { n -= 2; - (prices[n], prices[n + 1]) = _latestPrice(channel.pairs[pairIndices[n >> 1]]); + (prices[n], prices[n + 1]) = _latestPrice(pairs[pairIndices[n >> 1]]); } } @@ -237,47 +199,21 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { uint[] calldata pairIndices, uint count, address payback - ) external payable returns (uint[] memory prices) { - PriceChannel storage channel = _pay(channelId, payback); + ) external payable override returns (uint[] memory prices) { + PricePair[0xFFFF] storage pairs = _pay(channelId, payback).pairs; uint row = count << 1; uint n = pairIndices.length * row; prices = new uint[](n); while (n > 0) { n -= row; - uint[] memory pi = _lastPriceList(channel.pairs[pairIndices[n / row]], count); + uint[] memory pi = _lastPriceList(pairs[pairIndices[n / row]], count); for (uint i = 0; i < row; ++i) { prices[n + i] = pi[i]; } } } - // /// @dev Returns the results of latestPrice() and triggeredPriceInfo() - // /// @param channelId 报价通道编号 - // /// @param pairIndex 报价对编号 - // /// @param payback 如果费用有多余的,则退回到此地址 - // /// @return latestPriceBlockNumber The block number of latest price - // /// @return latestPriceValue The token latest price. (1eth equivalent to (price) token) - // /// @return triggeredPriceBlockNumber The block number of triggered price - // /// @return triggeredPriceValue The token triggered price. (1eth equivalent to (price) token) - // /// @return triggeredAvgPrice Average price - // /// @return triggeredSigmaSQ The square of the volatility (18 decimal places). The current implementation - // /// assumes that the volatility cannot exceed 1. Correspondingly, when the return value is equal to - // /// 999999999999996447, it means that the volatility has exceeded the range that can be expressed - // function latestPriceAndTriggeredPriceInfo(uint channelId, uint pairIndex, address payback) external payable - // returns ( - // uint latestPriceBlockNumber, - // uint latestPriceValue, - // uint triggeredPriceBlockNumber, - // uint triggeredPriceValue, - // uint triggeredAvgPrice, - // uint triggeredSigmaSQ - // ) { - // PriceChannel storage channel = _channels[channelId]; - // _pay(channel, uint(channel.singleFee), payback); - // return _latestPriceAndTriggeredPriceInfo(channel.pairs[pairIndex]); - // } - /// @dev Returns lastPriceList and triggered price info /// @param channelId 报价通道编号 /// @param pairIndices 报价对编号 @@ -290,8 +226,8 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { uint[] calldata pairIndices, uint count, address payback - ) external payable returns (uint[] memory prices) { - PriceChannel storage channel = _pay(channelId, payback); + ) external payable override returns (uint[] memory prices) { + PricePair[0xFFFF] storage pairs = _pay(channelId, payback).pairs; uint row = (count << 1) + 4; uint n = pairIndices.length * row; @@ -299,7 +235,7 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { while (n > 0) { n -= row; - PricePair storage pair = channel.pairs[pairIndices[n / row]]; + PricePair storage pair = pairs[pairIndices[n / row]]; uint[] memory pi = _lastPriceList(pair, count); for (uint i = 0; i + 4 < row; ++i) { prices[n + i] = pi[i]; @@ -313,4 +249,20 @@ contract NestBatchPlatform2 is NestBatchMining, INestBatchPriceView { ) = _triggeredPriceInfo(pair); } } + + // Payment of transfer fee + function _pay(uint channelId, address payback) private returns (PriceChannel storage channel) { + + channel = _channels[channelId]; + uint fee = uint(channel.singleFee) * DIMI_ETHER; + if (msg.value > fee) { + payable(payback).transfer(msg.value - fee); + // TODO: BSC上采用的是老的gas计算策略,直接转账可能导致代理合约gas超出,要改用下面的方式转账 + //TransferHelper.safeTransferETH(payback, msg.value - fee); + } else { + require(msg.value == fee, "NOP:!fee"); + } + + channel.rewards += fee; + } } \ No newline at end of file diff --git a/contracts/interface/INestBatchPrice2.sol b/contracts/interface/INestBatchPrice2.sol new file mode 100644 index 0000000..9065585 --- /dev/null +++ b/contracts/interface/INestBatchPrice2.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.6; + +/// @dev This contract implemented the mining logic of nest +interface INestBatchPrice2 { + + /// @dev Get the latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 2 为第i个价格所在区块, i * 2 + 1 为第i个价格 + function triggeredPrice( + uint channelId, + uint[] calldata pairIndices, + address payback + ) external payable returns (uint[] memory prices); + + /// @dev Get the full information of latest trigger price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 4 为第i个价格所在区块, i * 4 + 1 为第i个价格, i * 4 + 2 为第i个平均价格, i * 4 + 3 为第i个波动率 + function triggeredPriceInfo( + uint channelId, + uint[] calldata pairIndices, + address payback + ) external payable returns (uint[] memory prices); + + /// @dev Find the price at block number + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param height Destination block number + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 2 为第i个价格所在区块, i * 2 + 1 为第i个价格 + function findPrice( + uint channelId, + uint[] calldata pairIndices, + uint height, + address payback + ) external payable returns (uint[] memory prices); + + /// @dev Get the latest effective price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 价格数组, i * 2 为第i个价格所在区块, i * 2 + 1 为第i个价格 + function latestPrice( + uint channelId, + uint[] calldata pairIndices, + address payback + ) external payable returns (uint[] memory prices); + + /// @dev Get the last (num) effective price + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 结果数组,第 i * count * 2 到 (i + 1) * count * 2 - 1为第i组报价对的价格结果 + function lastPriceList( + uint channelId, + uint[] calldata pairIndices, + uint count, + address payback + ) external payable returns (uint[] memory prices); + + /// @dev Returns lastPriceList and triggered price info + /// @param channelId 报价通道编号 + /// @param pairIndices 报价对编号 + /// @param count The number of prices that want to return + /// @param payback 如果费用有多余的,则退回到此地址 + /// @return prices 结果数组,第 i * (count * 2 + 4)到 (i + 1) * (count * 2 + 4)- 1为第i组报价对的价格结果 + /// 其中前count * 2个为最新价格,后4个依次为:触发价格区块号,触发价格,平均价格,波动率 + function lastPriceListAndTriggeredPriceInfo( + uint channelId, + uint[] calldata pairIndices, + uint count, + address payback + ) external payable returns (uint[] memory prices); +} \ No newline at end of file diff --git a/contracts/NestBatchPlatform3.sol b/contracts/test/NestBatchPlatform3.sol similarity index 97% rename from contracts/NestBatchPlatform3.sol rename to contracts/test/NestBatchPlatform3.sol index b0ead41..e9943e9 100644 --- a/contracts/NestBatchPlatform3.sol +++ b/contracts/test/NestBatchPlatform3.sol @@ -2,19 +2,17 @@ pragma solidity ^0.8.6; -import "./lib/TransferHelper.sol"; +import "../lib/TransferHelper.sol"; -import "./interface/INestBatchPriceView.sol"; -import "./interface/INestBatchPrice.sol"; +import "../interface/INestBatchPriceView.sol"; +import "../interface/INestBatchPrice.sol"; -import "./NestBatchMining.sol"; +import "../NestBatchMining.sol"; // 支持pairIndex数组,可以一次性查询多个价格 /// @dev This contract implemented the mining logic of nest contract NestBatchPlatform3 is NestBatchMining { - // TODO: 支持pairIndex数组,可以一次性查询多个价格 - // /// @dev Get the latest trigger price // /// @param channelId 报价通道编号 // /// @param pairIndex 报价对编号 @@ -128,7 +126,7 @@ contract NestBatchPlatform3 is NestBatchMining { // } // Payment of transfer fee - function _pay(uint channelId, address payback) private view returns (PriceChannel storage channel) { + function _pay(uint channelId, address) private view returns (PriceChannel storage channel) { channel = _channels[channelId]; // uint fee = uint(channel.singleFee) * DIMI_ETHER; diff --git a/scripts/deploy.proxy.js b/scripts/deploy.proxy.js index 74c8bd2..9dc7fb9 100644 --- a/scripts/deploy.proxy.js +++ b/scripts/deploy.proxy.js @@ -19,7 +19,7 @@ exports.deploy = async function() { const NestGovernance = await ethers.getContractFactory('NestGovernance'); const NestLedger = await ethers.getContractFactory('NestLedger'); const NestOpenMining = await ethers.getContractFactory('NestOpenPlatform'); - const NestBatchMining = await ethers.getContractFactory('NestBatchPlatform3'); + const NestBatchMining = await ethers.getContractFactory('NestBatchPlatform2'); const NestVote = await ethers.getContractFactory('NestVote'); console.log('** 开始部署合约 deploy.proxy.js **'); diff --git a/test/0.NestOpenMining-price.js b/test/0.NestOpenMining-price.js index 0586651..70893cf 100644 --- a/test/0.NestOpenMining-price.js +++ b/test/0.NestOpenMining-price.js @@ -188,7 +188,7 @@ describe('NestOpenMining', function() { await showStatus(); console.log('fee: ' + toDecimal((await nestBatchMining.getChannelInfo(0)).rewards)); - const np = await ethers.getContractAt('INestBatchPrice', nestBatchMining.address); + const np = await ethers.getContractAt('INestBatchPrice2', nestBatchMining.address); const nv = await ethers.getContractAt('INestBatchPriceView', nestBatchMining.address); const test = async function() { const FEE = 0.010; @@ -199,12 +199,12 @@ describe('NestOpenMining', function() { price: pi.price.toString() }); - await np.latestPrice(0, 0, owner.address, { value: toBigInt(FEE) }); - await np.triggeredPrice(0, 0, owner.address, { value: toBigInt(FEE) }); + await np.latestPrice(0, [0], owner.address, { value: toBigInt(FEE) }); + await np.triggeredPrice(0, [0], owner.address, { value: toBigInt(FEE) }); //await np.latestPriceAndTriggeredPriceInfo(0, 0, owner.address, { value: toBigInt(FEE) }); - await np.lastPriceListAndTriggeredPriceInfo(0, 0, 2, owner.address, { value: toBigInt(FEE) }); - await np.lastPriceList(0, 0, 2, owner.address, { value: toBigInt(FEE) }); - await np.findPrice(0, 0, 85, owner.address, { value: toBigInt(FEE) }); + await np.lastPriceListAndTriggeredPriceInfo(0, [0], 2, owner.address, { value: toBigInt(FEE) }); + await np.lastPriceList(0, [0], 2, owner.address, { value: toBigInt(FEE) }); + await np.findPrice(0, [0], 85, owner.address, { value: toBigInt(FEE) }); } console.log('没有等待'); diff --git a/test/20.NestBatchMining.js b/test/20.NestBatchMining.js index af96e4b..1fc7cbd 100644 --- a/test/20.NestBatchMining.js +++ b/test/20.NestBatchMining.js @@ -1,193 +1,193 @@ -const { expect } = require('chai'); -const { deploy } = require('../scripts/deploy.js'); -const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); +// const { expect } = require('chai'); +// const { deploy } = require('../scripts/deploy.js'); +// const { toBigInt, toDecimal, showReceipt, snd, tableSnd, d1, Vc, Vp, UI } = require('./utils.js'); -describe('NestOpenMining', function() { - it('First', async function() { - var [owner, addr1, addr2] = await ethers.getSigners(); +// describe('NestOpenMining', function() { +// it('First', async function() { +// var [owner, addr1, addr2] = await ethers.getSigners(); - const { - nest, usdt, hbtc, usdc, cofi, - - nestGovernance, nestLedger, - nestMining, nestOpenMining, nestBatchMining, - nestPriceFacade, nestVote, - nTokenController, nestRedeeming - } = await deploy(); - - const getAccountInfo = async function(account) { - let acc = account; - account = account.address; - return { - eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), - usdt: toDecimal(await usdt.balanceOf(account), 6), - hbtc: toDecimal(await hbtc.balanceOf(account), 18), - nest: toDecimal(await nest.balanceOf(account), 18), - }; - }; - const getStatus = async function() { - return { - height: await ethers.provider.getBlockNumber(), - owner: await getAccountInfo(owner), - addr1: await getAccountInfo(addr1), - mining: await getAccountInfo(nestBatchMining) - }; - }; - - const showStatus = async function() { - let status = await getStatus(); - //console.log(status); - return status; - } - - const skipBlocks = async function(n) { - for (var i = 0; i < n; ++i) { - await usdt.transfer(owner.address, 0); - } - } - - await usdt.transfer(owner.address, 10000000000000n); - await usdc.transfer(owner.address, 10000000000000n); - await cofi.transfer(owner.address, 10000000000000n); - await hbtc.transfer(owner.address, 10000000000000000000000000n); - await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); - await usdc.connect(addr1).transfer(addr1.address, 10000000000000n); - await cofi.connect(addr1).transfer(addr1.address, 10000000000000n); - await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); - await nest.transfer(addr1.address, 1000000000000000000000000000n); - console.log(await getStatus()); - - await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); - await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); - await usdc.approve(nestBatchMining.address, 10000000000000000000000000n); - await cofi.approve(nestBatchMining.address, 10000000000000000000000000n); - await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); - await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); - await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - await usdc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - await cofi.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); - - //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); - await nestBatchMining.open({ - // 计价代币地址, 0表示eth - token0: hbtc.address, - // 计价代币单位 - unit: 1000000000000000000n, +// const { +// nest, usdt, hbtc, usdc, cofi, + +// nestGovernance, nestLedger, +// nestMining, nestOpenMining, nestBatchMining, +// nestPriceFacade, nestVote, +// nTokenController, nestRedeeming +// } = await deploy(); + +// const getAccountInfo = async function(account) { +// let acc = account; +// account = account.address; +// return { +// eth: toDecimal(acc.ethBalance ? await acc.ethBalance() : await ethers.provider.getBalance(account)), +// usdt: toDecimal(await usdt.balanceOf(account), 6), +// hbtc: toDecimal(await hbtc.balanceOf(account), 18), +// nest: toDecimal(await nest.balanceOf(account), 18), +// }; +// }; +// const getStatus = async function() { +// return { +// height: await ethers.provider.getBlockNumber(), +// owner: await getAccountInfo(owner), +// addr1: await getAccountInfo(addr1), +// mining: await getAccountInfo(nestBatchMining) +// }; +// }; + +// const showStatus = async function() { +// let status = await getStatus(); +// //console.log(status); +// return status; +// } + +// const skipBlocks = async function(n) { +// for (var i = 0; i < n; ++i) { +// await usdt.transfer(owner.address, 0); +// } +// } + +// await usdt.transfer(owner.address, 10000000000000n); +// await usdc.transfer(owner.address, 10000000000000n); +// await cofi.transfer(owner.address, 10000000000000n); +// await hbtc.transfer(owner.address, 10000000000000000000000000n); +// await usdt.connect(addr1).transfer(addr1.address, 10000000000000n); +// await usdc.connect(addr1).transfer(addr1.address, 10000000000000n); +// await cofi.connect(addr1).transfer(addr1.address, 10000000000000n); +// await hbtc.connect(addr1).transfer(addr1.address, 10000000000000000000000000n); +// await nest.transfer(addr1.address, 1000000000000000000000000000n); +// console.log(await getStatus()); + +// await nest.approve(nestBatchMining.address, 10000000000000000000000000000n); +// await usdt.approve(nestBatchMining.address, 10000000000000000000000000n); +// await usdc.approve(nestBatchMining.address, 10000000000000000000000000n); +// await cofi.approve(nestBatchMining.address, 10000000000000000000000000n); +// await hbtc.approve(nestBatchMining.address, 10000000000000000000000000n); +// await nest.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000000n); +// await usdt.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); +// await usdc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); +// await cofi.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); +// await hbtc.connect(addr1).approve(nestBatchMining.address, 10000000000000000000000000n); + +// //await nestOpenMining.open(hbtc.address, 1000000000000000000n, usdt.address, nest.address); +// await nestBatchMining.open({ +// // 计价代币地址, 0表示eth +// token0: hbtc.address, +// // 计价代币单位 +// unit: 1000000000000000000n, - // 报价代币地址,0表示eth - //token1: usdt.address, - // 每个区块的标准出矿量 - rewardPerBlock: 1000000000000000000n, +// // 报价代币地址,0表示eth +// //token1: usdt.address, +// // 每个区块的标准出矿量 +// rewardPerBlock: 1000000000000000000n, - // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 - // 出矿代币地址 - reward: nest.address, - // 矿币总量 - //uint96 vault; +// // 矿币地址如果和token0或者token1是一种币,可能导致挖矿资产被当成矿币挖走 +// // 出矿代币地址 +// reward: nest.address, +// // 矿币总量 +// //uint96 vault; - // 管理地址 - //address governance; - // 创世区块 - //uint32 genesisBlock; - // Post fee(0.0001eth,DIMI_ETHER). 1000 - postFeeUnit: 1000, - // Single query fee (0.0001 ether, DIMI_ETHER). 100 - singleFee: 100, - // 衰减系数,万分制。8000 - reductionRate: 8000, +// // 管理地址 +// //address governance; +// // 创世区块 +// //uint32 genesisBlock; +// // Post fee(0.0001eth,DIMI_ETHER). 1000 +// postFeeUnit: 1000, +// // Single query fee (0.0001 ether, DIMI_ETHER). 100 +// singleFee: 100, +// // 衰减系数,万分制。8000 +// reductionRate: 8000, - tokens: [usdt.address, usdc.address, cofi.address] - }); - await nestBatchMining.increase(0, 5000000000000000000000000000n); - //console.log(await getStatus()); - - const GASLIMIT = 400000n; - const POSTFEE = 0.1; - const OPEN_FEE = 0n; - const EFFECT_BLOCK = 50; - - if (true) { - console.log('1. post'); - let receipt = await nestBatchMining.post(0, 1, [71000000000n, 72000000000n, 73000000000n], { - value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT - }); - await showReceipt(receipt); - - console.log('1. wait 20 and close'); - await skipBlocks(EFFECT_BLOCK); - await nestBatchMining.close(0, [[0], [0], [0]]); - //await nestBatchMining.close(0, 1, [0]); - //await nestBatchMining.close(0, 2, [0]); - } - - if (true) { - console.log('2. post'); - let receipt = await nestBatchMining.post(0, 1, [61000000000n, 62000000000n, 63000000000n], { - value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT - }); - await showReceipt(receipt); - } - - if (true) { - await skipBlocks(EFFECT_BLOCK); - await nestBatchMining.close(0, [[1], [1], [1]]); - } - - if (true) { - console.log('3. triggeredPrice'); - let p = await nestBatchMining.triggeredPrice(0, [1, 2, 0], owner.address); - for (var i = 0; i < p.length; ++i) { - console.log(p[i].toString()); - } - } - - if (true) { - console.log('4. triggeredPriceInfo'); - let p = await nestBatchMining.triggeredPriceInfo(0, [1, 2, 0], owner.address); - for (var i = 0; i < p.length; ++i) { - console.log(p[i].toString()); - } - } - - if (true) { - console.log('5. findPrice'); - let p = await nestBatchMining.findPrice(0, [1, 2, 0], 99, owner.address); - for (var i = 0; i < p.length; ++i) { - console.log(p[i].toString()); - } - } - - if (true) { - console.log('6. latestPrice'); - let p = await nestBatchMining.latestPrice(0, [1, 2, 0], owner.address); - for (var i = 0; i < p.length; ++i) { - console.log(p[i].toString()); - } - } - - if (true) { - console.log('7. lastPriceList'); - let p = await nestBatchMining.lastPriceList(0, [1, 2, 0], 2, owner.address); - for (var i = 0; i < p.length; ++i) { - console.log(p[i].toString()); - } - } - - if (true) { - console.log('8. lastPriceListAndTriggeredPriceInfo'); - let p = await nestBatchMining.lastPriceListAndTriggeredPriceInfo(0, [1, 2, 0], 2, owner.address); - for (var i = 0; i < p.length; ) { - console.log('height1: ' + p[i++].toString()); - console.log('price1: ' + p[i++].toString()); - console.log('height0: ' + p[i++].toString()); - console.log('price0: ' + p[i++].toString()); - console.log('triggeredPriceBlockNumber: ' + p[i++].toString()); - console.log('triggeredPriceValue: ' + p[i++].toString()); - console.log('triggeredAvgPrice: ' + p[i++].toString()); - console.log('triggeredSigmaSQ: ' + p[i++].toString()); - console.log(); - } - } - }); -}); +// tokens: [usdt.address, usdc.address, cofi.address] +// }); +// await nestBatchMining.increase(0, 5000000000000000000000000000n); +// //console.log(await getStatus()); + +// const GASLIMIT = 400000n; +// const POSTFEE = 0.1; +// const OPEN_FEE = 0n; +// const EFFECT_BLOCK = 50; + +// if (true) { +// console.log('1. post'); +// let receipt = await nestBatchMining.post(0, 1, [71000000000n, 72000000000n, 73000000000n], { +// value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT +// }); +// await showReceipt(receipt); + +// console.log('1. wait 20 and close'); +// await skipBlocks(EFFECT_BLOCK); +// await nestBatchMining.close(0, [[0], [0], [0]]); +// //await nestBatchMining.close(0, 1, [0]); +// //await nestBatchMining.close(0, 2, [0]); +// } + +// if (true) { +// console.log('2. post'); +// let receipt = await nestBatchMining.post(0, 1, [61000000000n, 62000000000n, 63000000000n], { +// value: toBigInt(POSTFEE) + 1000000000n * GASLIMIT +// }); +// await showReceipt(receipt); +// } + +// if (true) { +// await skipBlocks(EFFECT_BLOCK); +// await nestBatchMining.close(0, [[1], [1], [1]]); +// } + +// if (true) { +// console.log('3. triggeredPrice'); +// let p = await nestBatchMining.triggeredPrice(0, [1, 2, 0], owner.address); +// for (var i = 0; i < p.length; ++i) { +// console.log(p[i].toString()); +// } +// } + +// if (true) { +// console.log('4. triggeredPriceInfo'); +// let p = await nestBatchMining.triggeredPriceInfo(0, [1, 2, 0], owner.address); +// for (var i = 0; i < p.length; ++i) { +// console.log(p[i].toString()); +// } +// } + +// if (true) { +// console.log('5. findPrice'); +// let p = await nestBatchMining.findPrice(0, [1, 2, 0], 99, owner.address); +// for (var i = 0; i < p.length; ++i) { +// console.log(p[i].toString()); +// } +// } + +// if (true) { +// console.log('6. latestPrice'); +// let p = await nestBatchMining.latestPrice(0, [1, 2, 0], owner.address); +// for (var i = 0; i < p.length; ++i) { +// console.log(p[i].toString()); +// } +// } + +// if (true) { +// console.log('7. lastPriceList'); +// let p = await nestBatchMining.lastPriceList(0, [1, 2, 0], 2, owner.address); +// for (var i = 0; i < p.length; ++i) { +// console.log(p[i].toString()); +// } +// } + +// if (true) { +// console.log('8. lastPriceListAndTriggeredPriceInfo'); +// let p = await nestBatchMining.lastPriceListAndTriggeredPriceInfo(0, [1, 2, 0], 2, owner.address); +// for (var i = 0; i < p.length; ) { +// console.log('height1: ' + p[i++].toString()); +// console.log('price1: ' + p[i++].toString()); +// console.log('height0: ' + p[i++].toString()); +// console.log('price0: ' + p[i++].toString()); +// console.log('triggeredPriceBlockNumber: ' + p[i++].toString()); +// console.log('triggeredPriceValue: ' + p[i++].toString()); +// console.log('triggeredAvgPrice: ' + p[i++].toString()); +// console.log('triggeredSigmaSQ: ' + p[i++].toString()); +// console.log(); +// } +// } +// }); +// }); From 532ec77952a07297038403a38c5b09fcab13d1cc Mon Sep 17 00:00:00 2001 From: chenf Date: Sat, 11 Dec 2021 14:24:39 +0800 Subject: [PATCH 12/41] Organize code directory --- contracts/NToken.sol | 4 +-- contracts/NestBase.sol | 6 ++-- contracts/NestBatchMining.sol | 10 +++---- contracts/NestBatchPlatform.sol | 6 ++-- contracts/NestBatchPlatform2.sol | 6 ++-- contracts/NestGovernance.sol | 2 +- contracts/NestLedger.sol | 4 +-- contracts/NestOpenMining.sol | 10 +++---- contracts/NestOpenPlatform.sol | 6 ++-- contracts/NestVote.sol | 10 +++---- .../{interface => interfaces}/INToken.sol | 0 .../INestBatchMining.sol | 0 .../INestBatchPrice.sol | 0 .../INestBatchPrice2.sol | 0 .../INestBatchPriceView.sol | 0 .../INestGovernance.sol | 0 .../{interface => interfaces}/INestLedger.sol | 0 .../INestMapping.sol | 0 .../INestOpenMining.sol | 0 .../INestOpenPrice.sol | 0 .../INestPriceView.sol | 0 .../{interface => interfaces}/INestVote.sol | 0 .../{interface => interfaces}/IProxyAdmin.sol | 0 .../IVotePropose.sol | 0 contracts/lib/TransferHelper.sol | 29 ------------------- contracts/{lib => libs}/Context.sol | 0 contracts/{lib => libs}/ERC20.sol | 0 contracts/{lib => libs}/IERC20.sol | 0 contracts/test/NestBatchPlatform3.sol | 6 ++-- contracts/test/UpdateAdmin.sol | 6 ++-- contracts/test/UpdateProxyPropose.sol | 6 ++-- 31 files changed, 41 insertions(+), 70 deletions(-) rename contracts/{interface => interfaces}/INToken.sol (100%) rename contracts/{interface => interfaces}/INestBatchMining.sol (100%) rename contracts/{interface => interfaces}/INestBatchPrice.sol (100%) rename contracts/{interface => interfaces}/INestBatchPrice2.sol (100%) rename contracts/{interface => interfaces}/INestBatchPriceView.sol (100%) rename contracts/{interface => interfaces}/INestGovernance.sol (100%) rename contracts/{interface => interfaces}/INestLedger.sol (100%) rename contracts/{interface => interfaces}/INestMapping.sol (100%) rename contracts/{interface => interfaces}/INestOpenMining.sol (100%) rename contracts/{interface => interfaces}/INestOpenPrice.sol (100%) rename contracts/{interface => interfaces}/INestPriceView.sol (100%) rename contracts/{interface => interfaces}/INestVote.sol (100%) rename contracts/{interface => interfaces}/IProxyAdmin.sol (100%) rename contracts/{interface => interfaces}/IVotePropose.sol (100%) delete mode 100644 contracts/lib/TransferHelper.sol rename contracts/{lib => libs}/Context.sol (100%) rename contracts/{lib => libs}/ERC20.sol (100%) rename contracts/{lib => libs}/IERC20.sol (100%) diff --git a/contracts/NToken.sol b/contracts/NToken.sol index 9b6b4a9..06e7fbc 100644 --- a/contracts/NToken.sol +++ b/contracts/NToken.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.6; -import "./interface/INToken.sol"; -import "./interface/INestGovernance.sol"; +import "./interfaces/INToken.sol"; +import "./interfaces/INestGovernance.sol"; import "./NestBase.sol"; // The contract is based on Nest_NToken from Nest Protocol v3.0. Considering compatibility, the interface diff --git a/contracts/NestBase.sol b/contracts/NestBase.sol index 809515a..6ef40df 100644 --- a/contracts/NestBase.sol +++ b/contracts/NestBase.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.6; -import "./lib/TransferHelper.sol"; -import "./interface/INestGovernance.sol"; -import "./interface/INestLedger.sol"; +import "./libs/TransferHelper.sol"; +import "./interfaces/INestGovernance.sol"; +import "./interfaces/INestLedger.sol"; /// @dev Base contract of nest contract NestBase { diff --git a/contracts/NestBatchMining.sol b/contracts/NestBatchMining.sol index 36aae83..9b592fc 100644 --- a/contracts/NestBatchMining.sol +++ b/contracts/NestBatchMining.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.6; -import "./lib/IERC20.sol"; -import "./lib/TransferHelper.sol"; +import "./libs/IERC20.sol"; +import "./libs/TransferHelper.sol"; -import "./interface/INestBatchMining.sol"; -import "./interface/INestLedger.sol"; -import "./interface/INToken.sol"; +import "./interfaces/INestBatchMining.sol"; +import "./interfaces/INestLedger.sol"; +import "./interfaces/INToken.sol"; import "./NestBase.sol"; diff --git a/contracts/NestBatchPlatform.sol b/contracts/NestBatchPlatform.sol index c768757..0f07c02 100644 --- a/contracts/NestBatchPlatform.sol +++ b/contracts/NestBatchPlatform.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.6; -import "./lib/TransferHelper.sol"; +import "./libs/TransferHelper.sol"; -import "./interface/INestBatchPriceView.sol"; -import "./interface/INestBatchPrice.sol"; +import "./interfaces/INestBatchPriceView.sol"; +import "./interfaces/INestBatchPrice.sol"; import "./NestBatchMining.sol"; diff --git a/contracts/NestBatchPlatform2.sol b/contracts/NestBatchPlatform2.sol index e9f6e6c..10f7d91 100644 --- a/contracts/NestBatchPlatform2.sol +++ b/contracts/NestBatchPlatform2.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.6; -import "./lib/TransferHelper.sol"; +import "./libs/TransferHelper.sol"; -import "./interface/INestBatchPriceView.sol"; -import "./interface/INestBatchPrice2.sol"; +import "./interfaces/INestBatchPriceView.sol"; +import "./interfaces/INestBatchPrice2.sol"; import "./NestBatchMining.sol"; diff --git a/contracts/NestGovernance.sol b/contracts/NestGovernance.sol index 0527498..c0b7b04 100644 --- a/contracts/NestGovernance.sol +++ b/contracts/NestGovernance.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.6; -import "./interface/INestGovernance.sol"; +import "./interfaces/INestGovernance.sol"; import "./NestMapping.sol"; /// @dev Nest governance contract diff --git a/contracts/NestLedger.sol b/contracts/NestLedger.sol index 4d4bed0..1d2bbd4 100644 --- a/contracts/NestLedger.sol +++ b/contracts/NestLedger.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.6; -import "./lib/TransferHelper.sol"; -import "./interface/INestLedger.sol"; +import "./libs/TransferHelper.sol"; +import "./interfaces/INestLedger.sol"; import "./NestBase.sol"; /// @dev Nest ledger contract diff --git a/contracts/NestOpenMining.sol b/contracts/NestOpenMining.sol index e2aec91..a20bdb0 100644 --- a/contracts/NestOpenMining.sol +++ b/contracts/NestOpenMining.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.6; -import "./lib/IERC20.sol"; -import "./lib/TransferHelper.sol"; +import "./libs/IERC20.sol"; +import "./libs/TransferHelper.sol"; -import "./interface/INestOpenMining.sol"; -import "./interface/INestLedger.sol"; -import "./interface/INToken.sol"; +import "./interfaces/INestOpenMining.sol"; +import "./interfaces/INestLedger.sol"; +import "./interfaces/INToken.sol"; import "./NestBase.sol"; diff --git a/contracts/NestOpenPlatform.sol b/contracts/NestOpenPlatform.sol index d4113b1..b169ade 100644 --- a/contracts/NestOpenPlatform.sol +++ b/contracts/NestOpenPlatform.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.6; -import "./lib/TransferHelper.sol"; +import "./libs/TransferHelper.sol"; -import "./interface/INestPriceView.sol"; -import "./interface/INestOpenPrice.sol"; +import "./interfaces/INestPriceView.sol"; +import "./interfaces/INestOpenPrice.sol"; import "./NestOpenMining.sol"; diff --git a/contracts/NestVote.sol b/contracts/NestVote.sol index a7fbc6e..e6e796d 100644 --- a/contracts/NestVote.sol +++ b/contracts/NestVote.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.6; -import "./lib/IERC20.sol"; -import "./interface/INestVote.sol"; -import "./interface/IVotePropose.sol"; -import "./interface/INestGovernance.sol"; -import "./interface/IProxyAdmin.sol"; +import "./libs/IERC20.sol"; +import "./interfaces/INestVote.sol"; +import "./interfaces/IVotePropose.sol"; +import "./interfaces/INestGovernance.sol"; +import "./interfaces/IProxyAdmin.sol"; import "./NestBase.sol"; /// @dev nest voting contract, implemented the voting logic diff --git a/contracts/interface/INToken.sol b/contracts/interfaces/INToken.sol similarity index 100% rename from contracts/interface/INToken.sol rename to contracts/interfaces/INToken.sol diff --git a/contracts/interface/INestBatchMining.sol b/contracts/interfaces/INestBatchMining.sol similarity index 100% rename from contracts/interface/INestBatchMining.sol rename to contracts/interfaces/INestBatchMining.sol diff --git a/contracts/interface/INestBatchPrice.sol b/contracts/interfaces/INestBatchPrice.sol similarity index 100% rename from contracts/interface/INestBatchPrice.sol rename to contracts/interfaces/INestBatchPrice.sol diff --git a/contracts/interface/INestBatchPrice2.sol b/contracts/interfaces/INestBatchPrice2.sol similarity index 100% rename from contracts/interface/INestBatchPrice2.sol rename to contracts/interfaces/INestBatchPrice2.sol diff --git a/contracts/interface/INestBatchPriceView.sol b/contracts/interfaces/INestBatchPriceView.sol similarity index 100% rename from contracts/interface/INestBatchPriceView.sol rename to contracts/interfaces/INestBatchPriceView.sol diff --git a/contracts/interface/INestGovernance.sol b/contracts/interfaces/INestGovernance.sol similarity index 100% rename from contracts/interface/INestGovernance.sol rename to contracts/interfaces/INestGovernance.sol diff --git a/contracts/interface/INestLedger.sol b/contracts/interfaces/INestLedger.sol similarity index 100% rename from contracts/interface/INestLedger.sol rename to contracts/interfaces/INestLedger.sol diff --git a/contracts/interface/INestMapping.sol b/contracts/interfaces/INestMapping.sol similarity index 100% rename from contracts/interface/INestMapping.sol rename to contracts/interfaces/INestMapping.sol diff --git a/contracts/interface/INestOpenMining.sol b/contracts/interfaces/INestOpenMining.sol similarity index 100% rename from contracts/interface/INestOpenMining.sol rename to contracts/interfaces/INestOpenMining.sol diff --git a/contracts/interface/INestOpenPrice.sol b/contracts/interfaces/INestOpenPrice.sol similarity index 100% rename from contracts/interface/INestOpenPrice.sol rename to contracts/interfaces/INestOpenPrice.sol diff --git a/contracts/interface/INestPriceView.sol b/contracts/interfaces/INestPriceView.sol similarity index 100% rename from contracts/interface/INestPriceView.sol rename to contracts/interfaces/INestPriceView.sol diff --git a/contracts/interface/INestVote.sol b/contracts/interfaces/INestVote.sol similarity index 100% rename from contracts/interface/INestVote.sol rename to contracts/interfaces/INestVote.sol diff --git a/contracts/interface/IProxyAdmin.sol b/contracts/interfaces/IProxyAdmin.sol similarity index 100% rename from contracts/interface/IProxyAdmin.sol rename to contracts/interfaces/IProxyAdmin.sol diff --git a/contracts/interface/IVotePropose.sol b/contracts/interfaces/IVotePropose.sol similarity index 100% rename from contracts/interface/IVotePropose.sol rename to contracts/interfaces/IVotePropose.sol diff --git a/contracts/lib/TransferHelper.sol b/contracts/lib/TransferHelper.sol deleted file mode 100644 index aec0711..0000000 --- a/contracts/lib/TransferHelper.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -pragma solidity ^0.8.6; - -// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false -library TransferHelper { - function safeApprove(address token, address to, uint value) internal { - // bytes4(keccak256(bytes('approve(address,uint256)'))); - (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); - require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); - } - - function safeTransfer(address token, address to, uint value) internal { - // bytes4(keccak256(bytes('transfer(address,uint256)'))); - (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); - require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); - } - - function safeTransferFrom(address token, address from, address to, uint value) internal { - // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); - (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); - require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); - } - - function safeTransferETH(address to, uint value) internal { - (bool success,) = to.call{value:value}(new bytes(0)); - require(success, 'TransferHelper: ETH_TRANSFER_FAILED'); - } -} \ No newline at end of file diff --git a/contracts/lib/Context.sol b/contracts/libs/Context.sol similarity index 100% rename from contracts/lib/Context.sol rename to contracts/libs/Context.sol diff --git a/contracts/lib/ERC20.sol b/contracts/libs/ERC20.sol similarity index 100% rename from contracts/lib/ERC20.sol rename to contracts/libs/ERC20.sol diff --git a/contracts/lib/IERC20.sol b/contracts/libs/IERC20.sol similarity index 100% rename from contracts/lib/IERC20.sol rename to contracts/libs/IERC20.sol diff --git a/contracts/test/NestBatchPlatform3.sol b/contracts/test/NestBatchPlatform3.sol index e9943e9..344bae5 100644 --- a/contracts/test/NestBatchPlatform3.sol +++ b/contracts/test/NestBatchPlatform3.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.6; -import "../lib/TransferHelper.sol"; +import "../libs/TransferHelper.sol"; -import "../interface/INestBatchPriceView.sol"; -import "../interface/INestBatchPrice.sol"; +import "../interfaces/INestBatchPriceView.sol"; +import "../interfaces/INestBatchPrice.sol"; import "../NestBatchMining.sol"; diff --git a/contracts/test/UpdateAdmin.sol b/contracts/test/UpdateAdmin.sol index 309f97e..cb15bdc 100644 --- a/contracts/test/UpdateAdmin.sol +++ b/contracts/test/UpdateAdmin.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.6; -import "../interface/IVotePropose.sol"; -import "../interface/INestMapping.sol"; -import "../interface/INestGovernance.sol"; +import "../interfaces/IVotePropose.sol"; +import "../interfaces/INestMapping.sol"; +import "../interfaces/INestGovernance.sol"; // Add and remove administrators by voting contract UpdateAdmin is IVotePropose { diff --git a/contracts/test/UpdateProxyPropose.sol b/contracts/test/UpdateProxyPropose.sol index e9dd1da..465fcb7 100644 --- a/contracts/test/UpdateProxyPropose.sol +++ b/contracts/test/UpdateProxyPropose.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.6; -import "../interface/IProxyAdmin.sol"; -import "../interface/IVotePropose.sol"; -import "../interface/INestVote.sol"; +import "../interfaces/IProxyAdmin.sol"; +import "../interfaces/IVotePropose.sol"; +import "../interfaces/INestVote.sol"; contract UpdateProxyPropose is IVotePropose { From 6c24322aa80c317355099c4ea2df3c7ced90aa25 Mon Sep 17 00:00:00 2001 From: chenf Date: Sat, 11 Dec 2021 14:50:10 +0800 Subject: [PATCH 13/41] Deploy to rinkeby --- scripts/deploy.js | 2 +- scripts/rinkeby@20211211.js | 198 ++++++++++++++++++++++++++++++++++++ test/deploy.js | 72 +++++++------ 3 files changed, 233 insertions(+), 39 deletions(-) create mode 100644 scripts/rinkeby@20211211.js diff --git a/scripts/deploy.js b/scripts/deploy.js index 36f3883..16bc654 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -5,6 +5,6 @@ // Runtime Environment's members available in the global scope. //const hre = require('hardhat'); -const deploy = require('./deploy.proxy.js'); +const deploy = require('./rinkeby@20211211.js'); exports.deploy = deploy.deploy; \ No newline at end of file diff --git a/scripts/rinkeby@20211211.js b/scripts/rinkeby@20211211.js new file mode 100644 index 0000000..d38195b --- /dev/null +++ b/scripts/rinkeby@20211211.js @@ -0,0 +1,198 @@ +// We require the Hardhat Runtime Environment explicitly here. This is optional +// but useful for running the script in a standalone fashion through `node