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

issue #328 (Nightly Draft) #330

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
caf51db
issue #328
Lomet Oct 2, 2023
c803ded
fix length misstype
Lomet Oct 2, 2023
fe59089
add CalcUtils
Lomet Oct 2, 2023
9d5c9f3
fix brakets
Lomet Oct 2, 2023
75001a7
remove pure
Lomet Oct 2, 2023
685fd01
add pure
Lomet Oct 2, 2023
678a5b7
add UpgradeType
Lomet Oct 2, 2023
445328b
add require for UpgradeType
Lomet Oct 2, 2023
9626199
fix CreateNewDelayVault
Lomet Oct 2, 2023
c23d19b
add more code
Lomet Oct 2, 2023
d430455
add _getWithdrawPoolParams
Lomet Oct 2, 2023
c985989
add require
Lomet Oct 2, 2023
c7032a8
ProviderState was red
Lomet Oct 2, 2023
7a96a67
extract some code
Lomet Oct 2, 2023
752bfcf
add some code
Lomet Oct 2, 2023
c045aca
add type(uint256).max
Lomet Oct 2, 2023
cee603a
order
Lomet Oct 2, 2023
552df73
some code
Lomet Oct 2, 2023
7d8c4ec
make pure
Lomet Oct 2, 2023
00e2392
some refactor
Lomet Oct 2, 2023
6ecc275
reorder
Lomet Oct 2, 2023
e4a66c7
swap imports
Lomet Oct 2, 2023
d96cd13
order
Lomet Oct 2, 2023
d746b1b
add event
Lomet Oct 2, 2023
e19b2df
typo
Lomet Oct 2, 2023
574655a
add if
Lomet Oct 2, 2023
fb98c54
add owner to createNewDelayVault
Lomet Oct 3, 2023
fa9a067
delay vault migrator (#337)
Lomet Oct 3, 2023
840af1d
Merge branch 'master' into Issue_#328
Lomet Oct 3, 2023
6a0a324
Update LockDealNFT.sol
Lomet Oct 3, 2023
553ba0f
add else if
Lomet Oct 3, 2023
2e3707c
remove return
Lomet Oct 3, 2023
1bb4c33
refactor
Lomet Oct 3, 2023
322e28a
refaactor
Lomet Oct 3, 2023
b47bb7f
some renames
Lomet Oct 3, 2023
4b2c9cd
requires fix (#338)
YouStillAlive Oct 4, 2023
da47a99
avoid duplicate vaultManager address (#340)
YouStillAlive Oct 4, 2023
68725e4
use camelCase (#339)
YouStillAlive Oct 4, 2023
c683b66
Merge branch 'master' into Issue_#328
Lomet Oct 5, 2023
86e2b0c
add ILockDealV2
Lomet Oct 5, 2023
e4c396c
added tests (#342)
YouStillAlive Oct 5, 2023
68c3324
Merge branch 'master' into Issue_#328
YouStillAlive Oct 11, 2023
c0604ac
`DelayProvider` tests (#345)
YouStillAlive Oct 11, 2023
8aa6535
Merge branch 'master' into Issue_#328
Lomet Oct 11, 2023
4ac7413
Merge branch 'master' into Issue_#328
YouStillAlive Oct 13, 2023
5e41327
build fixing
YouStillAlive Oct 13, 2023
fa24c5f
migrator preparations (#352)
YouStillAlive Oct 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import "./BundleModifiers.sol";
import "../../util/CalcUtils.sol";
import "../../interfaces/ISimpleProvider.sol";
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import "../../ERC165/Bundable.sol";

contract BundleProvider is BundleModifiers, ERC721Holder {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./DelayVaultState.sol";

contract DelayVaultProvider is DelayVaultState {
constructor(address _token, IMigrator _migrator, ProviderData[] memory _providersData) {
require(address(_token) != address(0x0), "invalid address");
require(address(_migrator) != address(0x0), "invalid address");
require(_providersData.length <= 255, "too many providers");
name = "DelayVaultProvider";
token = _token;
migrator = _migrator;
lockDealNFT = _migrator.lockDealNFT();
_finilize(_providersData);
}

///@param params[0] = amount
function registerPool(

Check warning on line 19 in contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol

View check run for this annotation

Codecov / codecov/patch

contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol#L19

Added line #L19 was not covered by tests
uint256 poolId,
uint256[] calldata params
) public override onlyProvider validProviderId(poolId) {
require(params.length == currentParamsTargetLenght(), "invalid params length");
_registerPool(poolId, params);

Check warning on line 24 in contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol

View check run for this annotation

Codecov / codecov/patch

contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol#L24

Added line #L24 was not covered by tests
}

function _registerPool(uint256 poolId, uint256[] calldata params) internal {
uint256 amount = params[0];
address owner = lockDealNFT.ownerOf(poolId);
_addHoldersSum(owner, amount, owner == msg.sender || msg.sender == address(migrator));
poolIdToAmount[poolId] = amount;
}

function getParams(uint256 poolId) external view override returns (uint256[] memory params) {
params = new uint256[](1);
params[0] = poolIdToAmount[poolId];
}

function getWithdrawableAmount(uint256 poolId) external view override returns (uint256 withdrawalAmount) {
withdrawalAmount = poolIdToAmount[poolId];
}

function upgradeType(uint8 newType) public {
uint8 oldType = userToType[msg.sender];
uint256 amount = getTotalAmount(msg.sender);
require(amount > 0, "amount must be bigger than 0");
require(newType > oldType, "new type must be bigger than the old one");
require(newType < typesCount, "new type must be smaller than the types count");
userToType[msg.sender] = newType;
}

function createNewDelayVault(address owner, uint256[] calldata params) external returns (uint256 poolId) {
require(params.length == currentParamsTargetLenght(), "invalid params length");
require(owner != address(0), "invalid owner address");
uint256 amount = params[0];
require(amount > 0, "amount must be bigger than 0");
poolId = lockDealNFT.mintAndTransfer(owner, token, msg.sender, amount, this);
_registerPool(poolId, params);
}
}
88 changes: 88 additions & 0 deletions contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../../SimpleProviders/DealProvider/DealProviderState.sol";
import "../../util/CalcUtils.sol";
import "./LastPoolOwnerState.sol";
import "./HoldersSum.sol";

abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, HoldersSum {
using CalcUtils for uint256;

function beforeTransfer(address from, address to, uint256 poolId) external override onlyNFT {
if (to == address(lockDealNFT))
// this means it will be withdraw or split
lastPoolOwner[poolId] = from; //this is the only way to know the owner of the pool
else if (from != address(0) && !lockDealNFT.approvedContracts(from)) {
_handleTransfer(from, to, poolId);
}
}

function _handleTransfer(address from, address to, uint256 poolId) internal returns (uint256 amount) {
amount = poolIdToAmount[poolId];
_subHoldersSum(from, amount);
_addHoldersSum(to, amount, false);
}

function getWithdrawPoolParams(uint256 amount, uint8 theType) public view returns (uint256[] memory params) {
uint256[] memory settings = typeToProviderData[theType].params;
params = _getWithdrawPoolParams(amount, settings);
}

function _getWithdrawPoolParams(
uint256 amount,
uint256[] memory settings
) internal view returns (uint256[] memory params) {
uint256 length = settings.length + 1;
params = new uint256[](length);
params[0] = amount;
for (uint256 i = 0; i < settings.length; i++) {
params[i + 1] = block.timestamp + settings[i];
}
}

//This need to make a new pool without transfering the token, the pool data is taken from the settings
function withdraw(uint256 tokenId) external override onlyNFT returns (uint256 withdrawnAmount, bool isFinal) {
address owner = lastPoolOwner[tokenId];
uint8 theType = userToType[owner];
uint256 amount = poolIdToAmount[tokenId];
_createLockNFT(owner, amount, theType, tokenId);
isFinal = true;
withdrawnAmount = poolIdToAmount[tokenId] = 0;
_subHoldersSum(owner, amount);
_resetTypeIfEmpty(owner);
}

function _createLockNFT(address owner, uint256 amount, uint8 theType, uint tokenId) internal {
ProviderData memory providerData = typeToProviderData[theType];
uint256 newPoolId = lockDealNFT.mintForProvider(owner, providerData.provider);
lockDealNFT.cloneVaultId(newPoolId, tokenId);
uint256[] memory params = getWithdrawPoolParams(amount, theType);
providerData.provider.registerPool(newPoolId, params);
}

function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override onlyNFT {
address oldOwner = lastPoolOwner[oldPoolId];
address newOwner = lockDealNFT.ownerOf(newPoolId);
uint256 amount = poolIdToAmount[oldPoolId].calcAmount(ratio);
poolIdToAmount[oldPoolId] -= amount;
poolIdToAmount[newPoolId] = amount;
if (newOwner != oldOwner) {
_handleTransfer(oldOwner, newOwner, newPoolId);
}
}

function _resetTypeIfEmpty(address user) internal {
if (getTotalAmount(user) == 0) {
userToType[user] = 0; //reset the type
}
}

function getTypeToProviderData(uint8 theType) public view virtual returns (ProviderData memory providerData) {
providerData = typeToProviderData[theType];
}

function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IDelayVaultProvider).interfaceId || super.supportsInterface(interfaceId);
}
}
95 changes: 95 additions & 0 deletions contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../../SimpleProviders/Provider/ProviderModifiers.sol";
import "../../interfaces/IDelayVaultProvider.sol";
import "../../interfaces/IDelayVaultV1.sol";
import "../../interfaces/IMigrator.sol";

abstract contract HoldersSum is ProviderModifiers, IDelayVaultProvider {
//this is only the delta
//the amount is the amount of the pool
// params[0] = startTimeDelta (empty for DealProvider)
// params[1] = endTimeDelta (only for TimedLockDealProvider)
mapping(address => uint256) public userToAmount; //Each user got total amount
mapping(address => uint8) public userToType; //Each user got type, can go up. wjem withdraw to 0, its reset
mapping(uint8 => ProviderData) public typeToProviderData; //will be {typesCount} length
uint8 public typesCount; //max type + 1
address public token;
IMigrator public migrator;

event VaultValueChanged(address indexed token, address indexed owner, uint256 amount);

function getTotalAmount(address user) public view returns (uint256) {
return userToAmount[user] + migrator.getUserV1Amount(user);
}

function theTypeOf(uint256 amount) public view returns (uint8 theType) {
for (uint8 i = 0; i < typesCount; ++i) {
if (amount <= typeToProviderData[i].limit) {
theType = i;
break;
}
}
}

function _addHoldersSum(address user, uint256 amount, bool allowTypeUpgrade) internal {
uint256 newAmount = userToAmount[user] + amount;
_setHoldersSum(user, newAmount, allowTypeUpgrade);
}

function _subHoldersSum(address user, uint256 amount) internal {
uint256 oldAmount = userToAmount[user];
require(oldAmount >= amount, "amount exceeded");
uint256 newAmount = oldAmount - amount;
_setHoldersSum(user, newAmount, false);
}

function _setHoldersSum(address user, uint256 newAmount, bool allowTypeUpgrade) internal {
uint8 newType = theTypeOf(migrator.getUserV1Amount(user) + newAmount);
if (allowTypeUpgrade) {
_upgradeUserTypeIfGreater(user, newType);
} else {
_upgradeUserTypeIfMatchesV1(user, newType);
// Ensure the type doesn't change if upgrades are not allowed
require(newType <= userToType[user], "type must be the same or lower");
}
userToAmount[user] = newAmount;
emit VaultValueChanged(token, user, newAmount);
}

function _upgradeUserTypeIfGreater(address user, uint8 newType) internal {
if (newType > userToType[user]) {
userToType[user] = newType;
}
}

function _upgradeUserTypeIfMatchesV1(address user, uint8 newType) internal {
if (newType == theTypeOf(migrator.getUserV1Amount(user)) && newType > userToType[user]) {
userToType[user] = newType;

Check warning on line 69 in contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol

View check run for this annotation

Codecov / codecov/patch

contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol#L69

Added line #L69 was not covered by tests
}
}

function _finilize(ProviderData[] memory _providersData) internal {
typesCount = uint8(_providersData.length);
uint256 limit = 0;
for (uint8 i = 0; i < typesCount; ++i) {
limit = _setTypeToProviderData(i, limit, _providersData[i]);
}
}

function _setTypeToProviderData(
uint8 theType,
uint256 lastLimit,
ProviderData memory item
) internal returns (uint256 limit) {
require(address(item.provider) != address(0x0), "invalid address");
require(item.provider.currentParamsTargetLenght() == item.params.length + 1, "invalid params length");
limit = item.limit;
require(limit >= lastLimit, "limit must be bigger or equal than the previous on");
typeToProviderData[theType] = item;
if (theType == typesCount - 1) {
typeToProviderData[theType].limit = type(uint256).max; //the last one is the max, token supply is out of the scope
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../../interfaces/IBeforeTransfer.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

abstract contract LastPoolOwnerState is IBeforeTransfer, IERC165 {
mapping(uint256 => address) internal lastPoolOwner;

function beforeTransfer(address from, address to, uint256 poolId) external virtual override;

function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId || interfaceId == type(IBeforeTransfer).interfaceId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../../../interfaces/IDelayVaultProvider.sol";
import "../../../interfaces/IDelayVaultV1.sol";
import "../../../interfaces/IMigrator.sol";

abstract contract DelayMigratorState is IMigrator {
IDelayVaultV1 public oldVault;
IDelayVaultProvider public newVault;
ILockDealNFT public lockDealNFT;
IVaultManager public vaultManager;
address public token;
address public owner = msg.sender; // Initialize owner at declaration

modifier afterInit() {
_afterInit();
_;
}

///@dev internal function to save small amounts of gas
function _afterInit() internal view {
require(owner == address(0), "DelayVaultMigrator: not initialized");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./DelayMigratorState.sol";
import "../../../interfaces/ILockDealV2.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";

contract DelayVaultMigrator is DelayMigratorState, ILockDealV2 {
constructor(ILockDealNFT _nft, IDelayVaultV1 _oldVault) {
require(address(_oldVault) != address(0), "DelayVaultMigrator: Invalid old delay vault contract");
require(address(_nft) != address(0), "DelayVaultMigrator: Invalid lock deal nft contract");
oldVault = _oldVault;
lockDealNFT = _nft;
}

function finilize(IDelayVaultProvider _newVault) external {
require(owner != address(0), "DelayVaultMigrator: already initialized");
require(msg.sender == owner, "DelayVaultMigrator: not owner");
require(
ERC165Checker.supportsInterface(address(_newVault), type(IDelayVaultProvider).interfaceId),
"DelayVaultMigrator: Invalid new delay vault contract"
);
newVault = _newVault;
token = newVault.token();
vaultManager = lockDealNFT.vaultManager();
owner = address(0); // Set owner to zero address
}

//this option is to get tokens from the DelayVaultV1 and deposit them to the DelayVaultV2 (LockDealNFT, v3)
function fullMigrate() external afterInit {
require(oldVault.Allowance(token, msg.sender), "DelayVaultMigrator: not allowed");
uint256 amount = getUserV1Amount(msg.sender);
oldVault.redeemTokensFromVault(token, msg.sender, amount);
uint256[] memory params = new uint256[](1);
params[0] = amount;
IERC20(token).approve(address(vaultManager), amount);
newVault.createNewDelayVault(msg.sender, params);

Check warning on line 38 in contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol

View check run for this annotation

Codecov / codecov/patch

contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol#L33-L38

Added lines #L33 - L38 were not covered by tests
}

//this option is to get tokens from the DelayVaultV1 and deposit them to the LockDealNFT (v3)
function withdrawTokensFromV1Vault() external afterInit {
require(oldVault.Allowance(token, msg.sender), "DelayVaultMigrator: not allowed");
uint256 amount = getUserV1Amount(msg.sender);
oldVault.redeemTokensFromVault(token, msg.sender, amount);
uint8 theType = newVault.theTypeOf(newVault.getTotalAmount(msg.sender));
IDelayVaultProvider.ProviderData memory providerData = newVault.getTypeToProviderData(theType);
IERC20(token).approve(address(vaultManager), amount);
uint256 newPoolId = lockDealNFT.mintAndTransfer(

Check warning on line 49 in contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol

View check run for this annotation

Codecov / codecov/patch

contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol#L44-L49

Added lines #L44 - L49 were not covered by tests
msg.sender,
token,
address(this),
amount,
providerData.provider
);
uint256[] memory params = newVault.getWithdrawPoolParams(amount, theType);
providerData.provider.registerPool(newPoolId, params);

Check warning on line 57 in contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol

View check run for this annotation

Codecov / codecov/patch

contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol#L56-L57

Added lines #L56 - L57 were not covered by tests
}

function getUserV1Amount(address user) public view returns (uint256 amount) {
(amount, , , ) = oldVault.VaultMap(token, user);
}

function CreateNewPool(
address _Token, //token to lock address
uint256, // Until what time the pool will start
uint256, //Before CliffTime can't withdraw tokens
uint256, //Until what time the pool will end
uint256 _StartAmount, //Total amount of the tokens to sell in the pool
address _Owner // Who the tokens belong to
) external payable override afterInit {
require(msg.sender == address(oldVault), "DelayVaultMigrator: not DelayVaultV1");
uint8 theType = newVault.theTypeOf(newVault.getTotalAmount(_Owner));
IDelayVaultProvider.ProviderData memory providerData = newVault.getTypeToProviderData(theType);
IERC20(token).transferFrom(msg.sender, address(this), _StartAmount);
IERC20(token).approve(address(vaultManager), _StartAmount);
uint256 newPoolId = lockDealNFT.mintAndTransfer(

Check warning on line 77 in contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol

View check run for this annotation

Codecov / codecov/patch

contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol#L73-L77

Added lines #L73 - L77 were not covered by tests
_Owner,
_Token,
address(this),
_StartAmount,
providerData.provider
);
uint256[] memory params = newVault.getWithdrawPoolParams(_StartAmount, theType);
providerData.provider.registerPool(newPoolId, params);

Check warning on line 85 in contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol

View check run for this annotation

Codecov / codecov/patch

contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol#L84-L85

Added lines #L84 - L85 were not covered by tests
}
}
Loading
Loading