Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test/generic stepwise curve rebased #100

Merged
merged 11 commits into from
Jan 24, 2022
3 changes: 3 additions & 0 deletions contracts/Foundry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import "./interfaces/IFoundry.sol";
import "./libs/WeightedAverage.sol";
import "./libs/Details.sol";

/// @title meTokens Foundry
/// @author Carl Farterson (@carlfarterson), Chris Robison (@cbobrobison), Parv Garg (@parv3213), @zgorizzo69
/// @notice Mint and burn meTokens for other assets
contract Foundry is IFoundry, Ownable, Initializable {
using SafeERC20 for IERC20;
uint256 public constant PRECISION = 10**18;
Expand Down
2 changes: 1 addition & 1 deletion contracts/Hub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import "./interfaces/IFoundry.sol";
import "./libs/Details.sol";

/// @title meToken hub
/// @author Carl Farterson (@carlfarterson)
/// @author Carl Farterson (@carlfarterson), Chris Robison (@cbobrobison), Parv Garg (@parv3213), @zgorizzo69
/// @notice This contract tracks all combinations of vaults and curves,
/// and their respective subscribed meTokens
contract Hub is IHub, Ownable, Initializable {
Expand Down
9 changes: 4 additions & 5 deletions contracts/curves/BancorABDK.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "../libs/WeightedAverage.sol";
import "../utils/ABDKMathQuad.sol";

/// @title Bancor curve registry and calculator
/// @author Carl Farterson (@carlfarterson), Chris Robison (@CBobRobison)
/// @author Carl Farterson (@carlfarterson), Chris Robison (@CBobRobison), @zgorizzo69
contract BancorABDK is ICurve {
using ABDKMathQuad for uint256;
using ABDKMathQuad for bytes16;
Expand All @@ -25,14 +25,12 @@ contract BancorABDK is ICurve {
bytes16 private immutable _maxWeight = uint256(MAX_WEIGHT).fromUInt(); // gas savings
bytes16 private immutable _one = (uint256(1)).fromUInt();
address public hub;
address public foundry;

// NOTE: keys are their respective hubId
mapping(uint256 => Bancor) private _bancors;

constructor(address _hub, address _foundry) {
constructor(address _hub) {
hub = _hub;
foundry = _foundry;
}

function register(uint256 _hubId, bytes calldata _encodedDetails)
Expand Down Expand Up @@ -320,7 +318,8 @@ contract BancorABDK is ICurve {
_balancePooled > 0 &&
_reserveWeight > 0 &&
_reserveWeight <= MAX_WEIGHT &&
_meTokensBurned <= _supply
_meTokensBurned <= _supply,
"!valid"
zgorizzo69 marked this conversation as resolved.
Show resolved Hide resolved
);
// special case for 0 sell amount
if (_meTokensBurned == 0) {
Expand Down
5 changes: 2 additions & 3 deletions contracts/curves/BancorPower.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8;

import "../utils/ABDKMathQuad.sol";
Expand Down Expand Up @@ -29,14 +30,12 @@ contract BancorPower is Power, ICurve {
bytes16 private immutable _maxWeight = uint256(MAX_WEIGHT).fromUInt(); // gas savings
bytes16 private immutable _one = (uint256(1)).fromUInt();
address public hub;
address public foundry;

// NOTE: keys are the respective hubId
mapping(uint256 => Bancor) private _bancors;

constructor(address _hub, address _foundry) {
constructor(address _hub) {
hub = _hub;
foundry = _foundry;
}

function register(uint256 _hubId, bytes calldata _encodedDetails)
Expand Down
1 change: 1 addition & 0 deletions contracts/curves/Power.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8;

/**
Expand Down
11 changes: 4 additions & 7 deletions contracts/curves/StepwiseCurve.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,26 @@ contract StepwiseCurve is ICurve {

uint256 public constant PRECISION = 10**18;
address public hub;
address public foundry;

// NOTE: keys are their respective hubId
mapping(uint256 => Stepwise) private _stepwises;

constructor(address _hub, address _foundry) {
constructor(address _hub) {
hub = _hub;
foundry = _foundry;
}

function register(uint256 _hubId, bytes calldata _encodedDetails)
external
override
{
require(msg.sender == hub, "!hub");
require(_encodedDetails.length > 0, "_encodedDetails empty");

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");
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;
Expand Down
125 changes: 52 additions & 73 deletions contracts/curves/StepwiseCurveABDK.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ 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 {
/// @author Carl Farterson (@carlfarterson), Chris Robison (@CBobRobison), @zgorizzo69
contract StepwiseCurveABDK is ICurve {
using ABDKMathQuad for uint256;
using ABDKMathQuad for int256;
using ABDKMathQuad for bytes16;
struct Stepwise {
uint256 stepX;
Expand All @@ -18,32 +19,31 @@ contract StepwiseCurve is ICurve {
}

uint256 public constant PRECISION = 10**18;
bytes16 private immutable _precision = uint256(PRECISION).fromUInt();
bytes16 private immutable _one = uint256(1).fromUInt();
bytes16 private immutable _two = uint256(2).fromUInt();
address public hub;
address public foundry;
bytes16 private immutable _two = (2 * PRECISION).fromUInt();

// NOTE: keys are their respective hubId
mapping(uint256 => Stepwise) private _stepwises;

constructor(address _hub, address _foundry) {
constructor(address _hub) {
hub = _hub;
foundry = _foundry;
}

function register(uint256 _hubId, bytes calldata _encodedDetails)
external
override
{
require(msg.sender == hub, "!hub");
require(_encodedDetails.length > 0, "_encodedDetails empty");
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");
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;
Expand All @@ -64,17 +64,10 @@ contract StepwiseCurve is ICurve {
(uint256, uint256)
);
Stepwise storage stepwiseDetails = _stepwises[_hubId];

require(
targetStepX > 0 && targetStepX < PRECISION,
"stepX not in range"
);
require(targetStepX > 0 && targetStepX > PRECISION, "!targetStepX");
require(targetStepX != stepwiseDetails.stepX, "targeStepX == stepX");

require(
targetStepY > 0 && targetStepY < PRECISION,
"stepY not in range"
);
require(targetStepY > 0 && targetStepY > PRECISION, "!targetStepY");
require(targetStepY != stepwiseDetails.stepY, "targeStepY == stepY");

stepwiseDetails.targetStepY = targetStepY;
Expand Down Expand Up @@ -196,48 +189,40 @@ contract StepwiseCurve is ICurve {
return 0;
}

bytes16 assetsDeposited_ = _assetsDeposited.fromUInt();
// bytes16 assetsDeposited_ = _assetsDeposited.fromUInt();
bytes16 stepX_ = _stepX.fromUInt();
bytes16 stepY_ = _stepY.fromUInt();
bytes16 supply_ = _supply.fromUInt();
bytes16 balancePooled_ = _balancePooled.fromUInt();

// Note: _calculateSupply() without the method (use if we don't need a dedicated _viewMeTokensMintedFromZero() function)
bytes16 stepsAfterMint = (
(
(balancePooled_.add(assetsDeposited_).mul(stepX_).mul(stepX_))
.div((stepX_).mul(stepY_).div(_two))
)
).sqrt();

bytes16 balancePooledAtCurrentSteps = (
(stepsAfterMint.mul(stepsAfterMint).add(stepsAfterMint)).div(_two)
).mul(stepX_).mul(stepY_);
bytes16 totalBalancePooled_ = (_balancePooled + _assetsDeposited)
.fromUInt();

// Note: .toUInt().fromUInt() is used to round down
bytes16 steps = (_two.mul(totalBalancePooled_).mul(stepX_).mul(stepX_))
.div((stepX_).mul(stepY_))
.sqrt()
.div(stepX_)
.toUInt()
.fromUInt();
bytes16 stepBalance = (steps.mul(steps).add(steps))
.div(_two)
.mul(stepX_)
.mul(stepY_);

bytes16 supplyAfterMint;
if (
balancePooledAtCurrentSteps > balancePooled_.add(assetsDeposited_)
) {
supplyAfterMint = stepX_
.mul(stepsAfterMint)
.sub(
balancePooledAtCurrentSteps.sub(
balancePooled_.add(assetsDeposited_)
)
)
.div(stepY_.mul(stepsAfterMint));
if (stepBalance.cmp(totalBalancePooled_) > 0) {
bytes16 intres = (stepBalance.sub(totalBalancePooled_))
.div(stepY_.mul(steps))
.mul(_precision);
supplyAfterMint = stepX_.mul(steps).sub(intres);
} else {
supplyAfterMint = stepX_
.mul(stepsAfterMint)
.add(
(balancePooled_.add(assetsDeposited_)).sub(
balancePooledAtCurrentSteps
)
supplyAfterMint = stepX_.mul(steps).add(
(totalBalancePooled_.sub(stepBalance)).div(
stepY_.div(_precision).mul(steps.add(_one))
)
.div(stepY_.mul(stepsAfterMint.add(_one)));
);
}

return supplyAfterMint.sub(supply_).toUInt();
return supplyAfterMint.toUInt() - _supply;
}

/// @notice Given an amount of meTokens to burn, length of stepX, height of stepY, supply and collateral pooled,
Expand All @@ -257,7 +242,8 @@ contract StepwiseCurve is ICurve {
) private view returns (uint256) {
// validate input
require(
_supply > 0 && _balancePooled > 0 && _meTokensBurned <= _supply
_supply > 0 && _balancePooled > 0 && _meTokensBurned <= _supply,
"!valid"
);
// special case for 0 sell amount
if (_meTokensBurned == 0) {
Expand All @@ -268,26 +254,19 @@ contract StepwiseCurve is ICurve {
bytes16 stepX_ = _stepX.fromUInt();
bytes16 stepY_ = _stepY.fromUInt();
bytes16 supply_ = _supply.fromUInt();

bytes16 steps = supply_.div(stepX_);
bytes16 supplyAtCurrentStep = supply_.sub(steps.mul(stepX_));
bytes16 stepsAfterBurn = (supply_.sub(meTokensBurned_)).div(stepX_);
bytes16 supplyAtStepAfterBurn = supply_.sub(stepsAfterBurn.mul(stepX_));

bytes16 balancePooledAtCurrentSteps = (
(steps.mul(steps).add(steps)).div(_two)
).mul(stepX_).mul(stepY_);

bytes16 balancePooledAtStepsAfterBurn = (
(stepsAfterBurn.mul(stepsAfterBurn).add(stepsAfterBurn)).div(_two)
).mul(stepX_).mul(stepY_);

bytes16 res = balancePooledAtCurrentSteps
.add(supplyAtCurrentStep)
.mul(stepY_)
.sub(balancePooledAtStepsAfterBurn)
.sub(supplyAtStepAfterBurn)
.mul(stepY_);
return res.toUInt();
// .toUInt().fromUInt() is used to round down
bytes16 newSteps = supply_
.sub(meTokensBurned_)
.div(stepX_)
.toUInt()
.fromUInt();
bytes16 newSupplyInStep = supply_
.sub(meTokensBurned_)
.sub(newSteps.mul(stepX_))
.div(_precision);
bytes16 newCollateralInBalance = (
newSteps.mul(stepX_).mul(stepY_).div(_precision)
).add((newSteps.add(_one)).mul(newSupplyInStep).mul(stepY_));
return _balancePooled - newCollateralInBalance.toUInt();
}
}
2 changes: 1 addition & 1 deletion contracts/migrations/UniswapSingleTransferMigration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import "../interfaces/IMigration.sol";
import "../interfaces/ISingleAssetVault.sol";

/// @title Vault migrator from erc20 to erc20 (non-lp)
/// @author Carl Farterson (@carlfarterson)
/// @author Carl Farterson (@carlfarterson), Chris Robison (@cbobrobison), Parv Garg (@parv3213)
/// @notice create a vault that instantly swaps token A for token B
/// when recollateralizing to a vault with a different base token
/// @dev This contract moves the pooled/locked balances from
Expand Down
4 changes: 1 addition & 3 deletions contracts/registries/MeTokenRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,7 @@ contract MeTokenRegistry is Ownable, IMeTokenRegistry {
);
// Update balancePooled / balanceLocked
// solhint-disable-next-line
uint256 newBalance = IMigration(meToken_.migration).finishMigration(
_meToken
);
IMigration(meToken_.migration).finishMigration(_meToken);

// Finish updating metoken details
meToken_.startTime = 0;
Expand Down
5 changes: 3 additions & 2 deletions contracts/vaults/SingleAssetVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "./Vault.sol";
import "../interfaces/ISingleAssetVault.sol";

/// @title Vault
/// @author Carl Farterson (@carlfarterson)
/// @author Carl Farterson (@carlfarterson), Parv Garg (@parv3213), @zgorizzo69
/// @notice Implementation contract for SingleAssetFactory.sol
contract SingleAssetVault is Vault, ISingleAssetVault {
using SafeERC20 for IERC20;
Expand Down Expand Up @@ -36,9 +36,10 @@ contract SingleAssetVault is Vault, ISingleAssetVault {
emit StartMigration(_meToken);
}

// solhint-disable-next-line
function isValid(
address _asset,
bytes memory /* _encodedArgs */
bytes memory /*_encodedArgs */
) public pure override returns (bool) {
if (_asset == address(0)) {
return false;
Expand Down
6 changes: 3 additions & 3 deletions contracts/vaults/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import "../interfaces/IHub.sol";
import "../interfaces/IMeTokenRegistry.sol";
import "../interfaces/IMigrationRegistry.sol";

/// @title Vault
/// @author Carl Farterson (@carlfarterson)
/// @notice Implementation contract for SingleAssetFactory.sol
/// @title meTokens basic Vault
/// @author Carl Farterson (@carlfarterson), Parv Garg (@parv3213), @zgorizzo69
/// @notice Most basic vault implementation to be inherited by meToken vaults
abstract contract Vault is Ownable, IVault {
using SafeERC20 for IERC20;
uint256 public constant PRECISION = 10**18;
Expand Down
4 changes: 2 additions & 2 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ const makeNetwork = (_network: string) => {
const config: HardhatUserConfig = {
solidity: {
compilers: [
{ version: "0.7.0" },
{ version: "0.8.3" },
{
version: "0.8.0",
version: "0.8.10",
settings: {
optimizer: {
enabled: true,
Expand Down
Loading