From c1ceb9c95c2fec57053357b7ced034f242b263c0 Mon Sep 17 00:00:00 2001 From: Carl Farterson Date: Mon, 21 Feb 2022 13:43:18 -0700 Subject: [PATCH 1/6] refactor: correct facets dir --- .../{Fees.ts => facets/FeesFacet.ts} | 4 +-- .../{Foundry.ts => facets/FoundryFacet.ts} | 30 +++++++++---------- test/contracts/{Hub.ts => facets/HubFacet.ts} | 27 +++++++++-------- .../{registries => facets}/MeTokenRegistry.ts | 0 test/contracts/facets/OwnershipFacet.ts | 0 5 files changed, 32 insertions(+), 29 deletions(-) rename test/contracts/{Fees.ts => facets/FeesFacet.ts} (98%) rename test/contracts/{Foundry.ts => facets/FoundryFacet.ts} (97%) rename test/contracts/{Hub.ts => facets/HubFacet.ts} (97%) rename test/contracts/{registries => facets}/MeTokenRegistry.ts (100%) create mode 100644 test/contracts/facets/OwnershipFacet.ts diff --git a/test/contracts/Fees.ts b/test/contracts/facets/FeesFacet.ts similarity index 98% rename from test/contracts/Fees.ts rename to test/contracts/facets/FeesFacet.ts index 9fce0d05..d22272f4 100644 --- a/test/contracts/Fees.ts +++ b/test/contracts/facets/FeesFacet.ts @@ -1,8 +1,8 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { expect } from "chai"; import { ethers } from "hardhat"; -import { FeesFacet } from "../../artifacts/types/FeesFacet"; -import { hubSetupWithoutRegister } from "../utils/hubSetup"; +import { FeesFacet } from "../../../artifacts/types/FeesFacet"; +import { hubSetupWithoutRegister } from "../../utils/hubSetup"; const setup = async () => { describe("FeesFacet.sol", () => { diff --git a/test/contracts/Foundry.ts b/test/contracts/facets/FoundryFacet.ts similarity index 97% rename from test/contracts/Foundry.ts rename to test/contracts/facets/FoundryFacet.ts index ba468837..dffd187d 100644 --- a/test/contracts/Foundry.ts +++ b/test/contracts/facets/FoundryFacet.ts @@ -1,8 +1,8 @@ import { ethers, getNamedAccounts } from "hardhat"; -import { CurveRegistry } from "../../artifacts/types/CurveRegistry"; -import { FoundryFacet } from "../../artifacts/types/FoundryFacet"; -import { HubFacet } from "../../artifacts/types/HubFacet"; -import { SameAssetTransferMigration } from "../../artifacts/types/SameAssetTransferMigration"; +import { CurveRegistry } from "../../../artifacts/types/CurveRegistry"; +import { FoundryFacet } from "../../../artifacts/types/FoundryFacet"; +import { HubFacet } from "../../../artifacts/types/HubFacet"; +import { SameAssetTransferMigration } from "../../../artifacts/types/SameAssetTransferMigration"; import { calculateCollateralReturned, calculateCollateralToDepositFromZero, @@ -12,20 +12,20 @@ import { fromETHNumber, getContractAt, toETHNumber, -} from "../utils/helpers"; +} from "../../utils/helpers"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { Signer, BigNumber } from "ethers"; -import { BancorABDK } from "../../artifacts/types/BancorABDK"; -import { ERC20 } from "../../artifacts/types/ERC20"; -import { MeTokenRegistryFacet } from "../../artifacts/types/MeTokenRegistryFacet"; -import { MigrationRegistry } from "../../artifacts/types/MigrationRegistry"; -import { SingleAssetVault } from "../../artifacts/types/SingleAssetVault"; -import { mineBlock } from "../utils/hardhatNode"; -import { MeToken } from "../../artifacts/types/MeToken"; +import { BancorABDK } from "../../../artifacts/types/BancorABDK"; +import { ERC20 } from "../../../artifacts/types/ERC20"; +import { MeTokenRegistryFacet } from "../../../artifacts/types/MeTokenRegistryFacet"; +import { MigrationRegistry } from "../../../artifacts/types/MigrationRegistry"; +import { SingleAssetVault } from "../../../artifacts/types/SingleAssetVault"; +import { mineBlock } from "../../utils/hardhatNode"; +import { MeToken } from "../../../artifacts/types/MeToken"; import { expect } from "chai"; -import { UniswapSingleTransferMigration } from "../../artifacts/types/UniswapSingleTransferMigration"; -import { hubSetup } from "../utils/hubSetup"; -import { ICurve } from "../../artifacts/types"; +import { UniswapSingleTransferMigration } from "../../../artifacts/types/UniswapSingleTransferMigration"; +import { hubSetup } from "../../utils/hubSetup"; +import { ICurve } from "../../../artifacts/types"; const setup = async () => { describe("FoundryFacet.sol", () => { diff --git a/test/contracts/Hub.ts b/test/contracts/facets/HubFacet.ts similarity index 97% rename from test/contracts/Hub.ts rename to test/contracts/facets/HubFacet.ts index 064e91d3..f20be9c3 100644 --- a/test/contracts/Hub.ts +++ b/test/contracts/facets/HubFacet.ts @@ -1,19 +1,22 @@ import { ethers, getNamedAccounts } from "hardhat"; -import { HubFacet } from "../../artifacts/types/HubFacet"; -import { FoundryFacet } from "../../artifacts/types/FoundryFacet"; -import { CurveRegistry } from "../../artifacts/types/CurveRegistry"; +import { HubFacet } from "../../../artifacts/types/HubFacet"; +import { FoundryFacet } from "../../../artifacts/types/FoundryFacet"; +import { CurveRegistry } from "../../../artifacts/types/CurveRegistry"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; -import { BancorABDK } from "../../artifacts/types/BancorABDK"; -import { SingleAssetVault } from "../../artifacts/types/SingleAssetVault"; -import { deploy, getContractAt } from "../utils/helpers"; -import { hubSetupWithoutRegister, tranferFromWhale } from "../utils/hubSetup"; +import { BancorABDK } from "../../../artifacts/types/BancorABDK"; +import { SingleAssetVault } from "../../../artifacts/types/SingleAssetVault"; +import { deploy, getContractAt } from "../../utils/helpers"; +import { + hubSetupWithoutRegister, + tranferFromWhale, +} from "../../utils/hubSetup"; import { expect } from "chai"; -import { mineBlock } from "../utils/hardhatNode"; -import { ERC20 } from "../../artifacts/types/ERC20"; +import { mineBlock } from "../../utils/hardhatNode"; +import { ERC20 } from "../../../artifacts/types/ERC20"; import { Signer } from "ethers"; -import { MeTokenRegistryFacet } from "../../artifacts/types/MeTokenRegistryFacet"; -import { MeToken } from "../../artifacts/types/MeToken"; -import { ICurve } from "../../artifacts/types"; +import { MeTokenRegistryFacet } from "../../../artifacts/types/MeTokenRegistryFacet"; +import { MeToken } from "../../../artifacts/types/MeToken"; +import { ICurve } from "../../../artifacts/types"; /* const paginationFactory = await ethers.getContractFactory("Pagination", {}); diff --git a/test/contracts/registries/MeTokenRegistry.ts b/test/contracts/facets/MeTokenRegistry.ts similarity index 100% rename from test/contracts/registries/MeTokenRegistry.ts rename to test/contracts/facets/MeTokenRegistry.ts diff --git a/test/contracts/facets/OwnershipFacet.ts b/test/contracts/facets/OwnershipFacet.ts new file mode 100644 index 00000000..e69de29b From 89dd350ff5450126b7663d15b97229599528af09 Mon Sep 17 00:00:00 2001 From: Carter Carlson Date: Wed, 23 Feb 2022 13:52:35 -0800 Subject: [PATCH 2/6] fix: test name --- .../facets/{MeTokenRegistry.ts => MeTokenRegistryFacet.ts} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename test/contracts/facets/{MeTokenRegistry.ts => MeTokenRegistryFacet.ts} (99%) diff --git a/test/contracts/facets/MeTokenRegistry.ts b/test/contracts/facets/MeTokenRegistryFacet.ts similarity index 99% rename from test/contracts/facets/MeTokenRegistry.ts rename to test/contracts/facets/MeTokenRegistryFacet.ts index 785522ec..952661b9 100644 --- a/test/contracts/facets/MeTokenRegistry.ts +++ b/test/contracts/facets/MeTokenRegistryFacet.ts @@ -969,7 +969,7 @@ const setup = async () => { ).to.be.equal(amountDepositedAfterFee); }); - it("updateBalanceLocked()", async () => { + it("updateBalanceLocked() [TODO]", async () => { const meToken = await getContractAt("MeToken", meTokenAddr1); const meTokenTotalSupply = await meToken.totalSupply(); const buyerMeToken = await meToken.balanceOf(account0.address); @@ -1010,7 +1010,7 @@ const setup = async () => { newMeTokenDetails.balanceLocked.sub(meTokenDetails.balanceLocked) ).to.be.equal(lockedAmount); }); - it("updateBalanceLocked() when owner burns", async () => { + it("updateBalanceLocked() when owner burns [TODO]", async () => { await weth .connect(tokenHolder) .transfer(account1.address, tokenDeposited); From 58e450f08e0aec009f383359274b93ffdbb55444 Mon Sep 17 00:00:00 2001 From: Carter Carlson Date: Wed, 23 Feb 2022 14:02:18 -0800 Subject: [PATCH 3/6] chore: rmv old power contracts --- contracts/curves/BancorPower.sol | 294 ---------------- contracts/curves/Power.sol | 545 ----------------------------- contracts/curves/StepwiseCurve.sol | 270 -------------- 3 files changed, 1109 deletions(-) delete mode 100644 contracts/curves/BancorPower.sol delete mode 100644 contracts/curves/Power.sol delete mode 100644 contracts/curves/StepwiseCurve.sol diff --git a/contracts/curves/BancorPower.sol b/contracts/curves/BancorPower.sol deleted file mode 100644 index 9baef53f..00000000 --- a/contracts/curves/BancorPower.sol +++ /dev/null @@ -1,294 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8; - -import "../utils/ABDKMathQuad.sol"; -import "./Power.sol"; -import "../libs/Details.sol"; -import "../interfaces/ICurve.sol"; - -/** - * @title Bancor formula by Bancor - * @dev Modified from the original by Slava Balasanov - * https://github.com/bancorprotocol/contracts - * Split Power.sol out from BancorFormula.sol and replace SafeMath formulas with zeppelin's SafeMath - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements; - * and to You under the Apache License, Version 2.0. " - */ -contract BancorPower is Power, ICurve { - using ABDKMathQuad for uint256; - using ABDKMathQuad for bytes16; - - struct Bancor { - uint256 baseY; - uint256 targetBaseY; - uint32 reserveWeight; - uint32 targetReserveWeight; - } - - uint32 public constant MAX_WEIGHT = 1e6; - bytes16 private immutable _baseX = uint256(1 ether).fromUInt(); - bytes16 private immutable _maxWeight = uint256(MAX_WEIGHT).fromUInt(); // gas savings - bytes16 private immutable _one = (uint256(1)).fromUInt(); - address public hub; - - // NOTE: keys are the respective hubId - mapping(uint256 => Bancor) private _bancors; - - constructor(address _hub) { - require(_hub != address(0), "!hub"); - hub = _hub; - } - - function register(uint256 _hubId, bytes calldata _encodedDetails) - external - override - { - require(msg.sender == hub, "!hub"); - require(_encodedDetails.length > 0, "!_encodedDetails"); - - (uint256 baseY, uint32 reserveWeight) = abi.decode( - _encodedDetails, - (uint256, uint32) - ); - require(baseY > 0, "!baseY"); - require( - reserveWeight > 0 && reserveWeight <= MAX_WEIGHT, - "!reserveWeight" - ); - - Bancor storage bancor_ = _bancors[_hubId]; - bancor_.baseY = baseY; - bancor_.reserveWeight = reserveWeight; - } - - function initReconfigure(uint256 _hubId, bytes calldata _encodedDetails) - external - override - { - require(msg.sender == hub, "!hub"); - - uint32 targetReserveWeight = abi.decode(_encodedDetails, (uint32)); - Bancor storage bancor_ = _bancors[_hubId]; - - require(targetReserveWeight > 0, "!reserveWeight"); - require( - targetReserveWeight != bancor_.reserveWeight, - "targetWeight!=Weight" - ); - - // targetBaseX = (old baseY * oldR) / newR - uint256 targetBaseY = (bancor_.baseY * bancor_.reserveWeight) / - targetReserveWeight; - - bancor_.targetBaseY = targetBaseY; - bancor_.targetReserveWeight = targetReserveWeight; - } - - function finishReconfigure(uint256 _hubId) external override { - require(msg.sender == hub, "!hub"); - Bancor storage bancor_ = _bancors[_hubId]; - bancor_.reserveWeight = bancor_.targetReserveWeight; - bancor_.baseY = bancor_.targetBaseY; - bancor_.targetReserveWeight = 0; - bancor_.targetBaseY = 0; - } - - function getBancorDetails(uint256 bancor) - external - view - returns (Bancor memory) - { - return _bancors[bancor]; - } - - function getCurveDetails(uint256 bancor) - external - view - override - returns (uint256[4] memory) - { - return [ - _bancors[bancor].baseY, - uint256(_bancors[bancor].reserveWeight), - _bancors[bancor].targetBaseY, - uint256(_bancors[bancor].targetReserveWeight) - ]; - } - - function viewMeTokensMinted( - uint256 _assetsDeposited, - uint256 _hubId, - uint256 _supply, - uint256 _balancePooled - ) external view override returns (uint256 meTokensMinted) { - Bancor memory bancorDetails = _bancors[_hubId]; - if (_supply > 0) { - meTokensMinted = _viewMeTokensMinted( - _assetsDeposited, - bancorDetails.reserveWeight, - _supply, - _balancePooled - ); - } else { - meTokensMinted = _viewMeTokensMintedFromZero( - _assetsDeposited, - bancorDetails.reserveWeight, - bancorDetails.baseY - ); - } - } - - function viewTargetMeTokensMinted( - uint256 _assetsDeposited, - uint256 _hubId, - uint256 _supply, - uint256 _balancePooled - ) external view override returns (uint256 meTokensMinted) { - Bancor memory bancorDetails = _bancors[_hubId]; - if (_supply > 0) { - meTokensMinted = _viewMeTokensMinted( - _assetsDeposited, - bancorDetails.targetReserveWeight, - _supply, - _balancePooled - ); - } else { - meTokensMinted = _viewMeTokensMintedFromZero( - _assetsDeposited, - bancorDetails.targetReserveWeight, - bancorDetails.targetBaseY - ); - } - } - - function viewAssetsReturned( - uint256 _meTokensBurned, - uint256 _hubId, - uint256 _supply, - uint256 _balancePooled - ) external view override returns (uint256 assetsReturned) { - Bancor memory bancorDetails = _bancors[_hubId]; - assetsReturned = _viewAssetsReturned( - _meTokensBurned, - bancorDetails.reserveWeight, - _supply, - _balancePooled - ); - } - - function viewTargetAssetsReturned( - uint256 _meTokensBurned, - uint256 _hubId, - uint256 _supply, - uint256 _balancePooled - ) external view override returns (uint256 assetsReturned) { - Bancor memory bancorDetails = _bancors[_hubId]; - assetsReturned = _viewAssetsReturned( - _meTokensBurned, - bancorDetails.targetReserveWeight, - _supply, - _balancePooled - ); - } - - function _viewMeTokensMinted( - uint256 _depositAmount, - uint32 _connectorWeight, - uint256 _supply, - uint256 _connectorBalance - ) private view returns (uint256) { - // validate input - require( - _connectorBalance > 0 && - _connectorWeight > 0 && - _connectorWeight <= MAX_WEIGHT - ); - // special case for 0 deposit amount - if (_depositAmount == 0) { - return 0; - } - // special case if the weight = 100% - if (_connectorWeight == MAX_WEIGHT) { - // TODO: will ABDK round correctly here? - return (_supply * _depositAmount) / _connectorBalance; - } - uint256 result; - uint8 precision; - uint256 baseN = _depositAmount + _connectorBalance; - (result, precision) = power( - baseN, - _connectorBalance, - _connectorWeight, - MAX_WEIGHT - ); - // TODO: will ABDK shift correctly here? - uint256 newTokenSupply = (_supply * result) >> precision; - return newTokenSupply - _supply; - } - - function _viewMeTokensMintedFromZero( - uint256 _assetsDeposited, - uint256 _reserveWeight, - uint256 _baseY - ) private view returns (uint256) { - bytes16 reserveWeight = _reserveWeight.fromUInt().div(_maxWeight); - // _assetsDeposited * baseY ^ (1/connectorWeight) - bytes16 numerator = _assetsDeposited.fromUInt().mul( - _baseX.ln().mul(_one.div(reserveWeight)).exp() - ); - // as baseX == 1 ether and we want to result to be in ether too we simply remove - // the multiplication by baseY - bytes16 denominator = reserveWeight.mul(_baseY.fromUInt()); - // Instead of calculating "x ^ exp", we calculate "e ^ (log(x) * exp)". - // (numerator/denominator) ^ (reserveWeight ) - // => e^ (log(numerator/denominator) * reserveWeight ) - // => log(numerator/denominator) == (numerator.div(denominator)).ln() - // => (numerator.div(denominator)).ln().mul(reserveWeight).exp(); - bytes16 res = (numerator.div(denominator)) - .ln() - .mul(reserveWeight) - .exp(); - - return res.toUInt(); - } - - function _viewAssetsReturned( - uint256 _sellAmount, - uint32 _connectorWeight, - uint256 _supply, - uint256 _connectorBalance - ) private view returns (uint256) { - // validate input - require( - _supply > 0 && - _connectorBalance > 0 && - _connectorWeight > 0 && - _connectorWeight <= MAX_WEIGHT && - _sellAmount <= _supply - ); - // special case for 0 sell amount - if (_sellAmount == 0) { - return 0; - } - // special case for selling the entire supply - if (_sellAmount == _supply) { - return _connectorBalance; - } - // special case if the weight = 100% - if (_connectorWeight == MAX_WEIGHT) { - return (_connectorBalance * _sellAmount) / _supply; - } - uint256 result; - uint8 precision; - uint256 baseD = _supply - _sellAmount; - (result, precision) = power( - _supply, - baseD, - MAX_WEIGHT, - _connectorWeight - ); - uint256 oldBalance = _connectorBalance * result; - uint256 newBalance = _connectorBalance << precision; - return (oldBalance - newBalance) / result; - } -} diff --git a/contracts/curves/Power.sol b/contracts/curves/Power.sol deleted file mode 100644 index 8cf9ec7d..00000000 --- a/contracts/curves/Power.sol +++ /dev/null @@ -1,545 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8; - -/** - * @title Power function by Bancor - * @dev https://github.com/bancorprotocol/contracts - * - * Modified from the original by Slava Balasanov & Tarrence van As - * - * Split Power.sol out from BancorFormula.sol - */ -contract Power { - string public version = "0.3"; - - uint256 private constant ONE = 1; - uint8 private constant MIN_PRECISION = 32; - uint8 private constant MAX_PRECISION = 127; - - uint256 private constant FIXED_1 = 0x080000000000000000000000000000000; - uint256 private constant FIXED_2 = 0x100000000000000000000000000000000; - uint256 private constant MAX_NUM = 0x200000000000000000000000000000000; - - uint256 private constant LN2_NUMERATOR = 0x3f80fe03f80fe03f80fe03f80fe03f8; - uint256 private constant LN2_DENOMINATOR = - 0x5b9de1d10bf4103d647b0955897ba80; - - uint256 private constant OPT_LOG_MAX_VAL = - 0x15bf0a8b1457695355fb8ac404e7a79e3; - uint256 private constant OPT_EXP_MAX_VAL = - 0x800000000000000000000000000000000; - - uint256[128] private maxExpArray; - - constructor() { - // maxExpArray[0] = 0x6bffffffffffffffffffffffffffffffff; - // maxExpArray[1] = 0x67ffffffffffffffffffffffffffffffff; - // maxExpArray[2] = 0x637fffffffffffffffffffffffffffffff; - // maxExpArray[3] = 0x5f6fffffffffffffffffffffffffffffff; - // maxExpArray[4] = 0x5b77ffffffffffffffffffffffffffffff; - // maxExpArray[5] = 0x57b3ffffffffffffffffffffffffffffff; - // maxExpArray[6] = 0x5419ffffffffffffffffffffffffffffff; - // maxExpArray[7] = 0x50a2ffffffffffffffffffffffffffffff; - // maxExpArray[8] = 0x4d517fffffffffffffffffffffffffffff; - // maxExpArray[9] = 0x4a233fffffffffffffffffffffffffffff; - // maxExpArray[10] = 0x47165fffffffffffffffffffffffffffff; - // maxExpArray[11] = 0x4429afffffffffffffffffffffffffffff; - // maxExpArray[12] = 0x415bc7ffffffffffffffffffffffffffff; - // maxExpArray[13] = 0x3eab73ffffffffffffffffffffffffffff; - // maxExpArray[14] = 0x3c1771ffffffffffffffffffffffffffff; - // maxExpArray[15] = 0x399e96ffffffffffffffffffffffffffff; - // maxExpArray[16] = 0x373fc47fffffffffffffffffffffffffff; - // maxExpArray[17] = 0x34f9e8ffffffffffffffffffffffffffff; - // maxExpArray[18] = 0x32cbfd5fffffffffffffffffffffffffff; - // maxExpArray[19] = 0x30b5057fffffffffffffffffffffffffff; - // maxExpArray[20] = 0x2eb40f9fffffffffffffffffffffffffff; - // maxExpArray[21] = 0x2cc8340fffffffffffffffffffffffffff; - // maxExpArray[22] = 0x2af09481ffffffffffffffffffffffffff; - // maxExpArray[23] = 0x292c5bddffffffffffffffffffffffffff; - // maxExpArray[24] = 0x277abdcdffffffffffffffffffffffffff; - // maxExpArray[25] = 0x25daf6657fffffffffffffffffffffffff; - // maxExpArray[26] = 0x244c49c65fffffffffffffffffffffffff; - // maxExpArray[27] = 0x22ce03cd5fffffffffffffffffffffffff; - // maxExpArray[28] = 0x215f77c047ffffffffffffffffffffffff; - // maxExpArray[29] = 0x1fffffffffffffffffffffffffffffffff; - // maxExpArray[30] = 0x1eaefdbdabffffffffffffffffffffffff; - // maxExpArray[31] = 0x1d6bd8b2ebffffffffffffffffffffffff; - maxExpArray[32] = 0x1c35fedd14ffffffffffffffffffffffff; - maxExpArray[33] = 0x1b0ce43b323fffffffffffffffffffffff; - maxExpArray[34] = 0x19f0028ec1ffffffffffffffffffffffff; - maxExpArray[35] = 0x18ded91f0e7fffffffffffffffffffffff; - maxExpArray[36] = 0x17d8ec7f0417ffffffffffffffffffffff; - maxExpArray[37] = 0x16ddc6556cdbffffffffffffffffffffff; - maxExpArray[38] = 0x15ecf52776a1ffffffffffffffffffffff; - maxExpArray[39] = 0x15060c256cb2ffffffffffffffffffffff; - maxExpArray[40] = 0x1428a2f98d72ffffffffffffffffffffff; - maxExpArray[41] = 0x13545598e5c23fffffffffffffffffffff; - maxExpArray[42] = 0x1288c4161ce1dfffffffffffffffffffff; - maxExpArray[43] = 0x11c592761c666fffffffffffffffffffff; - maxExpArray[44] = 0x110a688680a757ffffffffffffffffffff; - maxExpArray[45] = 0x1056f1b5bedf77ffffffffffffffffffff; - maxExpArray[46] = 0x0faadceceeff8bffffffffffffffffffff; - maxExpArray[47] = 0x0f05dc6b27edadffffffffffffffffffff; - maxExpArray[48] = 0x0e67a5a25da4107fffffffffffffffffff; - maxExpArray[49] = 0x0dcff115b14eedffffffffffffffffffff; - maxExpArray[50] = 0x0d3e7a392431239fffffffffffffffffff; - maxExpArray[51] = 0x0cb2ff529eb71e4fffffffffffffffffff; - maxExpArray[52] = 0x0c2d415c3db974afffffffffffffffffff; - maxExpArray[53] = 0x0bad03e7d883f69bffffffffffffffffff; - maxExpArray[54] = 0x0b320d03b2c343d5ffffffffffffffffff; - maxExpArray[55] = 0x0abc25204e02828dffffffffffffffffff; - maxExpArray[56] = 0x0a4b16f74ee4bb207fffffffffffffffff; - maxExpArray[57] = 0x09deaf736ac1f569ffffffffffffffffff; - maxExpArray[58] = 0x0976bd9952c7aa957fffffffffffffffff; - maxExpArray[59] = 0x09131271922eaa606fffffffffffffffff; - maxExpArray[60] = 0x08b380f3558668c46fffffffffffffffff; - maxExpArray[61] = 0x0857ddf0117efa215bffffffffffffffff; - maxExpArray[62] = 0x07ffffffffffffffffffffffffffffffff; - maxExpArray[63] = 0x07abbf6f6abb9d087fffffffffffffffff; - maxExpArray[64] = 0x075af62cbac95f7dfa7fffffffffffffff; - maxExpArray[65] = 0x070d7fb7452e187ac13fffffffffffffff; - maxExpArray[66] = 0x06c3390ecc8af379295fffffffffffffff; - maxExpArray[67] = 0x067c00a3b07ffc01fd6fffffffffffffff; - maxExpArray[68] = 0x0637b647c39cbb9d3d27ffffffffffffff; - maxExpArray[69] = 0x05f63b1fc104dbd39587ffffffffffffff; - maxExpArray[70] = 0x05b771955b36e12f7235ffffffffffffff; - maxExpArray[71] = 0x057b3d49dda84556d6f6ffffffffffffff; - maxExpArray[72] = 0x054183095b2c8ececf30ffffffffffffff; - maxExpArray[73] = 0x050a28be635ca2b888f77fffffffffffff; - maxExpArray[74] = 0x04d5156639708c9db33c3fffffffffffff; - maxExpArray[75] = 0x04a23105873875bd52dfdfffffffffffff; - maxExpArray[76] = 0x0471649d87199aa990756fffffffffffff; - maxExpArray[77] = 0x04429a21a029d4c1457cfbffffffffffff; - maxExpArray[78] = 0x0415bc6d6fb7dd71af2cb3ffffffffffff; - maxExpArray[79] = 0x03eab73b3bbfe282243ce1ffffffffffff; - maxExpArray[80] = 0x03c1771ac9fb6b4c18e229ffffffffffff; - maxExpArray[81] = 0x0399e96897690418f785257fffffffffff; - maxExpArray[82] = 0x0373fc456c53bb779bf0ea9fffffffffff; - maxExpArray[83] = 0x034f9e8e490c48e67e6ab8bfffffffffff; - maxExpArray[84] = 0x032cbfd4a7adc790560b3337ffffffffff; - maxExpArray[85] = 0x030b50570f6e5d2acca94613ffffffffff; - maxExpArray[86] = 0x02eb40f9f620fda6b56c2861ffffffffff; - maxExpArray[87] = 0x02cc8340ecb0d0f520a6af58ffffffffff; - maxExpArray[88] = 0x02af09481380a0a35cf1ba02ffffffffff; - maxExpArray[89] = 0x0292c5bdd3b92ec810287b1b3fffffffff; - maxExpArray[90] = 0x0277abdcdab07d5a77ac6d6b9fffffffff; - maxExpArray[91] = 0x025daf6654b1eaa55fd64df5efffffffff; - maxExpArray[92] = 0x0244c49c648baa98192dce88b7ffffffff; - maxExpArray[93] = 0x022ce03cd5619a311b2471268bffffffff; - maxExpArray[94] = 0x0215f77c045fbe885654a44a0fffffffff; - maxExpArray[95] = 0x01ffffffffffffffffffffffffffffffff; - maxExpArray[96] = 0x01eaefdbdaaee7421fc4d3ede5ffffffff; - maxExpArray[97] = 0x01d6bd8b2eb257df7e8ca57b09bfffffff; - maxExpArray[98] = 0x01c35fedd14b861eb0443f7f133fffffff; - maxExpArray[99] = 0x01b0ce43b322bcde4a56e8ada5afffffff; - maxExpArray[100] = 0x019f0028ec1fff007f5a195a39dfffffff; - maxExpArray[101] = 0x018ded91f0e72ee74f49b15ba527ffffff; - maxExpArray[102] = 0x017d8ec7f04136f4e5615fd41a63ffffff; - maxExpArray[103] = 0x016ddc6556cdb84bdc8d12d22e6fffffff; - maxExpArray[104] = 0x015ecf52776a1155b5bd8395814f7fffff; - maxExpArray[105] = 0x015060c256cb23b3b3cc3754cf40ffffff; - maxExpArray[106] = 0x01428a2f98d728ae223ddab715be3fffff; - maxExpArray[107] = 0x013545598e5c23276ccf0ede68034fffff; - maxExpArray[108] = 0x01288c4161ce1d6f54b7f61081194fffff; - maxExpArray[109] = 0x011c592761c666aa641d5a01a40f17ffff; - maxExpArray[110] = 0x0110a688680a7530515f3e6e6cfdcdffff; - maxExpArray[111] = 0x01056f1b5bedf75c6bcb2ce8aed428ffff; - maxExpArray[112] = 0x00faadceceeff8a0890f3875f008277fff; - maxExpArray[113] = 0x00f05dc6b27edad306388a600f6ba0bfff; - maxExpArray[114] = 0x00e67a5a25da41063de1495d5b18cdbfff; - maxExpArray[115] = 0x00dcff115b14eedde6fc3aa5353f2e4fff; - maxExpArray[116] = 0x00d3e7a3924312399f9aae2e0f868f8fff; - maxExpArray[117] = 0x00cb2ff529eb71e41582cccd5a1ee26fff; - maxExpArray[118] = 0x00c2d415c3db974ab32a51840c0b67edff; - maxExpArray[119] = 0x00bad03e7d883f69ad5b0a186184e06bff; - maxExpArray[120] = 0x00b320d03b2c343d4829abd6075f0cc5ff; - maxExpArray[121] = 0x00abc25204e02828d73c6e80bcdb1a95bf; - maxExpArray[122] = 0x00a4b16f74ee4bb2040a1ec6c15fbbf2df; - maxExpArray[123] = 0x009deaf736ac1f569deb1b5ae3f36c130f; - maxExpArray[124] = 0x00976bd9952c7aa957f5937d790ef65037; - maxExpArray[125] = 0x009131271922eaa6064b73a22d0bd4f2bf; - maxExpArray[126] = 0x008b380f3558668c46c91c49a2f8e967b9; - maxExpArray[127] = 0x00857ddf0117efa215952912839f6473e6; - } - - /** - General Description: - Determine a value of precision. - Calculate an integer approximation of (_baseN / _baseD) ^ (_expN / _expD) * 2 ^ precision. - Return the result along with the precision used. - Detailed Description: - Instead of calculating "base ^ exp", we calculate "e ^ (log(base) * exp)". - The value of "log(base)" is represented with an integer slightly smaller than "log(base) * 2 ^ precision". - The larger "precision" is, the more accurately this value represents the real value. - However, the larger "precision" is, the more bits are required in order to store this value. - And the exponentiation function, which takes "x" and calculates "e ^ x", is limited to a maximum exponent (maximum value of "x"). - This maximum exponent depends on the "precision" used, and it is given by "maxExpArray[precision] >> (MAX_PRECISION - precision)". - Hence we need to determine the highest precision which can be used for the given input, before calling the exponentiation function. - This allows us to compute "base ^ exp" with maximum accuracy and without exceeding 256 bits in any of the intermediate computations. - This functions assumes that "_expN < 2 ^ 256 / log(MAX_NUM - 1)", otherwise the multiplication should be replaced with a "safeMul". - */ - function power( - uint256 _baseN, - uint256 _baseD, - uint32 _expN, - uint32 _expD - ) internal view returns (uint256, uint8) { - assert(_baseN < MAX_NUM); - require(_baseN >= _baseD, "Bases < 1 are not supported."); - - uint256 baseLog; - uint256 base = (_baseN * FIXED_1) / _baseD; - if (base < OPT_LOG_MAX_VAL) { - baseLog = optimalLog(base); - } else { - baseLog = generalLog(base); - } - - uint256 baseLogTimesExp = (baseLog * _expN) / _expD; - if (baseLogTimesExp < OPT_EXP_MAX_VAL) { - return (optimalExp(baseLogTimesExp), MAX_PRECISION); - } else { - uint8 precision = findPositionInMaxExpArray(baseLogTimesExp); - return ( - generalExp( - baseLogTimesExp >> (MAX_PRECISION - precision), - precision - ), - precision - ); - } - } - - /** - Compute log(x / FIXED_1) * FIXED_1. - This functions assumes that "x >= FIXED_1", because the output would be negative otherwise. - */ - function generalLog(uint256 _x) internal pure returns (uint256) { - uint256 res = 0; - uint256 x = _x; - - // If x >= 2, then we compute the integer part of log2(x), which is larger than 0. - if (x >= FIXED_2) { - uint8 count = floorLog2(x / FIXED_1); - x >>= count; // now x < 2 - res = count * FIXED_1; - } - - // If x > 1, then we compute the fraction part of log2(x), which is larger than 0. - if (x > FIXED_1) { - for (uint8 i = MAX_PRECISION; i > 0; --i) { - x = (x * x) / FIXED_1; // now 1 < x < 4 - if (x >= FIXED_2) { - x >>= 1; // now 1 < x < 2 - res += ONE << (i - 1); - } - } - } - - return (res * LN2_NUMERATOR) / LN2_DENOMINATOR; - } - - /** - Compute the largest integer smaller than or equal to the binary logarithm of the input. - */ - function floorLog2(uint256 _n) internal pure returns (uint8) { - uint8 res = 0; - uint256 n = _n; - - if (n < 256) { - // At most 8 iterations - while (n > 1) { - n >>= 1; - res += 1; - } - } else { - // Exactly 8 iterations - for (uint8 s = 128; s > 0; s >>= 1) { - if (n >= (ONE << s)) { - n >>= s; - res |= s; - } - } - } - - return res; - } - - /** - The global "maxExpArray" is sorted in descending order, and therefore the following statements are equivalent: - - This function finds the position of [the smallest value in "maxExpArray" larger than or equal to "x"] - - This function finds the highest position of [a value in "maxExpArray" larger than or equal to "x"] - */ - function findPositionInMaxExpArray(uint256 _x) - internal - view - returns (uint8) - { - uint8 lo = MIN_PRECISION; - uint8 hi = MAX_PRECISION; - - while (lo + 1 < hi) { - uint8 mid = (lo + hi) / 2; - if (maxExpArray[mid] >= _x) lo = mid; - else hi = mid; - } - - if (maxExpArray[hi] >= _x) return hi; - if (maxExpArray[lo] >= _x) return lo; - - assert(false); - return 0; - } - - /* solium-disable */ - /** - This function can be auto-generated by the script 'PrintFunctionGeneralExp.py'. - It approximates "e ^ x" via maclaurin summation: "(x^0)/0! + (x^1)/1! + ... + (x^n)/n!". - It returns "e ^ (x / 2 ^ precision) * 2 ^ precision", that is, the result is upshifted for accuracy. - The global "maxExpArray" maps each "precision" to "((maximumExponent + 1) << (MAX_PRECISION - precision)) - 1". - The maximum permitted value for "x" is therefore given by "maxExpArray[precision] >> (MAX_PRECISION - precision)". - */ - function generalExp(uint256 _x, uint8 _precision) - internal - pure - returns (uint256) - { - uint256 xi = _x; - uint256 res = 0; - - xi = (xi * _x) >> _precision; - res += xi * 0x3442c4e6074a82f1797f72ac0000000; // add x^02 * (33! / 02!) - xi = (xi * _x) >> _precision; - res += xi * 0x116b96f757c380fb287fd0e40000000; // add x^03 * (33! / 03!) - xi = (xi * _x) >> _precision; - res += xi * 0x045ae5bdd5f0e03eca1ff4390000000; // add x^04 * (33! / 04!) - xi = (xi * _x) >> _precision; - res += xi * 0x00defabf91302cd95b9ffda50000000; // add x^05 * (33! / 05!) - xi = (xi * _x) >> _precision; - res += xi * 0x002529ca9832b22439efff9b8000000; // add x^06 * (33! / 06!) - xi = (xi * _x) >> _precision; - res += xi * 0x00054f1cf12bd04e516b6da88000000; // add x^07 * (33! / 07!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000a9e39e257a09ca2d6db51000000; // add x^08 * (33! / 08!) - xi = (xi * _x) >> _precision; - res += xi * 0x000012e066e7b839fa050c309000000; // add x^09 * (33! / 09!) - xi = (xi * _x) >> _precision; - res += xi * 0x000001e33d7d926c329a1ad1a800000; // add x^10 * (33! / 10!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000002bee513bdb4a6b19b5f800000; // add x^11 * (33! / 11!) - xi = (xi * _x) >> _precision; - res += xi * 0x00000003a9316fa79b88eccf2a00000; // add x^12 * (33! / 12!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000000048177ebe1fa812375200000; // add x^13 * (33! / 13!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000000005263fe90242dcbacf00000; // add x^14 * (33! / 14!) - xi = (xi * _x) >> _precision; - res += xi * 0x000000000057e22099c030d94100000; // add x^15 * (33! / 15!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000000000057e22099c030d9410000; // add x^16 * (33! / 16!) - xi = (xi * _x) >> _precision; - res += xi * 0x00000000000052b6b54569976310000; // add x^17 * (33! / 17!) - xi = (xi * _x) >> _precision; - res += xi * 0x00000000000004985f67696bf748000; // add x^18 * (33! / 18!) - xi = (xi * _x) >> _precision; - res += xi * 0x000000000000003dea12ea99e498000; // add x^19 * (33! / 19!) - xi = (xi * _x) >> _precision; - res += xi * 0x00000000000000031880f2214b6e000; // add x^20 * (33! / 20!) - xi = (xi * _x) >> _precision; - res += xi * 0x000000000000000025bcff56eb36000; // add x^21 * (33! / 21!) - xi = (xi * _x) >> _precision; - res += xi * 0x000000000000000001b722e10ab1000; // add x^22 * (33! / 22!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000000000000000001317c70077000; // add x^23 * (33! / 23!) - xi = (xi * _x) >> _precision; - res += xi * 0x00000000000000000000cba84aafa00; // add x^24 * (33! / 24!) - xi = (xi * _x) >> _precision; - res += xi * 0x00000000000000000000082573a0a00; // add x^25 * (33! / 25!) - xi = (xi * _x) >> _precision; - res += xi * 0x00000000000000000000005035ad900; // add x^26 * (33! / 26!) - xi = (xi * _x) >> _precision; - res += xi * 0x000000000000000000000002f881b00; // add x^27 * (33! / 27!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000000000000000000000001b29340; // add x^28 * (33! / 28!) - xi = (xi * _x) >> _precision; - res += xi * 0x00000000000000000000000000efc40; // add x^29 * (33! / 29!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000000000000000000000000007fe0; // add x^30 * (33! / 30!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000000000000000000000000000420; // add x^31 * (33! / 31!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000000000000000000000000000021; // add x^32 * (33! / 32!) - xi = (xi * _x) >> _precision; - res += xi * 0x0000000000000000000000000000001; // add x^33 * (33! / 33!) - - return - res / 0x688589cc0e9505e2f2fee5580000000 + _x + (ONE << _precision); // divide by 33! and then add x^1 / 1! + x^0 / 0! - } - - /** - Return log(x / FIXED_1) * FIXED_1 - Input range: FIXED_1 <= x <= LOG_EXP_MAX_VAL - 1 - Auto-generated via 'PrintFunctionOptimalLog.py' - */ - function optimalLog(uint256 x) internal pure returns (uint256) { - uint256 res = 0; - - uint256 y; - uint256 z; - uint256 w; - - if (x >= 0xd3094c70f034de4b96ff7d5b6f99fcd8) { - res += 0x40000000000000000000000000000000; - x = (x * FIXED_1) / 0xd3094c70f034de4b96ff7d5b6f99fcd8; - } - if (x >= 0xa45af1e1f40c333b3de1db4dd55f29a7) { - res += 0x20000000000000000000000000000000; - x = (x * FIXED_1) / 0xa45af1e1f40c333b3de1db4dd55f29a7; - } - if (x >= 0x910b022db7ae67ce76b441c27035c6a1) { - res += 0x10000000000000000000000000000000; - x = (x * FIXED_1) / 0x910b022db7ae67ce76b441c27035c6a1; - } - if (x >= 0x88415abbe9a76bead8d00cf112e4d4a8) { - res += 0x08000000000000000000000000000000; - x = (x * FIXED_1) / 0x88415abbe9a76bead8d00cf112e4d4a8; - } - if (x >= 0x84102b00893f64c705e841d5d4064bd3) { - res += 0x04000000000000000000000000000000; - x = (x * FIXED_1) / 0x84102b00893f64c705e841d5d4064bd3; - } - if (x >= 0x8204055aaef1c8bd5c3259f4822735a2) { - res += 0x02000000000000000000000000000000; - x = (x * FIXED_1) / 0x8204055aaef1c8bd5c3259f4822735a2; - } - if (x >= 0x810100ab00222d861931c15e39b44e99) { - res += 0x01000000000000000000000000000000; - x = (x * FIXED_1) / 0x810100ab00222d861931c15e39b44e99; - } - if (x >= 0x808040155aabbbe9451521693554f733) { - res += 0x00800000000000000000000000000000; - x = (x * FIXED_1) / 0x808040155aabbbe9451521693554f733; - } - - z = y = x - FIXED_1; - w = (y * y) / FIXED_1; - res += - (z * (0x100000000000000000000000000000000 - y)) / - 0x100000000000000000000000000000000; - z = (z * w) / FIXED_1; - res += - (z * (0x0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - y)) / - 0x200000000000000000000000000000000; - z = (z * w) / FIXED_1; - res += - (z * (0x099999999999999999999999999999999 - y)) / - 0x300000000000000000000000000000000; - z = (z * w) / FIXED_1; - res += - (z * (0x092492492492492492492492492492492 - y)) / - 0x400000000000000000000000000000000; - z = (z * w) / FIXED_1; - res += - (z * (0x08e38e38e38e38e38e38e38e38e38e38e - y)) / - 0x500000000000000000000000000000000; - z = (z * w) / FIXED_1; - res += - (z * (0x08ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8b - y)) / - 0x600000000000000000000000000000000; - z = (z * w) / FIXED_1; - res += - (z * (0x089d89d89d89d89d89d89d89d89d89d89 - y)) / - 0x700000000000000000000000000000000; - z = (z * w) / FIXED_1; - res += - (z * (0x088888888888888888888888888888888 - y)) / - 0x800000000000000000000000000000000; - - return res; - } - - /** - Return e ^ (x / FIXED_1) * FIXED_1 - Input range: 0 <= x <= OPT_EXP_MAX_VAL - 1 - Auto-generated via 'PrintFunctionOptimalExp.py' - */ - function optimalExp(uint256 x) internal pure returns (uint256) { - uint256 res = 0; - - uint256 y; - uint256 z; - - z = y = x % 0x10000000000000000000000000000000; - z = (z * y) / FIXED_1; - res += z * 0x10e1b3be415a0000; // add y^02 * (20! / 02!) - z = (z * y) / FIXED_1; - res += z * 0x05a0913f6b1e0000; // add y^03 * (20! / 03!) - z = (z * y) / FIXED_1; - res += z * 0x0168244fdac78000; // add y^04 * (20! / 04!) - z = (z * y) / FIXED_1; - res += z * 0x004807432bc18000; // add y^05 * (20! / 05!) - z = (z * y) / FIXED_1; - res += z * 0x000c0135dca04000; // add y^06 * (20! / 06!) - z = (z * y) / FIXED_1; - res += z * 0x0001b707b1cdc000; // add y^07 * (20! / 07!) - z = (z * y) / FIXED_1; - res += z * 0x000036e0f639b800; // add y^08 * (20! / 08!) - z = (z * y) / FIXED_1; - res += z * 0x00000618fee9f800; // add y^09 * (20! / 09!) - z = (z * y) / FIXED_1; - res += z * 0x0000009c197dcc00; // add y^10 * (20! / 10!) - z = (z * y) / FIXED_1; - res += z * 0x0000000e30dce400; // add y^11 * (20! / 11!) - z = (z * y) / FIXED_1; - res += z * 0x000000012ebd1300; // add y^12 * (20! / 12!) - z = (z * y) / FIXED_1; - res += z * 0x0000000017499f00; // add y^13 * (20! / 13!) - z = (z * y) / FIXED_1; - res += z * 0x0000000001a9d480; // add y^14 * (20! / 14!) - z = (z * y) / FIXED_1; - res += z * 0x00000000001c6380; // add y^15 * (20! / 15!) - z = (z * y) / FIXED_1; - res += z * 0x000000000001c638; // add y^16 * (20! / 16!) - z = (z * y) / FIXED_1; - res += z * 0x0000000000001ab8; // add y^17 * (20! / 17!) - z = (z * y) / FIXED_1; - res += z * 0x000000000000017c; // add y^18 * (20! / 18!) - z = (z * y) / FIXED_1; - res += z * 0x0000000000000014; // add y^19 * (20! / 19!) - z = (z * y) / FIXED_1; - res += z * 0x0000000000000001; // add y^20 * (20! / 20!) - res = res / 0x21c3677c82b40000 + y + FIXED_1; // divide by 20! and then add y^1 / 1! + y^0 / 0! - - if ((x & 0x010000000000000000000000000000000) != 0) - res = - (res * 0x1c3d6a24ed82218787d624d3e5eba95f9) / - 0x18ebef9eac820ae8682b9793ac6d1e776; - if ((x & 0x020000000000000000000000000000000) != 0) - res = - (res * 0x18ebef9eac820ae8682b9793ac6d1e778) / - 0x1368b2fc6f9609fe7aceb46aa619baed4; - if ((x & 0x040000000000000000000000000000000) != 0) - res = - (res * 0x1368b2fc6f9609fe7aceb46aa619baed5) / - 0x0bc5ab1b16779be3575bd8f0520a9f21f; - if ((x & 0x080000000000000000000000000000000) != 0) - res = - (res * 0x0bc5ab1b16779be3575bd8f0520a9f21e) / - 0x0454aaa8efe072e7f6ddbab84b40a55c9; - if ((x & 0x100000000000000000000000000000000) != 0) - res = - (res * 0x0454aaa8efe072e7f6ddbab84b40a55c5) / - 0x00960aadc109e7a3bf4578099615711ea; - if ((x & 0x200000000000000000000000000000000) != 0) - res = - (res * 0x00960aadc109e7a3bf4578099615711d7) / - 0x0002bf84208204f5977f9a8cf01fdce3d; - if ((x & 0x400000000000000000000000000000000) != 0) - res = - (res * 0x0002bf84208204f5977f9a8cf01fdc307) / - 0x0000003c6ab775dd0b95b4cbee7e65d11; - - return res; - } - /* solium-enable */ -} diff --git a/contracts/curves/StepwiseCurve.sol b/contracts/curves/StepwiseCurve.sol deleted file mode 100644 index c563ffbd..00000000 --- a/contracts/curves/StepwiseCurve.sol +++ /dev/null @@ -1,270 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.0; - -import "../interfaces/ICurve.sol"; - -import "../libs/WeightedAverage.sol"; - -import "../utils/ABDKMathQuad.sol"; - -/// @title Stepwise curve registry and calculator -/// @author Carl Farterson (@carlfarterson) & Chris Robison (@CBobRobison) -contract StepwiseCurve is ICurve { - using ABDKMathQuad for uint256; - using ABDKMathQuad for bytes16; - struct Stepwise { - uint256 stepX; - uint256 stepY; - uint256 targetStepX; - uint256 targetStepY; - } - - uint256 public constant PRECISION = 10**18; - address public hub; - // NOTE: keys are their respective hubId - mapping(uint256 => Stepwise) private _stepwises; - - constructor(address _hub) { - require(_hub != address(0), "!hub"); - hub = _hub; - } - - function register(uint256 _hubId, bytes calldata _encodedDetails) - external - override - { - require(msg.sender == hub, "!hub"); - require(_encodedDetails.length > 0, "!_encodedDetails"); - (uint256 stepX, uint256 stepY) = abi.decode( - _encodedDetails, - (uint256, uint256) - ); - require(stepX > 0 && stepX > PRECISION, "stepX not in range"); - require(stepY > 0 && stepY > PRECISION, "stepY not in range"); - - Stepwise storage stepwise_ = _stepwises[_hubId]; - stepwise_.stepX = stepX; - stepwise_.stepY = stepY; - } - - function initReconfigure(uint256 _hubId, bytes calldata _encodedDetails) - external - override - { - require(msg.sender == hub, "!hub"); - - // TODO: does this require statement need to be added to BancorZeroFormula.sol initReconfigure() as well? - // require(_encodedDetails.length > 0, "_encodedDetails empty"); - - (uint256 targetStepX, uint256 targetStepY) = abi.decode( - _encodedDetails, - (uint256, uint256) - ); - Stepwise storage stepwiseDetails = _stepwises[_hubId]; - - require( - targetStepX > 0 && targetStepX < PRECISION, - "stepX not in range" - ); - require(targetStepX != stepwiseDetails.stepX, "targeStepX == stepX"); - - require( - targetStepY > 0 && targetStepY < PRECISION, - "stepY not in range" - ); - require(targetStepY != stepwiseDetails.stepY, "targeStepY == stepY"); - - stepwiseDetails.targetStepY = targetStepY; - stepwiseDetails.targetStepX = targetStepX; - } - - function finishReconfigure(uint256 _hubId) external override { - require(msg.sender == hub, "!hub"); - Stepwise storage stepwise_ = _stepwises[_hubId]; - stepwise_.stepX = stepwise_.targetStepX; - stepwise_.stepY = stepwise_.targetStepY; - stepwise_.targetStepX = 0; - stepwise_.targetStepY = 0; - } - - function getStepWiseDetails(uint256 stepwise) - external - view - returns (Stepwise memory) - { - return _stepwises[stepwise]; - } - - function getCurveDetails(uint256 stepwise) - external - view - override - returns (uint256[4] memory) - { - return [ - _stepwises[stepwise].stepX, - _stepwises[stepwise].stepY, - _stepwises[stepwise].targetStepX, - _stepwises[stepwise].targetStepY - ]; - } - - function viewMeTokensMinted( - uint256 _assetsDeposited, // assets deposited - uint256 _hubId, // hubId - uint256 _supply, // current supply - uint256 _balancePooled // current collateral amount - ) external view override returns (uint256 meTokensMinted) { - Stepwise memory stepwiseDetails = _stepwises[_hubId]; - meTokensMinted = _viewMeTokensMinted( - _assetsDeposited, - stepwiseDetails.stepX, - stepwiseDetails.stepY, - _supply, - _balancePooled - ); - } - - function viewTargetMeTokensMinted( - uint256 _assetsDeposited, // assets deposited - uint256 _hubId, // hubId - uint256 _supply, // current supply - uint256 _balancePooled // current collateral amount - ) external view override returns (uint256 meTokensMinted) { - Stepwise memory stepwiseDetails = _stepwises[_hubId]; - meTokensMinted = _viewMeTokensMinted( - _assetsDeposited, - stepwiseDetails.targetStepX, - stepwiseDetails.targetStepY, - _supply, - _balancePooled - ); - } - - function viewAssetsReturned( - uint256 _meTokensBurned, - uint256 _hubId, - uint256 _supply, - uint256 _balancePooled - ) external view override returns (uint256 assetsReturned) { - Stepwise memory stepwiseDetails = _stepwises[_hubId]; - assetsReturned = _viewAssetsReturned( - _meTokensBurned, - stepwiseDetails.stepX, - stepwiseDetails.stepY, - _supply, - _balancePooled - ); - } - - function viewTargetAssetsReturned( - uint256 _meTokensBurned, - uint256 _hubId, - uint256 _supply, - uint256 _balancePooled - ) external view override returns (uint256 assetsReturned) { - Stepwise memory stepwiseDetails = _stepwises[_hubId]; - assetsReturned = _viewAssetsReturned( - _meTokensBurned, - stepwiseDetails.targetStepX, - stepwiseDetails.targetStepY, - _supply, - _balancePooled - ); - } - - /// @notice Given a deposit (in the connector token), length of stepX, height of stepY, meToken supply and - /// balance pooled, calculate the return for a given conversion (in the meToken) - /// @param _assetsDeposited, // assets deposited - /// @param _stepX, // length of step (aka supply duration) - /// @param _stepY, // height of step (aka price delta) - /// @param _supply, // current supply - /// @param _balancePooled // current collateral amount - /// @return amount of meTokens minted - function _viewMeTokensMinted( - uint256 _assetsDeposited, // assets deposited - uint256 _stepX, // length of step (aka supply duration) - uint256 _stepY, // height of step (aka price delta) - uint256 _supply, // current supply - uint256 _balancePooled // current collateral amount - ) private pure returns (uint256) { - // special case for 0 deposit amount - if (_assetsDeposited == 0) { - return 0; - } - - // Note: _calculateSupply() without the method (use if we don't need a dedicated _viewMeTokensMintedFromZero() function) - uint256 stepsAfterMint = (((_balancePooled + _assetsDeposited) * - _stepX * - _stepX) / ((_stepX * _stepY) / 2)); // ^ (1 / 2); - uint256 balancePooledAtCurrentSteps = ((stepsAfterMint * - stepsAfterMint + - stepsAfterMint) / 2) * - _stepX * - _stepY; - uint256 supplyAfterMint; - if (balancePooledAtCurrentSteps > (_balancePooled + _assetsDeposited)) { - supplyAfterMint = - _stepX * - stepsAfterMint - - (balancePooledAtCurrentSteps - - (_balancePooled + _assetsDeposited)) / - (_stepY * stepsAfterMint); - } else { - supplyAfterMint = - _stepX * - stepsAfterMint + - ((_balancePooled + _assetsDeposited) - - balancePooledAtCurrentSteps) / - (_stepY * (stepsAfterMint + 1)); - } - return supplyAfterMint - _supply; - } - - /// @notice Given an amount of meTokens to burn, length of stepX, height of stepY, supply and collateral pooled, - /// calculates the return for a given conversion (in the collateral token) - /// @param _meTokensBurned, // meTokens burned - /// @param _stepX, // length of step (aka supply duration) - /// @param _stepY, // height of step (aka price delta) - /// @param _supply, // current supply - /// @param _balancePooled // current collateral amount - /// @return amount of collateral tokens received - function _viewAssetsReturned( - uint256 _meTokensBurned, // meTokens burned - uint256 _stepX, // length of step (aka supply duration) - uint256 _stepY, // height of step (aka price delta) - uint256 _supply, // current supply - uint256 _balancePooled // current collateral amount - ) private pure returns (uint256) { - // validate input - require( - _supply > 0 && _balancePooled > 0 && _meTokensBurned <= _supply - ); - // special case for 0 sell amount - if (_meTokensBurned == 0) { - return 0; - } - - uint256 steps = _supply / _stepX; - uint256 supplyAtCurrentStep = _supply - (steps * _stepX); - uint256 stepsAfterBurn = (_supply - _meTokensBurned) / _stepX; - uint256 supplyAtStepAfterBurn = _supply - (stepsAfterBurn * _stepX); - - uint256 balancePooledAtCurrentSteps = ((steps * steps + steps) / 2) * - _stepX * - _stepY; - uint256 balancePooledAtStepsAfterBurn = ((stepsAfterBurn * - stepsAfterBurn + - stepsAfterBurn) / 2) * - _stepX * - _stepY; - - return - balancePooledAtCurrentSteps + - supplyAtCurrentStep * - _stepY - - balancePooledAtStepsAfterBurn - - supplyAtStepAfterBurn * - _stepY; - } -} From 9cc82d82a56b7f58ab512f2897a960bbbb7f52f2 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Thu, 24 Feb 2022 00:42:31 +0100 Subject: [PATCH 4/6] fix(test): update rounding in calculation --- test/contracts/facets/MeTokenRegistryFacet.ts | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/test/contracts/facets/MeTokenRegistryFacet.ts b/test/contracts/facets/MeTokenRegistryFacet.ts index 952661b9..6533cd92 100644 --- a/test/contracts/facets/MeTokenRegistryFacet.ts +++ b/test/contracts/facets/MeTokenRegistryFacet.ts @@ -91,9 +91,9 @@ const setup = async () => { let encodedMigrationArgs: string; let receipt: ContractReceipt; - const hubId = 1; - const hubId2 = 2; - const hubId3 = 3; + const hubId = 1; // DAI + const hubId2 = 2; // WETH + const hubId3 = 3; // USDT const MAX_WEIGHT = 1000000; const PRECISION = BigNumber.from(10).pow(18); const reserveWeight = MAX_WEIGHT / 2; @@ -142,7 +142,6 @@ const setup = async () => { refundRatio, "bancorABDK" )); - await hub.register( account0.address, WETH, @@ -162,9 +161,6 @@ const setup = async () => { encodedVaultArgs ); await hub.setHubWarmup(hubWarmup); - /* - await hub.setHubCooldown(coolDown); - await hub.setHubDuration(duration); */ await meTokenRegistry.setMeTokenWarmup(warmup - 1); await meTokenRegistry.setMeTokenCooldown(coolDown + 1); await meTokenRegistry.setMeTokenDuration(duration - 1); @@ -291,7 +287,6 @@ const setup = async () => { meTokenAddr1 = await meTokenRegistry.getOwnerMeToken(account1.address); const meToken = await getContractAt("MeToken", meTokenAddr1); // should be greater than 0 - const calculatedRes = calculateTokenReturnedFromZero( 20, toETHNumber(baseY), @@ -465,7 +460,6 @@ const setup = async () => { ); await expect(tx).to.be.revertedWith("same hub"); }); - it("Fails if resubscribing to inactive hub", async () => { const meToken = meTokenAddr0; const targetHubId = 0; // inactive hub @@ -480,9 +474,7 @@ const setup = async () => { await expect(tx).to.be.revertedWith("targetHub inactive"); }); it("Fails if current hub currently updating", async () => { - await ( - await hub.initUpdate(hubId, curve.address, refundRatio / 2, "0x") - ).wait(); + await hub.initUpdate(hubId, curve.address, refundRatio / 2, "0x"); const tx = meTokenRegistry.initResubscribe( meTokenAddr0, @@ -491,12 +483,10 @@ const setup = async () => { "0x" ); await expect(tx).to.be.revertedWith("hub updating"); - await (await hub.cancelUpdate(hubId)).wait(); + await hub.cancelUpdate(hubId); }); it("Fails if target hub currently updating", async () => { - await ( - await hub.initUpdate(hubId2, curve.address, refundRatio / 2, "0x") - ).wait(); + await hub.initUpdate(hubId2, curve.address, refundRatio / 2, "0x"); const tx = meTokenRegistry.initResubscribe( meTokenAddr0, @@ -505,7 +495,7 @@ const setup = async () => { "0x" ); await expect(tx).to.be.revertedWith("targetHub updating"); - await (await hub.cancelUpdate(hubId2)).wait(); + await hub.cancelUpdate(hubId2); }); it("Fails if attempting to use an unapproved migration", async () => { await expect( @@ -534,7 +524,7 @@ const setup = async () => { ) ).to.be.revertedWith("Invalid encodedMigrationArgs"); }); - it("Passes when current and target hub have same asset", async () => { + it("Fails when current and target hub have same asset", async () => { const tx = meTokenRegistry.callStatic.initResubscribe( meToken, hubId3, @@ -579,6 +569,7 @@ const setup = async () => { const meTokenRegistryDetails = await meTokenRegistry.getMeTokenDetails( meTokenAddr0 ); + expect(meTokenRegistryDetails.startTime).to.equal(expectedStartTime); expect(meTokenRegistryDetails.endTime).to.equal(expectedEndTime); expect(meTokenRegistryDetails.endCooldown).to.equal( @@ -947,6 +938,12 @@ const setup = async () => { const meTokenDetails = await meTokenRegistry.getMeTokenDetails( meToken.address ); + const meTokenTotalSupply = await meToken.totalSupply(); + console.log(` AVANT +meTokenTotalSupply):${toETHNumber(meTokenTotalSupply)} +meTokenDetails.balancePooled):${toETHNumber(meTokenDetails.balancePooled)} +meTokenDetails.balanceLocked):${toETHNumber(meTokenDetails.balanceLocked)} +`); const tx = await foundry.mint( meTokenAddr1, tokenDeposited, @@ -976,11 +973,13 @@ const setup = async () => { const meTokenDetails = await meTokenRegistry.getMeTokenDetails( meToken.address ); - const rawAssetsReturned = calculateCollateralReturned( - toETHNumber(buyerMeToken), - toETHNumber(meTokenTotalSupply), - toETHNumber(meTokenDetails.balancePooled), - reserveWeight / MAX_WEIGHT + const rawAssetsReturned = Number( + calculateCollateralReturned( + toETHNumber(buyerMeToken), + toETHNumber(meTokenTotalSupply), + toETHNumber(meTokenDetails.balancePooled), + reserveWeight / MAX_WEIGHT + ).toFixed(12) ); const assetsReturned = (rawAssetsReturned * refundRatio) / MAX_WEIGHT; const lockedAmount = fromETHNumber(rawAssetsReturned - assetsReturned); @@ -1027,11 +1026,13 @@ const setup = async () => { const meTokenDetails = await meTokenRegistry.getMeTokenDetails( meToken.address ); - const rawAssetsReturned = calculateCollateralReturned( - toETHNumber(ownerMeToken), - toETHNumber(meTokenTotalSupply), - toETHNumber(meTokenDetails.balancePooled), - reserveWeight / MAX_WEIGHT + const rawAssetsReturned = Number( + calculateCollateralReturned( + toETHNumber(ownerMeToken), + toETHNumber(meTokenTotalSupply), + toETHNumber(meTokenDetails.balancePooled), + reserveWeight / MAX_WEIGHT + ).toFixed(12) ); const assetsReturned = rawAssetsReturned + From 02a9f55fc7b5b89e196afe81ee0f032c357623c8 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Thu, 24 Feb 2022 00:52:43 +0100 Subject: [PATCH 5/6] fix(test): adapt rounding --- test/contracts/facets/MeTokenRegistryFacet.ts | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/test/contracts/facets/MeTokenRegistryFacet.ts b/test/contracts/facets/MeTokenRegistryFacet.ts index 6533cd92..11ac807d 100644 --- a/test/contracts/facets/MeTokenRegistryFacet.ts +++ b/test/contracts/facets/MeTokenRegistryFacet.ts @@ -938,12 +938,6 @@ const setup = async () => { const meTokenDetails = await meTokenRegistry.getMeTokenDetails( meToken.address ); - const meTokenTotalSupply = await meToken.totalSupply(); - console.log(` AVANT -meTokenTotalSupply):${toETHNumber(meTokenTotalSupply)} -meTokenDetails.balancePooled):${toETHNumber(meTokenDetails.balancePooled)} -meTokenDetails.balanceLocked):${toETHNumber(meTokenDetails.balanceLocked)} -`); const tx = await foundry.mint( meTokenAddr1, tokenDeposited, @@ -1026,13 +1020,11 @@ meTokenDetails.balanceLocked):${toETHNumber(meTokenDetails.balanceLocked)} const meTokenDetails = await meTokenRegistry.getMeTokenDetails( meToken.address ); - const rawAssetsReturned = Number( - calculateCollateralReturned( - toETHNumber(ownerMeToken), - toETHNumber(meTokenTotalSupply), - toETHNumber(meTokenDetails.balancePooled), - reserveWeight / MAX_WEIGHT - ).toFixed(12) + const rawAssetsReturned = calculateCollateralReturned( + toETHNumber(ownerMeToken), + toETHNumber(meTokenTotalSupply), + toETHNumber(meTokenDetails.balancePooled), + reserveWeight / MAX_WEIGHT ); const assetsReturned = rawAssetsReturned + @@ -1064,7 +1056,7 @@ meTokenDetails.balanceLocked):${toETHNumber(meTokenDetails.balanceLocked)} toETHNumber( meTokenDetails.balanceLocked.sub(newMeTokenDetails.balanceLocked) ) - ).to.be.approximately(lockedAmount, 1e-15); + ).to.be.approximately(lockedAmount, 1e-13); }); }); }); From eb3d3918470bfaebce5dca713a7a27159370a0d1 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Thu, 24 Feb 2022 10:18:56 +0100 Subject: [PATCH 6/6] fix(test): remove old curves --- .../migrations/UniswapSingleTransferMigration.sol | 3 ++- test/utils/hubSetup.ts | 13 +++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/contracts/migrations/UniswapSingleTransferMigration.sol b/contracts/migrations/UniswapSingleTransferMigration.sol index 32aa5d1e..90051255 100644 --- a/contracts/migrations/UniswapSingleTransferMigration.sol +++ b/contracts/migrations/UniswapSingleTransferMigration.sol @@ -159,7 +159,8 @@ contract UniswapSingleTransferMigration is ReentrancyGuard, Vault, IMigration { HubInfo memory targetHubInfo = IHub(diamond).getHubDetails( meTokenInfo.targetHubId ); - uint256 amountIn = meTokenInfo.balancePooled + meTokenInfo.balanceLocked; + uint256 amountIn = meTokenInfo.balancePooled + + meTokenInfo.balanceLocked; // Only swap if // - There are tokens to swap diff --git a/test/utils/hubSetup.ts b/test/utils/hubSetup.ts index 70dde31c..17df42ec 100644 --- a/test/utils/hubSetup.ts +++ b/test/utils/hubSetup.ts @@ -1,6 +1,6 @@ import { Contract } from "@ethersproject/contracts"; import { ethers, getNamedAccounts } from "hardhat"; -import { BancorABDK } from "../../artifacts/types/BancorABDK"; +import { BancorABDK, StepwiseCurveABDK } from "../../artifacts/types"; import { MeTokenFactory } from "../../artifacts/types/MeTokenFactory"; import { CurveRegistry } from "../../artifacts/types/CurveRegistry"; import { VaultRegistry } from "../../artifacts/types/VaultRegistry"; @@ -23,7 +23,6 @@ import { impersonate } from "./hardhatNode"; import { Signer } from "ethers"; import { ICurve } from "../../artifacts/types/ICurve"; import { expect } from "chai"; -import { BancorPower, StepwiseCurve } from "../../artifacts/types"; export async function hubSetup( encodedCurveDetails: string, @@ -115,15 +114,9 @@ async function getCurve(curveType: string, diamond: string): Promise { undefined, diamond )) as unknown as ICurve; - case "BancorPower": - return (await deploy( - "BancorPower", - undefined, - diamond - )) as unknown as ICurve; case "StepwiseCurve": - return (await deploy( - "StepwiseCurve", + return (await deploy( + "StepwiseCurveABDK", undefined, diamond )) as unknown as ICurve;