From caf51db4775b43ce5ff3e399142e4fec255e7cf7 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 22:44:57 +0300 Subject: [PATCH 01/42] issue #328 --- .../DelayVaultProvider/DelayVaultProvider.sol | 113 ++++++++++++++++++ contracts/LockDealNFT/LockDealNFTInternal.sol | 4 + contracts/interfaces/IBeforeTransfer.sol | 6 + 3 files changed, 123 insertions(+) create mode 100644 contracts/DelayVaultProvider/DelayVaultProvider.sol create mode 100644 contracts/interfaces/IBeforeTransfer.sol diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol new file mode 100644 index 00000000..0c9672db --- /dev/null +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../interfaces/IProvider.sol"; +import "../interfaces/ILockDealNFT.sol"; +import "../interfaces/IBeforeTransfer.sol"; +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import "../SimpleProviders/DealProvider/DealProviderState.sol"; + +contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProviderState { + constructor(ILockDealNFT _nftContract, ProviderData[] memory _providersData) { + nftContract = _nftContract; + typesCount = uint8(_providersData.length); + for (uint8 i = 0; i < typesCount; i++) { + require(address(_providersData[i].provider) != address(0x0), "invalid address"); + require( + _providersData[i].provider.currentParamsTargetLenght() == _providersData[i].params.lenght + 1, + "invalid params length" + ); + TypeToProviderData[i] = _providersData[i]; + } + } + + mapping(uint256 => address) internal LastPoolOwner; + mapping(address => uint256[]) internal UserToTotalAmount; //will be {typesCount} lentgh + mapping(uint256 => uint8) internal PoolToType; + mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh + uint8 public typesCount; + ILockDealNFT public nftContract; + //this is onlty the delta + //the amount taken from the user is the amount of the pool + // params[0] = startTimeDelta (empty for DealProvider) + // params[1] = endTimeDelta (only for TimedLockDealProvider) + struct ProviderData { + IProvider provider; + uint256[] params; + } + + function withdraw(uint256 tokenId) external override returns (uint256 withdrawnAmount, bool isFinal) { + uint8 theType = PoolToType[tokenId]; + address owner = LastPoolOwner[tokenId]; + uint256 newPoolId = nftContract.mintForProvider(owner, TypeToProviderData[theType].provider); + uint256[] memory settings = TypeToProviderData[theType].params; + uint256[] memory params = new uint256[](settings.length + 1); + params[0] = poolIdToAmount[tokenId]; + for (uint256 i = 0; i < settings.length; i++) { + params[i + 1] = block.timestamp + settings[i]; + } + TypeToProviderData[theType].provider.registerPool(newPoolId, params); + isFinal = true; + withdrawnAmount = poolIdToAmount[tokenId] = 0; + UserToTotalAmount[owner][theType] -= params[0]; + //This need to make a new pool without transfering the token, the pool data is taken from the settings + } + + function beforeTransfer(address from, address to, uint256 poolId /*NonReentry*/) external override { + if (to == address(nftContract)) LastPoolOwner[poolId] = from; + else { + _handleTransfer(from, to, poolId); + } + } + + function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external pure override { + address oldOwner = LastPoolOwner[oldPoolId]; + address newOwner = nftContract.ownerOf(newPoolId); + uint256 amount = poolIdToAmount[oldPoolId].calcAmount(ratio); + poolIdToAmount[oldPoolId] -= amount; + poolIdToAmount[newPoolId] = amount; + PoolToType[newPoolId] = PoolToType[oldPoolId]; + if (newOwner != oldOwner) { + _handleTransfer(oldOwner, newOwner, oldPoolId); + } + } + + function _handleTransfer(address from, address to, uint256 poolId) internal returns (uint256 amount) { + uint8 theType = PoolToType[poolId]; + amount = poolIdToAmount[poolId]; + UserToTotalAmount[from][theType] -= amount; + UserToTotalAmount[to][theType] += amount; + } + + function registerPool(uint256 poolId, uint256[] calldata params) external override { + uint8 theType = uint8(params[1]); + uint256 amount = params[0]; + require(PoolToType[poolId] == 0, "pool already registered"); + require(params.length == 2, "invalid params length"); + PoolToType[poolId] = theType; + UserToTotalAmount[nftContract.ownerOf(poolId)][theType] += amount; + poolIdToAmount[poolId] = amount; + } + + function getParams(uint256 poolId) external view override returns (uint256[] memory params) { + params = new uint256[](2); + params[0] = poolIdToAmount[poolId]; + params[1] = uint256(PoolToType[poolId]); + } + + function getWithdrawableAmount(uint256 poolId) external view override returns (uint256 withdrawalAmount) { + withdrawalAmount = 0; + } + + function currentParamsTargetLenght() external view override returns (uint256) { + return 2; + } + + function name() external pure override returns (string memory) { + return "DelayVaultProvider"; + } + + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId || interfaceId == type(IBeforeTransfer).interfaceId; + } +} diff --git a/contracts/LockDealNFT/LockDealNFTInternal.sol b/contracts/LockDealNFT/LockDealNFTInternal.sol index 981f98eb..bdd86189 100644 --- a/contracts/LockDealNFT/LockDealNFTInternal.sol +++ b/contracts/LockDealNFT/LockDealNFTInternal.sol @@ -4,9 +4,13 @@ pragma solidity ^0.8.0; import "./LockDealNFTModifiers.sol"; import "../interfaces/IInnerWithdraw.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; +import "../interfaces/IBeforeTransfer.sol"; abstract contract LockDealNFTInternal is LockDealNFTModifiers { function _transfer(address from, address to, uint256 poolId) internal override { + if (ERC165Checker.supportsInterface(address(poolIdToProvider[poolId], type(IBeforeTransfer).interfaceId))) { + IBeforeTransfer(address(poolIdToProvider[poolId])).beforeTransfer(from, to, poolId); + } // check for split and withdraw transfers if (!(approvedProviders[IProvider(to)] || approvedProviders[IProvider(from)])) { require(approvedPoolUserTransfers[from], "Pool transfer not approved by user"); diff --git a/contracts/interfaces/IBeforeTransfer.sol b/contracts/interfaces/IBeforeTransfer.sol new file mode 100644 index 00000000..8cd87b04 --- /dev/null +++ b/contracts/interfaces/IBeforeTransfer.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IBeforeTransfer { + function beforeTransfer(address from, address to, uint256 poolId) external; +} From c803ded8ddea0969cf7fec0c8f4cf065eb81e655 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 22:49:07 +0300 Subject: [PATCH 02/42] fix length misstype --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 0c9672db..5e076c37 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -14,7 +14,7 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider for (uint8 i = 0; i < typesCount; i++) { require(address(_providersData[i].provider) != address(0x0), "invalid address"); require( - _providersData[i].provider.currentParamsTargetLenght() == _providersData[i].params.lenght + 1, + _providersData[i].provider.currentParamsTargetLenght() == _providersData[i].params.length + 1, "invalid params length" ); TypeToProviderData[i] = _providersData[i]; From fe59089c688ea6466c4418b9ddf91bbb769e9da1 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 22:51:09 +0300 Subject: [PATCH 03/42] add CalcUtils --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 5e076c37..9b3a6cab 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -6,8 +6,11 @@ import "../interfaces/ILockDealNFT.sol"; import "../interfaces/IBeforeTransfer.sol"; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import "../SimpleProviders/DealProvider/DealProviderState.sol"; +import "../util/CalcUtils.sol"; contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProviderState { + using CalcUtils for uint256; + constructor(ILockDealNFT _nftContract, ProviderData[] memory _providersData) { nftContract = _nftContract; typesCount = uint8(_providersData.length); From 9d5c9f39d02c6b77301856cee70c51b7d4fc1f0c Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 22:52:00 +0300 Subject: [PATCH 04/42] fix brakets --- contracts/LockDealNFT/LockDealNFTInternal.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/LockDealNFT/LockDealNFTInternal.sol b/contracts/LockDealNFT/LockDealNFTInternal.sol index bdd86189..34deff7a 100644 --- a/contracts/LockDealNFT/LockDealNFTInternal.sol +++ b/contracts/LockDealNFT/LockDealNFTInternal.sol @@ -8,7 +8,7 @@ import "../interfaces/IBeforeTransfer.sol"; abstract contract LockDealNFTInternal is LockDealNFTModifiers { function _transfer(address from, address to, uint256 poolId) internal override { - if (ERC165Checker.supportsInterface(address(poolIdToProvider[poolId], type(IBeforeTransfer).interfaceId))) { + if (ERC165Checker.supportsInterface(address(poolIdToProvider[poolId]), type(IBeforeTransfer).interfaceId)) { IBeforeTransfer(address(poolIdToProvider[poolId])).beforeTransfer(from, to, poolId); } // check for split and withdraw transfers From 75001a74aea2b6f12670faf0fdac232371327414 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 22:52:43 +0300 Subject: [PATCH 05/42] remove pure --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 9b3a6cab..7eca8d34 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -63,7 +63,7 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider } } - function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external pure override { + function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override { address oldOwner = LastPoolOwner[oldPoolId]; address newOwner = nftContract.ownerOf(newPoolId); uint256 amount = poolIdToAmount[oldPoolId].calcAmount(ratio); From 685fd01ad9b142b46eacc026311a139be672b594 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 22:55:09 +0300 Subject: [PATCH 06/42] add pure --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 7eca8d34..1569f5a6 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -98,11 +98,11 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider params[1] = uint256(PoolToType[poolId]); } - function getWithdrawableAmount(uint256 poolId) external view override returns (uint256 withdrawalAmount) { + function getWithdrawableAmount(uint256 poolId) external pure override returns (uint256 withdrawalAmount) { withdrawalAmount = 0; } - function currentParamsTargetLenght() external view override returns (uint256) { + function currentParamsTargetLenght() external pure override returns (uint256) { return 2; } From 678a5b784219078655669a43983e81504c7db9cf Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 22:59:32 +0300 Subject: [PATCH 07/42] add UpgradeType --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 1569f5a6..200200d1 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -113,4 +113,12 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId || interfaceId == type(IBeforeTransfer).interfaceId; } + + function UpgradeType(uint256 PoolId, uint8 newType) external { + require(PoolToType[PoolId] != 0, "pool not registered"); + require(msg.sender == nftContract.ownerOf(PoolId), "only the Owner can upgrade the type"); + require(newType > PoolToType[PoolId], "new type must be bigger than the old one"); + require(newType <= typesCount, "new type must be smaller than the types count"); + PoolToType[PoolId] = newType; + } } From 445328b3e2589b51afeba85fb41a4a1de9db4cea Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 23:02:09 +0300 Subject: [PATCH 08/42] add require for UpgradeType --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 200200d1..2a3302f6 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -98,8 +98,8 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider params[1] = uint256(PoolToType[poolId]); } - function getWithdrawableAmount(uint256 poolId) external pure override returns (uint256 withdrawalAmount) { - withdrawalAmount = 0; + function getWithdrawableAmount(uint256 poolId) external view override returns (uint256 withdrawalAmount) { + withdrawalAmount = poolIdToAmount[poolId]; } function currentParamsTargetLenght() external pure override returns (uint256) { @@ -115,6 +115,7 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider } function UpgradeType(uint256 PoolId, uint8 newType) external { + require(nftContract.poolIdToProvider(PoolId) == this, "need to be THIS provider"); require(PoolToType[PoolId] != 0, "pool not registered"); require(msg.sender == nftContract.ownerOf(PoolId), "only the Owner can upgrade the type"); require(newType > PoolToType[PoolId], "new type must be bigger than the old one"); From 9626199567e045d3f4e863675d9531bcf4a32afa Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 23:08:34 +0300 Subject: [PATCH 09/42] fix CreateNewDelayVault --- .../DelayVaultProvider/DelayVaultProvider.sol | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 2a3302f6..3007f8dd 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -11,7 +11,10 @@ import "../util/CalcUtils.sol"; contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProviderState { using CalcUtils for uint256; - constructor(ILockDealNFT _nftContract, ProviderData[] memory _providersData) { + constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { + require(address(_token) != address(0x0), "invalid address"); + require(address(_nftContract) != address(0x0), "invalid address"); + Token = _token; nftContract = _nftContract; typesCount = uint8(_providersData.length); for (uint8 i = 0; i < typesCount; i++) { @@ -30,6 +33,7 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh uint8 public typesCount; ILockDealNFT public nftContract; + address public Token; //this is onlty the delta //the amount taken from the user is the amount of the pool // params[0] = startTimeDelta (empty for DealProvider) @@ -82,7 +86,7 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider UserToTotalAmount[to][theType] += amount; } - function registerPool(uint256 poolId, uint256[] calldata params) external override { + function registerPool(uint256 poolId, uint256[] calldata params) public override { uint8 theType = uint8(params[1]); uint256 amount = params[0]; require(PoolToType[poolId] == 0, "pool already registered"); @@ -122,4 +126,13 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider require(newType <= typesCount, "new type must be smaller than the types count"); PoolToType[PoolId] = newType; } + + function CreateNewDelayVault(uint256[] calldata params) external returns (uint256 PoolId) { + uint256 amount = params[0]; + uint8 theType = uint8(params[1]); + require(theType <= typesCount, "invalid type"); + require(amount > 0, "amount must be bigger than 0"); + PoolId = nftContract.mintAndTransfer(msg.sender, Token, msg.sender, amount, this); + registerPool(PoolId, params); + } } From c23d19bfe190b8f8f99f681b80268774fb2b0858 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 23:30:02 +0300 Subject: [PATCH 10/42] add more code --- .../DelayVaultProvider/DelayVaultProvider.sol | 32 ++++++++++--------- .../Provider/ProviderState.sol | 1 + 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 3007f8dd..0bd3f7ca 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -1,19 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/IProvider.sol"; import "../interfaces/ILockDealNFT.sol"; import "../interfaces/IBeforeTransfer.sol"; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import "../SimpleProviders/DealProvider/DealProviderState.sol"; import "../util/CalcUtils.sol"; +import "../SimpleProviders/Provider/ProviderModifiers.sol"; -contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProviderState { +contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, ProviderModifiers { using CalcUtils for uint256; constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { require(address(_token) != address(0x0), "invalid address"); require(address(_nftContract) != address(0x0), "invalid address"); + name = "DelayVaultProvider"; + Token = _token; nftContract = _nftContract; typesCount = uint8(_providersData.length); @@ -28,14 +30,15 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider } mapping(uint256 => address) internal LastPoolOwner; - mapping(address => uint256[]) internal UserToTotalAmount; //will be {typesCount} lentgh + mapping(address => uint256[]) public UserToTotalAmount; //will be {typesCount} lentgh mapping(uint256 => uint8) internal PoolToType; mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh uint8 public typesCount; ILockDealNFT public nftContract; address public Token; - //this is onlty the delta - //the amount taken from the user is the amount of the pool + + //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) struct ProviderData { @@ -43,7 +46,7 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider uint256[] params; } - function withdraw(uint256 tokenId) external override returns (uint256 withdrawnAmount, bool isFinal) { + function withdraw(uint256 tokenId) external override onlyNFT returns (uint256 withdrawnAmount, bool isFinal) { uint8 theType = PoolToType[tokenId]; address owner = LastPoolOwner[tokenId]; uint256 newPoolId = nftContract.mintForProvider(owner, TypeToProviderData[theType].provider); @@ -60,14 +63,17 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider //This need to make a new pool without transfering the token, the pool data is taken from the settings } - function beforeTransfer(address from, address to, uint256 poolId /*NonReentry*/) external override { - if (to == address(nftContract)) LastPoolOwner[poolId] = from; + /*TODO add reentry guard*/ + function beforeTransfer(address from, address to, uint256 poolId) external override onlyNFT { + if (to == address(nftContract)) + // this means it will be withdraw or split + LastPoolOwner[poolId] = from; //this is the only way to know the owner of the pool else { _handleTransfer(from, to, poolId); } } - function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override { + function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override onlyNFT { address oldOwner = LastPoolOwner[oldPoolId]; address newOwner = nftContract.ownerOf(newPoolId); uint256 amount = poolIdToAmount[oldPoolId].calcAmount(ratio); @@ -86,7 +92,7 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider UserToTotalAmount[to][theType] += amount; } - function registerPool(uint256 poolId, uint256[] calldata params) public override { + function registerPool(uint256 poolId, uint256[] calldata params) public override onlyProvider { uint8 theType = uint8(params[1]); uint256 amount = params[0]; require(PoolToType[poolId] == 0, "pool already registered"); @@ -106,14 +112,10 @@ contract DelayVaultProvider is IProvider, IBeforeTransfer, IERC165, DealProvider withdrawalAmount = poolIdToAmount[poolId]; } - function currentParamsTargetLenght() external pure override returns (uint256) { + function currentParamsTargetLenght() public view override returns (uint256) { return 2; } - function name() external pure override returns (string memory) { - return "DelayVaultProvider"; - } - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId || interfaceId == type(IBeforeTransfer).interfaceId; } diff --git a/contracts/SimpleProviders/Provider/ProviderState.sol b/contracts/SimpleProviders/Provider/ProviderState.sol index fff71a73..67b51a27 100644 --- a/contracts/SimpleProviders/Provider/ProviderState.sol +++ b/contracts/SimpleProviders/Provider/ProviderState.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import "../../interfaces/ILockDealNFT.sol"; +import "../../interfaces/IProvider.sol"; abstract contract ProviderState is IProvider { ///@dev Each provider sets its own name From d43045583b02342f1aa758e9ebaa8bea18864ea0 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 23:35:45 +0300 Subject: [PATCH 11/42] add _getWithdrawPoolParams --- .../DelayVaultProvider/DelayVaultProvider.sol | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 0bd3f7ca..e704fc4a 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -50,12 +50,7 @@ contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, Prov uint8 theType = PoolToType[tokenId]; address owner = LastPoolOwner[tokenId]; uint256 newPoolId = nftContract.mintForProvider(owner, TypeToProviderData[theType].provider); - uint256[] memory settings = TypeToProviderData[theType].params; - uint256[] memory params = new uint256[](settings.length + 1); - params[0] = poolIdToAmount[tokenId]; - for (uint256 i = 0; i < settings.length; i++) { - params[i + 1] = block.timestamp + settings[i]; - } + uint256[] memory params = _getWithdrawPoolParams(tokenId, theType); TypeToProviderData[theType].provider.registerPool(newPoolId, params); isFinal = true; withdrawnAmount = poolIdToAmount[tokenId] = 0; @@ -63,6 +58,16 @@ contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, Prov //This need to make a new pool without transfering the token, the pool data is taken from the settings } + function _getWithdrawPoolParams(uint256 poolId, uint8 theType) internal view returns (uint256[] memory params) { + uint256[] memory settings = TypeToProviderData[theType].params; + uint256 length = settings.length + 1; + params = new uint256[](length); + params[0] = poolIdToAmount[poolId]; + for (uint256 i = 0; i < settings.length; i++) { + params[i + 1] = block.timestamp + settings[i]; + } + } + /*TODO add reentry guard*/ function beforeTransfer(address from, address to, uint256 poolId) external override onlyNFT { if (to == address(nftContract)) From c98598900a0196820f17567f097fda1d865831cd Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 23:37:47 +0300 Subject: [PATCH 12/42] add require --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index e704fc4a..3a91dca4 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -14,6 +14,7 @@ contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, Prov constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { require(address(_token) != address(0x0), "invalid address"); require(address(_nftContract) != address(0x0), "invalid address"); + require(_providersData.length <= 255, "too many providers"); name = "DelayVaultProvider"; Token = _token; @@ -29,8 +30,8 @@ contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, Prov } } + mapping(address => uint256[]) public UserToTotalAmount; //thw array will be {typesCount} lentgh mapping(uint256 => address) internal LastPoolOwner; - mapping(address => uint256[]) public UserToTotalAmount; //will be {typesCount} lentgh mapping(uint256 => uint8) internal PoolToType; mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh uint8 public typesCount; From c7032a863cdd60ea709fc7df4d471544f0f3dd81 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Mon, 2 Oct 2023 23:53:20 +0300 Subject: [PATCH 13/42] ProviderState was red --- contracts/SimpleProviders/Provider/ProviderState.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/SimpleProviders/Provider/ProviderState.sol b/contracts/SimpleProviders/Provider/ProviderState.sol index 67b51a27..dfb8d1c2 100644 --- a/contracts/SimpleProviders/Provider/ProviderState.sol +++ b/contracts/SimpleProviders/Provider/ProviderState.sol @@ -6,11 +6,11 @@ import "../../interfaces/IProvider.sol"; abstract contract ProviderState is IProvider { ///@dev Each provider sets its own name - string public name; + string public override name; ILockDealNFT public lockDealNFT; ///@dev each provider decides how many parameters it needs by overriding this function - function currentParamsTargetLenght() public view virtual returns (uint256) { + function currentParamsTargetLenght() public view virtual override returns (uint256) { return 1; } } From 7a96a67f23e64608d6efd1f2cec4c52ab956b5bb Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 00:31:22 +0300 Subject: [PATCH 14/42] extract some code --- .../DelayVaultProvider/BeforeTransfer.sol | 32 ++++++++++ .../DelayVaultProvider/DelayVaultProvider.sol | 61 ++++++++----------- 2 files changed, 56 insertions(+), 37 deletions(-) create mode 100644 contracts/DelayVaultProvider/BeforeTransfer.sol diff --git a/contracts/DelayVaultProvider/BeforeTransfer.sol b/contracts/DelayVaultProvider/BeforeTransfer.sol new file mode 100644 index 00000000..0c365d90 --- /dev/null +++ b/contracts/DelayVaultProvider/BeforeTransfer.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../interfaces/IBeforeTransfer.sol"; +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import "../SimpleProviders/DealProvider/DealProviderState.sol"; +import "../SimpleProviders/Provider/ProviderModifiers.sol"; + +abstract contract BeforeTransfer is IBeforeTransfer, IERC165, DealProviderState, ProviderModifiers { + mapping(uint256 => address) internal LastPoolOwner; + mapping(uint256 => uint8) internal PoolToType; + mapping(address => uint256[]) public UserToTotalAmount; //thw array will be {typesCount} lentgh + + function beforeTransfer(address from, address to, uint256 poolId) external override { + _beforeTransfer(from, to, poolId); + } + + function _beforeTransfer(address from, address to, uint256 poolId) internal virtual { + 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 { + _handleTransfer(from, to, poolId); + } + } + + function _handleTransfer(address from, address to, uint256 poolId) internal virtual returns (uint256 amount); + + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId || interfaceId == type(IBeforeTransfer).interfaceId; + } +} diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 3a91dca4..71e7f019 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -1,14 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/ILockDealNFT.sol"; -import "../interfaces/IBeforeTransfer.sol"; +import "./BeforeTransfer.sol"; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import "../SimpleProviders/DealProvider/DealProviderState.sol"; import "../util/CalcUtils.sol"; -import "../SimpleProviders/Provider/ProviderModifiers.sol"; -contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, ProviderModifiers { +contract DelayVaultProvider is BeforeTransfer { using CalcUtils for uint256; constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { @@ -16,23 +13,22 @@ contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, Prov require(address(_nftContract) != address(0x0), "invalid address"); require(_providersData.length <= 255, "too many providers"); name = "DelayVaultProvider"; - Token = _token; - nftContract = _nftContract; + lockDealNFT = _nftContract; typesCount = uint8(_providersData.length); + uint256 limit = _providersData[0].limit; for (uint8 i = 0; i < typesCount; i++) { - require(address(_providersData[i].provider) != address(0x0), "invalid address"); - require( - _providersData[i].provider.currentParamsTargetLenght() == _providersData[i].params.length + 1, - "invalid params length" - ); - TypeToProviderData[i] = _providersData[i]; + ProviderData memory item = _providersData[i]; + require(address(item.provider) != address(0x0), "invalid address"); + require(item.provider.currentParamsTargetLenght() == item.params.length + 1, "invalid params length"); + if (i > 0) { + require(item.limit >= limit, "limit must be bigger or equal than the previous on"); + limit = item.limit; + } + TypeToProviderData[i] = item; } } - mapping(address => uint256[]) public UserToTotalAmount; //thw array will be {typesCount} lentgh - mapping(uint256 => address) internal LastPoolOwner; - mapping(uint256 => uint8) internal PoolToType; mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh uint8 public typesCount; ILockDealNFT public nftContract; @@ -44,7 +40,8 @@ contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, Prov // params[1] = endTimeDelta (only for TimedLockDealProvider) struct ProviderData { IProvider provider; - uint256[] params; + uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider + uint256 limit; } function withdraw(uint256 tokenId) external override onlyNFT returns (uint256 withdrawnAmount, bool isFinal) { @@ -69,16 +66,6 @@ contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, Prov } } - /*TODO add reentry guard*/ - function beforeTransfer(address from, address to, uint256 poolId) external override onlyNFT { - if (to == address(nftContract)) - // this means it will be withdraw or split - LastPoolOwner[poolId] = from; //this is the only way to know the owner of the pool - else { - _handleTransfer(from, to, poolId); - } - } - function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override onlyNFT { address oldOwner = LastPoolOwner[oldPoolId]; address newOwner = nftContract.ownerOf(newPoolId); @@ -91,20 +78,15 @@ contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, Prov } } - function _handleTransfer(address from, address to, uint256 poolId) internal returns (uint256 amount) { - uint8 theType = PoolToType[poolId]; - amount = poolIdToAmount[poolId]; - UserToTotalAmount[from][theType] -= amount; - UserToTotalAmount[to][theType] += amount; - } - function registerPool(uint256 poolId, uint256[] calldata params) public override onlyProvider { uint8 theType = uint8(params[1]); uint256 amount = params[0]; + uint256 newAmount = UserToTotalAmount[nftContract.ownerOf(poolId)][theType] + amount; + require(newAmount <= TypeToProviderData[theType].limit, "limit exceeded"); require(PoolToType[poolId] == 0, "pool already registered"); require(params.length == 2, "invalid params length"); PoolToType[poolId] = theType; - UserToTotalAmount[nftContract.ownerOf(poolId)][theType] += amount; + UserToTotalAmount[nftContract.ownerOf(poolId)][theType] = newAmount; poolIdToAmount[poolId] = amount; } @@ -122,8 +104,13 @@ contract DelayVaultProvider is IBeforeTransfer, IERC165, DealProviderState, Prov return 2; } - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - return interfaceId == type(IERC165).interfaceId || interfaceId == type(IBeforeTransfer).interfaceId; + function _handleTransfer(address from, address to, uint256 poolId) internal override returns (uint256 amount) { + uint8 theType = PoolToType[poolId]; + amount = poolIdToAmount[poolId]; + uint256 newAmount = UserToTotalAmount[to][theType] + amount; + require(newAmount <= TypeToProviderData[theType].limit, "limit exceeded"); + UserToTotalAmount[from][theType] -= amount; + UserToTotalAmount[to][theType] = newAmount; } function UpgradeType(uint256 PoolId, uint8 newType) external { From 752bfcfff9ebca446fd70b7f2085c57e5386fe14 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 00:35:41 +0300 Subject: [PATCH 15/42] add some code --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 71e7f019..fcc0e373 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -58,6 +58,13 @@ contract DelayVaultProvider is BeforeTransfer { function _getWithdrawPoolParams(uint256 poolId, uint8 theType) internal view returns (uint256[] memory params) { uint256[] memory settings = TypeToProviderData[theType].params; + params = _getWithdrawPoolParams(poolId, settings); + } + + function _getWithdrawPoolParams( + uint256 poolId, + uint256[] memory settings + ) internal view returns (uint256[] memory params) { uint256 length = settings.length + 1; params = new uint256[](length); params[0] = poolIdToAmount[poolId]; @@ -130,4 +137,8 @@ contract DelayVaultProvider is BeforeTransfer { PoolId = nftContract.mintAndTransfer(msg.sender, Token, msg.sender, amount, this); registerPool(PoolId, params); } + + function GetLeftAmount(address owner, uint8 theType) external view returns (uint256) { + return TypeToProviderData[theType].limit - UserToTotalAmount[owner][theType]; + } } From c045acaf2aaea3a1a062ad4580b788bfc5748130 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 00:37:51 +0300 Subject: [PATCH 16/42] add type(uint256).max --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index fcc0e373..b13e313c 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -27,6 +27,7 @@ contract DelayVaultProvider is BeforeTransfer { } TypeToProviderData[i] = item; } + TypeToProviderData[typesCount - 1].limit = type(uint256).max; //the last one is the max, token supply is out of the scope } mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh From cee603ad544ecee418074ed5d7b7d1df490fb886 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 00:44:32 +0300 Subject: [PATCH 17/42] order --- .../DelayVaultProvider/DelayVaultProvider.sol | 5 ++--- ...BeforeTransfer.sol => DelayVaultState.sol} | 16 +++------------- .../DelayVaultProvider/LastPoolOwnerState.sol | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 16 deletions(-) rename contracts/DelayVaultProvider/{BeforeTransfer.sol => DelayVaultState.sol} (54%) create mode 100644 contracts/DelayVaultProvider/LastPoolOwnerState.sol diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index b13e313c..e955afb0 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -1,11 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./BeforeTransfer.sol"; -import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import "./DelayVaultState.sol"; import "../util/CalcUtils.sol"; -contract DelayVaultProvider is BeforeTransfer { +contract DelayVaultProvider is DelayVaultState { using CalcUtils for uint256; constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { diff --git a/contracts/DelayVaultProvider/BeforeTransfer.sol b/contracts/DelayVaultProvider/DelayVaultState.sol similarity index 54% rename from contracts/DelayVaultProvider/BeforeTransfer.sol rename to contracts/DelayVaultProvider/DelayVaultState.sol index 0c365d90..bfacd4cc 100644 --- a/contracts/DelayVaultProvider/BeforeTransfer.sol +++ b/contracts/DelayVaultProvider/DelayVaultState.sol @@ -1,21 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/IBeforeTransfer.sol"; -import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import "../SimpleProviders/DealProvider/DealProviderState.sol"; import "../SimpleProviders/Provider/ProviderModifiers.sol"; +import "./LastPoolOwnerState.sol"; -abstract contract BeforeTransfer is IBeforeTransfer, IERC165, DealProviderState, ProviderModifiers { - mapping(uint256 => address) internal LastPoolOwner; +abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastPoolOwnerState { mapping(uint256 => uint8) internal PoolToType; mapping(address => uint256[]) public UserToTotalAmount; //thw array will be {typesCount} lentgh - function beforeTransfer(address from, address to, uint256 poolId) external override { - _beforeTransfer(from, to, poolId); - } - - function _beforeTransfer(address from, address to, uint256 poolId) internal virtual { + function _beforeTransfer(address from, address to, uint256 poolId) internal override { 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 @@ -25,8 +19,4 @@ abstract contract BeforeTransfer is IBeforeTransfer, IERC165, DealProviderState, } function _handleTransfer(address from, address to, uint256 poolId) internal virtual returns (uint256 amount); - - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - return interfaceId == type(IERC165).interfaceId || interfaceId == type(IBeforeTransfer).interfaceId; - } } diff --git a/contracts/DelayVaultProvider/LastPoolOwnerState.sol b/contracts/DelayVaultProvider/LastPoolOwnerState.sol new file mode 100644 index 00000000..b087163c --- /dev/null +++ b/contracts/DelayVaultProvider/LastPoolOwnerState.sol @@ -0,0 +1,19 @@ +// 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 override { + _beforeTransfer(from, to, poolId); + } + + function _beforeTransfer(address from, address to, uint256 poolId) internal virtual; + + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId || interfaceId == type(IBeforeTransfer).interfaceId; + } +} From 552df738bacfe7dd892d8f139905858f10013e6d Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 00:54:05 +0300 Subject: [PATCH 18/42] some code --- .../DelayVaultProvider/DelayVaultProvider.sol | 70 ++++--------------- .../DelayVaultProvider/DelayVaultState.sol | 44 +++++++++++- 2 files changed, 58 insertions(+), 56 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index e955afb0..e609fa4e 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -18,30 +18,19 @@ contract DelayVaultProvider is DelayVaultState { uint256 limit = _providersData[0].limit; for (uint8 i = 0; i < typesCount; i++) { ProviderData memory item = _providersData[i]; - require(address(item.provider) != address(0x0), "invalid address"); - require(item.provider.currentParamsTargetLenght() == item.params.length + 1, "invalid params length"); - if (i > 0) { - require(item.limit >= limit, "limit must be bigger or equal than the previous on"); - limit = item.limit; - } - TypeToProviderData[i] = item; + limit = _handleItem(i, limit, item); } TypeToProviderData[typesCount - 1].limit = type(uint256).max; //the last one is the max, token supply is out of the scope } - mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh - uint8 public typesCount; - ILockDealNFT public nftContract; - address public Token; - - //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) - struct ProviderData { - IProvider provider; - uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider - uint256 limit; + function _handleItem(uint8 index, 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"); + if (index > 0) { + limit = item.limit; + require(limit >= lastLimit, "limit must be bigger or equal than the previous on"); + } + TypeToProviderData[index] = item; } function withdraw(uint256 tokenId) external override onlyNFT returns (uint256 withdrawnAmount, bool isFinal) { @@ -56,23 +45,6 @@ contract DelayVaultProvider is DelayVaultState { //This need to make a new pool without transfering the token, the pool data is taken from the settings } - function _getWithdrawPoolParams(uint256 poolId, uint8 theType) internal view returns (uint256[] memory params) { - uint256[] memory settings = TypeToProviderData[theType].params; - params = _getWithdrawPoolParams(poolId, settings); - } - - function _getWithdrawPoolParams( - uint256 poolId, - uint256[] memory settings - ) internal view returns (uint256[] memory params) { - uint256 length = settings.length + 1; - params = new uint256[](length); - params[0] = poolIdToAmount[poolId]; - for (uint256 i = 0; i < settings.length; i++) { - params[i + 1] = block.timestamp + settings[i]; - } - } - function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override onlyNFT { address oldOwner = LastPoolOwner[oldPoolId]; address newOwner = nftContract.ownerOf(newPoolId); @@ -88,12 +60,13 @@ contract DelayVaultProvider is DelayVaultState { function registerPool(uint256 poolId, uint256[] calldata params) public override onlyProvider { uint8 theType = uint8(params[1]); uint256 amount = params[0]; - uint256 newAmount = UserToTotalAmount[nftContract.ownerOf(poolId)][theType] + amount; + address owner = nftContract.ownerOf(poolId); + uint256 newAmount = UserToTotalAmount[owner][theType] + amount; require(newAmount <= TypeToProviderData[theType].limit, "limit exceeded"); require(PoolToType[poolId] == 0, "pool already registered"); require(params.length == 2, "invalid params length"); PoolToType[poolId] = theType; - UserToTotalAmount[nftContract.ownerOf(poolId)][theType] = newAmount; + UserToTotalAmount[owner][theType] = newAmount; poolIdToAmount[poolId] = amount; } @@ -107,20 +80,7 @@ contract DelayVaultProvider is DelayVaultState { withdrawalAmount = poolIdToAmount[poolId]; } - function currentParamsTargetLenght() public view override returns (uint256) { - return 2; - } - - function _handleTransfer(address from, address to, uint256 poolId) internal override returns (uint256 amount) { - uint8 theType = PoolToType[poolId]; - amount = poolIdToAmount[poolId]; - uint256 newAmount = UserToTotalAmount[to][theType] + amount; - require(newAmount <= TypeToProviderData[theType].limit, "limit exceeded"); - UserToTotalAmount[from][theType] -= amount; - UserToTotalAmount[to][theType] = newAmount; - } - - function UpgradeType(uint256 PoolId, uint8 newType) external { + function upgradeType(uint256 PoolId, uint8 newType) external { require(nftContract.poolIdToProvider(PoolId) == this, "need to be THIS provider"); require(PoolToType[PoolId] != 0, "pool not registered"); require(msg.sender == nftContract.ownerOf(PoolId), "only the Owner can upgrade the type"); @@ -129,7 +89,7 @@ contract DelayVaultProvider is DelayVaultState { PoolToType[PoolId] = newType; } - function CreateNewDelayVault(uint256[] calldata params) external returns (uint256 PoolId) { + function createNewDelayVault(uint256[] calldata params) external returns (uint256 PoolId) { uint256 amount = params[0]; uint8 theType = uint8(params[1]); require(theType <= typesCount, "invalid type"); @@ -138,7 +98,7 @@ contract DelayVaultProvider is DelayVaultState { registerPool(PoolId, params); } - function GetLeftAmount(address owner, uint8 theType) external view returns (uint256) { + function getLeftAmount(address owner, uint8 theType) external view returns (uint256) { return TypeToProviderData[theType].limit - UserToTotalAmount[owner][theType]; } } diff --git a/contracts/DelayVaultProvider/DelayVaultState.sol b/contracts/DelayVaultProvider/DelayVaultState.sol index bfacd4cc..ad607a2b 100644 --- a/contracts/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/DelayVaultProvider/DelayVaultState.sol @@ -8,6 +8,20 @@ import "./LastPoolOwnerState.sol"; abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastPoolOwnerState { mapping(uint256 => uint8) internal PoolToType; mapping(address => uint256[]) public UserToTotalAmount; //thw array will be {typesCount} lentgh + mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh + uint8 public typesCount; + ILockDealNFT public nftContract; + address public Token; + + //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) + struct ProviderData { + IProvider provider; + uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider + uint256 limit; + } function _beforeTransfer(address from, address to, uint256 poolId) internal override { if (to == address(lockDealNFT)) @@ -18,5 +32,33 @@ abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastP } } - function _handleTransfer(address from, address to, uint256 poolId) internal virtual returns (uint256 amount); + function _handleTransfer(address from, address to, uint256 poolId) internal returns (uint256 amount) { + uint8 theType = PoolToType[poolId]; + amount = poolIdToAmount[poolId]; + uint256 newAmount = UserToTotalAmount[to][theType] + amount; + require(newAmount <= TypeToProviderData[theType].limit, "limit exceeded"); + UserToTotalAmount[from][theType] -= amount; + UserToTotalAmount[to][theType] = newAmount; + } + + function currentParamsTargetLenght() public view override returns (uint256) { + return 2; + } + + function _getWithdrawPoolParams(uint256 poolId, uint8 theType) internal view returns (uint256[] memory params) { + uint256[] memory settings = TypeToProviderData[theType].params; + params = _getWithdrawPoolParams(poolId, settings); + } + + function _getWithdrawPoolParams( + uint256 poolId, + uint256[] memory settings + ) internal view returns (uint256[] memory params) { + uint256 length = settings.length + 1; + params = new uint256[](length); + params[0] = poolIdToAmount[poolId]; + for (uint256 i = 0; i < settings.length; i++) { + params[i + 1] = block.timestamp + settings[i]; + } + } } From 7d8c4ec9883dd8cf42b8db338d8a739d11e0dad8 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 00:54:27 +0300 Subject: [PATCH 19/42] make pure --- contracts/DelayVaultProvider/DelayVaultState.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/DelayVaultProvider/DelayVaultState.sol b/contracts/DelayVaultProvider/DelayVaultState.sol index ad607a2b..22f9af1d 100644 --- a/contracts/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/DelayVaultProvider/DelayVaultState.sol @@ -41,7 +41,7 @@ abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastP UserToTotalAmount[to][theType] = newAmount; } - function currentParamsTargetLenght() public view override returns (uint256) { + function currentParamsTargetLenght() public pure override returns (uint256) { return 2; } From 00e23922a41fdd2499a500d83398fbf8b0f2c700 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 01:18:35 +0300 Subject: [PATCH 20/42] some refactor --- .../DelayVaultProvider/DelayVaultProvider.sol | 11 +--- .../DelayVaultProvider/DelayVaultState.sol | 24 ++------- contracts/DelayVaultProvider/HoldersSum.sol | 50 +++++++++++++++++++ 3 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 contracts/DelayVaultProvider/HoldersSum.sol diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index e609fa4e..77828dac 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -41,7 +41,7 @@ contract DelayVaultProvider is DelayVaultState { TypeToProviderData[theType].provider.registerPool(newPoolId, params); isFinal = true; withdrawnAmount = poolIdToAmount[tokenId] = 0; - UserToTotalAmount[owner][theType] -= params[0]; + _subHoldersSum(owner, theType, params[0]); //This need to make a new pool without transfering the token, the pool data is taken from the settings } @@ -61,12 +61,10 @@ contract DelayVaultProvider is DelayVaultState { uint8 theType = uint8(params[1]); uint256 amount = params[0]; address owner = nftContract.ownerOf(poolId); - uint256 newAmount = UserToTotalAmount[owner][theType] + amount; - require(newAmount <= TypeToProviderData[theType].limit, "limit exceeded"); require(PoolToType[poolId] == 0, "pool already registered"); require(params.length == 2, "invalid params length"); PoolToType[poolId] = theType; - UserToTotalAmount[owner][theType] = newAmount; + _addHoldersSum(owner, theType, amount); poolIdToAmount[poolId] = amount; } @@ -82,7 +80,6 @@ contract DelayVaultProvider is DelayVaultState { function upgradeType(uint256 PoolId, uint8 newType) external { require(nftContract.poolIdToProvider(PoolId) == this, "need to be THIS provider"); - require(PoolToType[PoolId] != 0, "pool not registered"); require(msg.sender == nftContract.ownerOf(PoolId), "only the Owner can upgrade the type"); require(newType > PoolToType[PoolId], "new type must be bigger than the old one"); require(newType <= typesCount, "new type must be smaller than the types count"); @@ -97,8 +94,4 @@ contract DelayVaultProvider is DelayVaultState { PoolId = nftContract.mintAndTransfer(msg.sender, Token, msg.sender, amount, this); registerPool(PoolId, params); } - - function getLeftAmount(address owner, uint8 theType) external view returns (uint256) { - return TypeToProviderData[theType].limit - UserToTotalAmount[owner][theType]; - } } diff --git a/contracts/DelayVaultProvider/DelayVaultState.sol b/contracts/DelayVaultProvider/DelayVaultState.sol index 22f9af1d..55c2b395 100644 --- a/contracts/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/DelayVaultProvider/DelayVaultState.sol @@ -4,25 +4,12 @@ pragma solidity ^0.8.0; import "../SimpleProviders/DealProvider/DealProviderState.sol"; import "../SimpleProviders/Provider/ProviderModifiers.sol"; import "./LastPoolOwnerState.sol"; +import "./HoldersSum.sol"; -abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastPoolOwnerState { - mapping(uint256 => uint8) internal PoolToType; - mapping(address => uint256[]) public UserToTotalAmount; //thw array will be {typesCount} lentgh - mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh - uint8 public typesCount; +abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastPoolOwnerState, HoldersSum { ILockDealNFT public nftContract; address public Token; - //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) - struct ProviderData { - IProvider provider; - uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider - uint256 limit; - } - function _beforeTransfer(address from, address to, uint256 poolId) internal override { if (to == address(lockDealNFT)) // this means it will be withdraw or split @@ -34,11 +21,8 @@ abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastP function _handleTransfer(address from, address to, uint256 poolId) internal returns (uint256 amount) { uint8 theType = PoolToType[poolId]; - amount = poolIdToAmount[poolId]; - uint256 newAmount = UserToTotalAmount[to][theType] + amount; - require(newAmount <= TypeToProviderData[theType].limit, "limit exceeded"); - UserToTotalAmount[from][theType] -= amount; - UserToTotalAmount[to][theType] = newAmount; + _subHoldersSum(from, theType, amount); + _addHoldersSum(to, theType, amount); } function currentParamsTargetLenght() public pure override returns (uint256) { diff --git a/contracts/DelayVaultProvider/HoldersSum.sol b/contracts/DelayVaultProvider/HoldersSum.sol new file mode 100644 index 00000000..5bea3352 --- /dev/null +++ b/contracts/DelayVaultProvider/HoldersSum.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../interfaces/IProvider.sol"; + +abstract contract HoldersSum { + //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) + struct ProviderData { + IProvider provider; + uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider + uint256 limit; + } + mapping(uint256 => uint8) internal PoolToType; + mapping(address => uint256[]) public UserToTotalAmount; //thw array will be {typesCount} lentgh + mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh + uint8 public typesCount; + + function _addHoldersSum(address user, uint8 theType, uint256 amount) internal { + uint256 newAmount = UserToTotalAmount[user][theType] + amount; + _setHoldersSum(user, theType, newAmount); + } + + function _subHoldersSum(address user, uint8 theType, uint256 amount) internal { + uint256 oldAmount = UserToTotalAmount[user][theType]; + require(oldAmount >= amount, "amount exceeded"); + uint256 newAmount = oldAmount - amount; + UserToTotalAmount[user][theType] = newAmount; + } + + function _setHoldersSum(address user, uint8 theType, uint256 amount) internal { + uint256[] memory amountsByType = UserToTotalAmount[user]; + require(amount <= TypeToProviderData[theType].limit, "limit exceeded"); + if (amountsByType.length == 0) { + amountsByType = new uint256[](typesCount); + UserToTotalAmount[user] = amountsByType; + } + UserToTotalAmount[user][theType] = amount; + } + + function _getHoldersSum(address user, uint8 theType) internal view returns (uint256 amount) { + amount = UserToTotalAmount[user][theType]; + } + + function getLeftAmount(address owner, uint8 theType) external view returns (uint256) { + return TypeToProviderData[theType].limit - _getHoldersSum(owner, theType); + } +} From 6ecc2753196d16ae80a09395615b73346d18579f Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 01:30:33 +0300 Subject: [PATCH 21/42] reorder --- .../DelayVaultProvider/DelayVaultProvider.sol | 43 +------------------ .../DelayVaultProvider/DelayVaultState.sol | 26 +++++++++++ contracts/DelayVaultProvider/HoldersSum.sol | 19 +++++++- 3 files changed, 45 insertions(+), 43 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 77828dac..13577265 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -2,11 +2,8 @@ pragma solidity ^0.8.0; import "./DelayVaultState.sol"; -import "../util/CalcUtils.sol"; contract DelayVaultProvider is DelayVaultState { - using CalcUtils for uint256; - constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { require(address(_token) != address(0x0), "invalid address"); require(address(_nftContract) != address(0x0), "invalid address"); @@ -15,45 +12,9 @@ contract DelayVaultProvider is DelayVaultState { Token = _token; lockDealNFT = _nftContract; typesCount = uint8(_providersData.length); - uint256 limit = _providersData[0].limit; + uint256 limit = 0; for (uint8 i = 0; i < typesCount; i++) { - ProviderData memory item = _providersData[i]; - limit = _handleItem(i, limit, item); - } - TypeToProviderData[typesCount - 1].limit = type(uint256).max; //the last one is the max, token supply is out of the scope - } - - function _handleItem(uint8 index, 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"); - if (index > 0) { - limit = item.limit; - require(limit >= lastLimit, "limit must be bigger or equal than the previous on"); - } - TypeToProviderData[index] = item; - } - - function withdraw(uint256 tokenId) external override onlyNFT returns (uint256 withdrawnAmount, bool isFinal) { - uint8 theType = PoolToType[tokenId]; - address owner = LastPoolOwner[tokenId]; - uint256 newPoolId = nftContract.mintForProvider(owner, TypeToProviderData[theType].provider); - uint256[] memory params = _getWithdrawPoolParams(tokenId, theType); - TypeToProviderData[theType].provider.registerPool(newPoolId, params); - isFinal = true; - withdrawnAmount = poolIdToAmount[tokenId] = 0; - _subHoldersSum(owner, theType, params[0]); - //This need to make a new pool without transfering the token, the pool data is taken from the settings - } - - function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override onlyNFT { - address oldOwner = LastPoolOwner[oldPoolId]; - address newOwner = nftContract.ownerOf(newPoolId); - uint256 amount = poolIdToAmount[oldPoolId].calcAmount(ratio); - poolIdToAmount[oldPoolId] -= amount; - poolIdToAmount[newPoolId] = amount; - PoolToType[newPoolId] = PoolToType[oldPoolId]; - if (newOwner != oldOwner) { - _handleTransfer(oldOwner, newOwner, oldPoolId); + limit = _setTypeToProviderData(i, limit, _providersData[i]); } } diff --git a/contracts/DelayVaultProvider/DelayVaultState.sol b/contracts/DelayVaultProvider/DelayVaultState.sol index 55c2b395..f42c3d8a 100644 --- a/contracts/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/DelayVaultProvider/DelayVaultState.sol @@ -5,8 +5,10 @@ import "../SimpleProviders/DealProvider/DealProviderState.sol"; import "../SimpleProviders/Provider/ProviderModifiers.sol"; import "./LastPoolOwnerState.sol"; import "./HoldersSum.sol"; +import "../util/CalcUtils.sol"; abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastPoolOwnerState, HoldersSum { + using CalcUtils for uint256; ILockDealNFT public nftContract; address public Token; @@ -45,4 +47,28 @@ abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastP params[i + 1] = block.timestamp + settings[i]; } } + + function withdraw(uint256 tokenId) external override onlyNFT returns (uint256 withdrawnAmount, bool isFinal) { + uint8 theType = PoolToType[tokenId]; + address owner = LastPoolOwner[tokenId]; + uint256 newPoolId = nftContract.mintForProvider(owner, TypeToProviderData[theType].provider); + uint256[] memory params = _getWithdrawPoolParams(tokenId, theType); + TypeToProviderData[theType].provider.registerPool(newPoolId, params); + isFinal = true; + withdrawnAmount = poolIdToAmount[tokenId] = 0; + _subHoldersSum(owner, theType, params[0]); + //This need to make a new pool without transfering the token, the pool data is taken from the settings + } + + function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override onlyNFT { + address oldOwner = LastPoolOwner[oldPoolId]; + address newOwner = nftContract.ownerOf(newPoolId); + uint256 amount = poolIdToAmount[oldPoolId].calcAmount(ratio); + poolIdToAmount[oldPoolId] -= amount; + poolIdToAmount[newPoolId] = amount; + PoolToType[newPoolId] = PoolToType[oldPoolId]; + if (newOwner != oldOwner) { + _handleTransfer(oldOwner, newOwner, oldPoolId); + } + } } diff --git a/contracts/DelayVaultProvider/HoldersSum.sol b/contracts/DelayVaultProvider/HoldersSum.sol index 5bea3352..c31c65ca 100644 --- a/contracts/DelayVaultProvider/HoldersSum.sol +++ b/contracts/DelayVaultProvider/HoldersSum.sol @@ -18,6 +18,10 @@ abstract contract HoldersSum { mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh uint8 public typesCount; + function getLeftAmount(address owner, uint8 theType) external view returns (uint256) { + return TypeToProviderData[theType].limit - _getHoldersSum(owner, theType); + } + function _addHoldersSum(address user, uint8 theType, uint256 amount) internal { uint256 newAmount = UserToTotalAmount[user][theType] + amount; _setHoldersSum(user, theType, newAmount); @@ -44,7 +48,18 @@ abstract contract HoldersSum { amount = UserToTotalAmount[user][theType]; } - function getLeftAmount(address owner, uint8 theType) external view returns (uint256) { - return TypeToProviderData[theType].limit - _getHoldersSum(owner, theType); + 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 + } } } From e4a66c795a9b5afaf780242a8c6e3a77db0164c6 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 01:39:49 +0300 Subject: [PATCH 22/42] swap imports --- contracts/DelayVaultProvider/DelayVaultState.sol | 3 +-- contracts/DelayVaultProvider/HoldersSum.sol | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultState.sol b/contracts/DelayVaultProvider/DelayVaultState.sol index f42c3d8a..9457f38d 100644 --- a/contracts/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/DelayVaultProvider/DelayVaultState.sol @@ -2,12 +2,11 @@ pragma solidity ^0.8.0; import "../SimpleProviders/DealProvider/DealProviderState.sol"; -import "../SimpleProviders/Provider/ProviderModifiers.sol"; import "./LastPoolOwnerState.sol"; import "./HoldersSum.sol"; import "../util/CalcUtils.sol"; -abstract contract DelayVaultState is DealProviderState, ProviderModifiers, LastPoolOwnerState, HoldersSum { +abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, HoldersSum { using CalcUtils for uint256; ILockDealNFT public nftContract; address public Token; diff --git a/contracts/DelayVaultProvider/HoldersSum.sol b/contracts/DelayVaultProvider/HoldersSum.sol index c31c65ca..e56f0361 100644 --- a/contracts/DelayVaultProvider/HoldersSum.sol +++ b/contracts/DelayVaultProvider/HoldersSum.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/IProvider.sol"; +import "../SimpleProviders/Provider/ProviderModifiers.sol"; -abstract contract HoldersSum { +abstract contract HoldersSum is ProviderModifiers { //this is only the delta //the amount is the amount of the pool // params[0] = startTimeDelta (empty for DealProvider) @@ -23,12 +23,12 @@ abstract contract HoldersSum { } function _addHoldersSum(address user, uint8 theType, uint256 amount) internal { - uint256 newAmount = UserToTotalAmount[user][theType] + amount; + uint256 newAmount = _getHoldersSum(user, theType) + amount; _setHoldersSum(user, theType, newAmount); } function _subHoldersSum(address user, uint8 theType, uint256 amount) internal { - uint256 oldAmount = UserToTotalAmount[user][theType]; + uint256 oldAmount = _getHoldersSum(user, theType); require(oldAmount >= amount, "amount exceeded"); uint256 newAmount = oldAmount - amount; UserToTotalAmount[user][theType] = newAmount; From d96cd13ab01f6a47b8b2de3b58550237555619b1 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 01:46:21 +0300 Subject: [PATCH 23/42] order --- contracts/DelayVaultProvider/DelayVaultState.sol | 2 +- contracts/DelayVaultProvider/LastPoolOwnerState.sol | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultState.sol b/contracts/DelayVaultProvider/DelayVaultState.sol index 9457f38d..623ecb91 100644 --- a/contracts/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/DelayVaultProvider/DelayVaultState.sol @@ -11,7 +11,7 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold ILockDealNFT public nftContract; address public Token; - function _beforeTransfer(address from, address to, uint256 poolId) internal override { + 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 diff --git a/contracts/DelayVaultProvider/LastPoolOwnerState.sol b/contracts/DelayVaultProvider/LastPoolOwnerState.sol index b087163c..de65666a 100644 --- a/contracts/DelayVaultProvider/LastPoolOwnerState.sol +++ b/contracts/DelayVaultProvider/LastPoolOwnerState.sol @@ -7,11 +7,7 @@ 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 override { - _beforeTransfer(from, to, poolId); - } - - function _beforeTransfer(address from, address to, uint256 poolId) internal virtual; + 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; From d746b1b556a00fba3e737a09511cac0868f1fbcc Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 01:52:41 +0300 Subject: [PATCH 24/42] add event --- .../DelayVaultProvider/DelayVaultProvider.sol | 15 +++++++++++++-- contracts/DelayVaultProvider/HoldersSum.sol | 4 +++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 13577265..f87c07a4 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -39,12 +39,23 @@ contract DelayVaultProvider is DelayVaultState { withdrawalAmount = poolIdToAmount[poolId]; } - function upgradeType(uint256 PoolId, uint8 newType) external { + function upgradeTypes(uint256[] calldata poolIds, uint8 newType) public { + for (uint256 i = 0; i < poolIds.length; i++) { + upgradeType(poolIds[i], newType); + } + } + + function upgradeType(uint256 PoolId, uint8 newType) public { + uint8 oldType = PoolToType[PoolId]; + uint256 amount = poolIdToAmount[PoolId]; + require(amount > 0, "pool is empty"); require(nftContract.poolIdToProvider(PoolId) == this, "need to be THIS provider"); require(msg.sender == nftContract.ownerOf(PoolId), "only the Owner can upgrade the type"); - require(newType > PoolToType[PoolId], "new type must be bigger than the old one"); + require(newType > oldType, "new type must be bigger than the old one"); require(newType <= typesCount, "new type must be smaller than the types count"); PoolToType[PoolId] = newType; + _subHoldersSum(msg.sender, oldType, amount); + _addHoldersSum(msg.sender, newType, amount); } function createNewDelayVault(uint256[] calldata params) external returns (uint256 PoolId) { diff --git a/contracts/DelayVaultProvider/HoldersSum.sol b/contracts/DelayVaultProvider/HoldersSum.sol index e56f0361..bdec615f 100644 --- a/contracts/DelayVaultProvider/HoldersSum.sol +++ b/contracts/DelayVaultProvider/HoldersSum.sol @@ -8,6 +8,7 @@ abstract contract HoldersSum is ProviderModifiers { //the amount is the amount of the pool // params[0] = startTimeDelta (empty for DealProvider) // params[1] = endTimeDelta (only for TimedLockDealProvider) + event HoldersSumChanged(address indexed user, uint8 indexed theType, uint256 amount); struct ProviderData { IProvider provider; uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider @@ -31,7 +32,7 @@ abstract contract HoldersSum is ProviderModifiers { uint256 oldAmount = _getHoldersSum(user, theType); require(oldAmount >= amount, "amount exceeded"); uint256 newAmount = oldAmount - amount; - UserToTotalAmount[user][theType] = newAmount; + _setHoldersSum(user, theType, newAmount); } function _setHoldersSum(address user, uint8 theType, uint256 amount) internal { @@ -42,6 +43,7 @@ abstract contract HoldersSum is ProviderModifiers { UserToTotalAmount[user] = amountsByType; } UserToTotalAmount[user][theType] = amount; + emit HoldersSumChanged(user, theType, amount); } function _getHoldersSum(address user, uint8 theType) internal view returns (uint256 amount) { From e19b2dfcdf0f0ae425a6dc932ac5ea5168ccf2da Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 01:54:47 +0300 Subject: [PATCH 25/42] typo --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index f87c07a4..8d3276aa 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -52,7 +52,7 @@ contract DelayVaultProvider is DelayVaultState { require(nftContract.poolIdToProvider(PoolId) == this, "need to be THIS provider"); require(msg.sender == nftContract.ownerOf(PoolId), "only the Owner can upgrade the type"); require(newType > oldType, "new type must be bigger than the old one"); - require(newType <= typesCount, "new type must be smaller than the types count"); + require(newType < typesCount, "new type must be smaller than the types count"); PoolToType[PoolId] = newType; _subHoldersSum(msg.sender, oldType, amount); _addHoldersSum(msg.sender, newType, amount); From 574655a49e9e8d2a3e9a39912ac0e375958076c5 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 02:02:17 +0300 Subject: [PATCH 26/42] add if --- contracts/LockDealNFT/LockDealNFTInternal.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/LockDealNFT/LockDealNFTInternal.sol b/contracts/LockDealNFT/LockDealNFTInternal.sol index 34deff7a..06d43f36 100644 --- a/contracts/LockDealNFT/LockDealNFTInternal.sol +++ b/contracts/LockDealNFT/LockDealNFTInternal.sol @@ -8,7 +8,10 @@ import "../interfaces/IBeforeTransfer.sol"; abstract contract LockDealNFTInternal is LockDealNFTModifiers { function _transfer(address from, address to, uint256 poolId) internal override { - if (ERC165Checker.supportsInterface(address(poolIdToProvider[poolId]), type(IBeforeTransfer).interfaceId)) { + if ( + from != address(0) && + ERC165Checker.supportsInterface(address(poolIdToProvider[poolId]), type(IBeforeTransfer).interfaceId) + ) { IBeforeTransfer(address(poolIdToProvider[poolId])).beforeTransfer(from, to, poolId); } // check for split and withdraw transfers From fb98c54f41ffcab2c0888ac738e2a75d873c8be9 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 17:19:24 +0300 Subject: [PATCH 27/42] add owner to createNewDelayVault --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 8d3276aa..6e4a52c6 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -58,12 +58,12 @@ contract DelayVaultProvider is DelayVaultState { _addHoldersSum(msg.sender, newType, amount); } - function createNewDelayVault(uint256[] calldata params) external returns (uint256 PoolId) { + function createNewDelayVault(address owner, uint256[] calldata params) external returns (uint256 PoolId) { uint256 amount = params[0]; uint8 theType = uint8(params[1]); require(theType <= typesCount, "invalid type"); require(amount > 0, "amount must be bigger than 0"); - PoolId = nftContract.mintAndTransfer(msg.sender, Token, msg.sender, amount, this); + PoolId = nftContract.mintAndTransfer(owner, Token, msg.sender, amount, this); registerPool(PoolId, params); } } From fa9a0675fae8f05c732b8c9f520033250a504778 Mon Sep 17 00:00:00 2001 From: Stan Goldin <48094744+Lomet@users.noreply.github.com> Date: Tue, 3 Oct 2023 23:13:57 +0300 Subject: [PATCH 28/42] delay vault migrator (#337) * draft * some other POV * some refactor --- .../DelayVaultProvider/DelayVaultProvider.sol | 40 +++++------ .../DelayVaultProvider/DelayVaultState.sol | 41 ++++++----- contracts/DelayVaultProvider/HoldersSum.sol | 68 +++++++++++-------- .../MigratorV1/DelayVaultMigrator.sol | 56 +++++++++++++++ .../MigratorV1/IDelayVaultProvider.sol | 31 +++++++++ .../MigratorV1/IDelayVaultV1.sol | 10 +++ .../MigratorV1/IMigrator.sol | 6 ++ contracts/LockDealNFT/ILockDealNFTEvents.sol | 2 +- contracts/LockDealNFT/LockDealNFT.sol | 10 +-- contracts/LockDealNFT/LockDealNFTInternal.sol | 2 +- .../LockDealNFT/LockDealNFTModifiers.sol | 6 +- contracts/LockDealNFT/LockDealNFTState.sol | 2 +- .../Provider/ProviderModifiers.sol | 2 +- contracts/interfaces/ILockDealNFT.sol | 2 +- 14 files changed, 194 insertions(+), 84 deletions(-) create mode 100644 contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol create mode 100644 contracts/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol create mode 100644 contracts/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol create mode 100644 contracts/DelayVaultProvider/MigratorV1/IMigrator.sol diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 6e4a52c6..59b96472 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -18,52 +18,46 @@ contract DelayVaultProvider is DelayVaultState { } } - function registerPool(uint256 poolId, uint256[] calldata params) public override onlyProvider { - uint8 theType = uint8(params[1]); + //params[0] = amount + //params[1] = allowTypeChange, 0 = false, 1(or any) = true + function registerPool(uint256 poolId, uint256[] calldata params) public override onlyProvider onlyProvider { uint256 amount = params[0]; + bool allowTypeChange = params[1] > 0; address owner = nftContract.ownerOf(poolId); - require(PoolToType[poolId] == 0, "pool already registered"); require(params.length == 2, "invalid params length"); - PoolToType[poolId] = theType; - _addHoldersSum(owner, theType, amount); + _addHoldersSum(owner, amount, allowTypeChange); poolIdToAmount[poolId] = amount; } function getParams(uint256 poolId) external view override returns (uint256[] memory params) { params = new uint256[](2); params[0] = poolIdToAmount[poolId]; - params[1] = uint256(PoolToType[poolId]); } function getWithdrawableAmount(uint256 poolId) external view override returns (uint256 withdrawalAmount) { withdrawalAmount = poolIdToAmount[poolId]; } - function upgradeTypes(uint256[] calldata poolIds, uint8 newType) public { - for (uint256 i = 0; i < poolIds.length; i++) { - upgradeType(poolIds[i], newType); - } - } - - function upgradeType(uint256 PoolId, uint8 newType) public { - uint8 oldType = PoolToType[PoolId]; - uint256 amount = poolIdToAmount[PoolId]; - require(amount > 0, "pool is empty"); - require(nftContract.poolIdToProvider(PoolId) == this, "need to be THIS provider"); - require(msg.sender == nftContract.ownerOf(PoolId), "only the Owner can upgrade the type"); + 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"); - PoolToType[PoolId] = newType; - _subHoldersSum(msg.sender, oldType, amount); - _addHoldersSum(msg.sender, newType, amount); + UserToType[msg.sender] = newType; } function createNewDelayVault(address owner, uint256[] calldata params) external returns (uint256 PoolId) { uint256 amount = params[0]; - uint8 theType = uint8(params[1]); - require(theType <= typesCount, "invalid type"); + bool allowTypeChange = params[1] > 0; + require(params.length == 2, "invalid params length"); + require(!allowTypeChange || _isAllowedChanheType(owner), "only owner can upgrade type"); require(amount > 0, "amount must be bigger than 0"); PoolId = nftContract.mintAndTransfer(owner, Token, msg.sender, amount, this); registerPool(PoolId, params); } + + function _isAllowedChanheType(address owner) internal view returns (bool) { + return owner == msg.sender || lockDealNFT.approvedProviders(msg.sender); + } } diff --git a/contracts/DelayVaultProvider/DelayVaultState.sol b/contracts/DelayVaultProvider/DelayVaultState.sol index 623ecb91..55373bdb 100644 --- a/contracts/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/DelayVaultProvider/DelayVaultState.sol @@ -21,42 +21,48 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold } function _handleTransfer(address from, address to, uint256 poolId) internal returns (uint256 amount) { - uint8 theType = PoolToType[poolId]; - _subHoldersSum(from, theType, amount); - _addHoldersSum(to, theType, amount); + amount = poolIdToAmount[poolId]; + _subHoldersSum(from, amount); + _addHoldersSum(to, amount, false); } - function currentParamsTargetLenght() public pure override returns (uint256) { - return 2; - } - - function _getWithdrawPoolParams(uint256 poolId, uint8 theType) internal view returns (uint256[] memory params) { + function getWithdrawPoolParams(uint256 amount, uint8 theType) public view returns (uint256[] memory params) { uint256[] memory settings = TypeToProviderData[theType].params; - params = _getWithdrawPoolParams(poolId, settings); + params = _getWithdrawPoolParams(amount, settings); } function _getWithdrawPoolParams( - uint256 poolId, + uint256 amount, uint256[] memory settings ) internal view returns (uint256[] memory params) { uint256 length = settings.length + 1; params = new uint256[](length); - params[0] = poolIdToAmount[poolId]; + 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) { - uint8 theType = PoolToType[tokenId]; address owner = LastPoolOwner[tokenId]; - uint256 newPoolId = nftContract.mintForProvider(owner, TypeToProviderData[theType].provider); - uint256[] memory params = _getWithdrawPoolParams(tokenId, theType); - TypeToProviderData[theType].provider.registerPool(newPoolId, params); + uint8 theType = UserToType[owner]; + uint256 amount = poolIdToAmount[tokenId]; + _createLockNFT(owner, amount, theType, tokenId); isFinal = true; withdrawnAmount = poolIdToAmount[tokenId] = 0; - _subHoldersSum(owner, theType, params[0]); - //This need to make a new pool without transfering the token, the pool data is taken from the settings + _subHoldersSum(owner, amount); + if (getTotalAmount(owner) == 0) { + UserToType[owner] = 0; //reset the type + } + } + + function _createLockNFT(address owner, uint256 amount, uint8 theType, uint tokenId) internal { + ProviderData memory providerData = TypeToProviderData[theType]; + uint256 newPoolId = nftContract.mintForProvider(owner, providerData.provider); + nftContract.copyVaultId(tokenId, newPoolId); + uint256[] memory params = getWithdrawPoolParams(amount, theType); + providerData.provider.registerPool(newPoolId, params); } function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override onlyNFT { @@ -65,7 +71,6 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold uint256 amount = poolIdToAmount[oldPoolId].calcAmount(ratio); poolIdToAmount[oldPoolId] -= amount; poolIdToAmount[newPoolId] = amount; - PoolToType[newPoolId] = PoolToType[oldPoolId]; if (newOwner != oldOwner) { _handleTransfer(oldOwner, newOwner, oldPoolId); } diff --git a/contracts/DelayVaultProvider/HoldersSum.sol b/contracts/DelayVaultProvider/HoldersSum.sol index bdec615f..ce7934d2 100644 --- a/contracts/DelayVaultProvider/HoldersSum.sol +++ b/contracts/DelayVaultProvider/HoldersSum.sol @@ -2,52 +2,60 @@ pragma solidity ^0.8.0; import "../SimpleProviders/Provider/ProviderModifiers.sol"; +import "./MigratorV1/IDelayVaultProvider.sol"; +import "./MigratorV1/IMigrator.sol"; -abstract contract HoldersSum is ProviderModifiers { +abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { //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) - event HoldersSumChanged(address indexed user, uint8 indexed theType, uint256 amount); - struct ProviderData { - IProvider provider; - uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider - uint256 limit; + event HoldersSumChanged(address indexed user, uint256 amount); + 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} lentgh + uint8 public typesCount; //max type + 1 + + IMigrator public Migrator; + + function getTotalAmount(address user) public view returns (uint256) { + return UserToAmount[user] + Migrator.getUserV1Amount(user); } - mapping(uint256 => uint8) internal PoolToType; - mapping(address => uint256[]) public UserToTotalAmount; //thw array will be {typesCount} lentgh - mapping(uint8 => ProviderData) internal TypeToProviderData; //will be {typesCount} lentgh - uint8 public typesCount; - function getLeftAmount(address owner, uint8 theType) external view returns (uint256) { - return TypeToProviderData[theType].limit - _getHoldersSum(owner, theType); + 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, uint8 theType, uint256 amount) internal { - uint256 newAmount = _getHoldersSum(user, theType) + amount; - _setHoldersSum(user, theType, newAmount); + function _addHoldersSum(address user, uint256 amount, bool allowTypeUpgrade) internal { + uint256 newAmount = UserToAmount[user] + amount; + _setHoldersSum(user, newAmount, allowTypeUpgrade); } - function _subHoldersSum(address user, uint8 theType, uint256 amount) internal { - uint256 oldAmount = _getHoldersSum(user, theType); + function _subHoldersSum(address user, uint256 amount) internal { + uint256 oldAmount = UserToAmount[user]; require(oldAmount >= amount, "amount exceeded"); uint256 newAmount = oldAmount - amount; - _setHoldersSum(user, theType, newAmount); + _setHoldersSum(user, newAmount, false); } - function _setHoldersSum(address user, uint8 theType, uint256 amount) internal { - uint256[] memory amountsByType = UserToTotalAmount[user]; - require(amount <= TypeToProviderData[theType].limit, "limit exceeded"); - if (amountsByType.length == 0) { - amountsByType = new uint256[](typesCount); - UserToTotalAmount[user] = amountsByType; + function _setHoldersSum(address user, uint256 amount, bool allowTypeUpgrade) internal { + uint8 newType = theTypeOf(getTotalAmount(user) + amount); + if (allowTypeUpgrade) { + // Upgrade the user type if the newType is greater + if (newType > UserToType[user]) { + UserToType[user] = newType; + } + } else { + // Ensure the type doesn't change if upgrades are not allowed + require(newType <= UserToType[user], "type must be the same or lower"); } - UserToTotalAmount[user][theType] = amount; - emit HoldersSumChanged(user, theType, amount); - } - - function _getHoldersSum(address user, uint8 theType) internal view returns (uint256 amount) { - amount = UserToTotalAmount[user][theType]; + UserToAmount[user] = amount; + emit HoldersSumChanged(user, amount); } function _setTypeToProviderData( diff --git a/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol b/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol new file mode 100644 index 00000000..1ac364d6 --- /dev/null +++ b/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IDelayVaultProvider.sol"; +import "./IDelayVaultV1.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract DelayVaultMigrator is IDelayVaultData { + IDelayVaultV1 public oldVault; + IDelayVaultProvider public newVault; + address public token; + address public vaultManager; + ILockDealNFT public nftContract; + + constructor(IDelayVaultProvider _newVault, IDelayVaultV1 _oldVault, address _vaultManager) { + newVault = _newVault; + oldVault = _oldVault; + token = newVault.Token(); + vaultManager = _vaultManager; + nftContract = _newVault.nftContract(); + } + + function fullMigrate() external { + 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[](2); + params[0] = amount; + params[1] = 1; //allow type change + IERC20(token).approve(vaultManager, amount); + newVault.createNewDelayVault(msg.sender, params); + } + + function getUserV1Amount(address user) public view returns (uint256) { + (uint256 amount, , , ) = oldVault.VaultMap(newVault.Token(), user); + return amount; + } + + function withdrawTokensFromV1Vault() external { + 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)); + ProviderData memory providerData = newVault.TypeToProviderData(theType); + IERC20(token).approve(vaultManager, amount); + uint256 newPoolId = nftContract.mintAndTransfer( + msg.sender, + token, + address(this), + amount, + providerData.provider + ); + uint256[] memory params = newVault.getWithdrawPoolParams(amount, theType); + providerData.provider.registerPool(newPoolId, params); + } +} diff --git a/contracts/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol b/contracts/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol new file mode 100644 index 00000000..9aa32ba2 --- /dev/null +++ b/contracts/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../../interfaces/IProvider.sol"; +import "../../interfaces/ILockDealNFT.sol"; + +interface IDelayVaultProvider { + function createNewDelayVault(address owner, uint256[] memory params) external; + + function Token() external view returns (address); + + function getLeftAmount(address owner, uint8 theType) external view returns (uint256); + + function theTypeOf(uint256 amount) external view returns (uint8); + + function nftContract() external view returns (ILockDealNFT); + + function getTotalAmount(address user) external view returns (uint256); + + function TypeToProviderData(uint8 theType) external view returns (IDelayVaultData.ProviderData memory providerData); + + function getWithdrawPoolParams(uint256 amount, uint8 theType) external view returns (uint256[] memory params); +} + +interface IDelayVaultData { + struct ProviderData { + IProvider provider; + uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider + uint256 limit; + } +} diff --git a/contracts/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol b/contracts/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol new file mode 100644 index 00000000..5e6b4fa3 --- /dev/null +++ b/contracts/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IDelayVaultV1 { + function redeemTokensFromVault(address _token, address _owner, uint256 _amount) external; + + function Allowance(address _token, address _owner) external view returns (bool); + + function VaultMap(address _token, address _owner) external view returns (uint256, uint256, uint256, uint256); +} diff --git a/contracts/DelayVaultProvider/MigratorV1/IMigrator.sol b/contracts/DelayVaultProvider/MigratorV1/IMigrator.sol new file mode 100644 index 00000000..37e5cb71 --- /dev/null +++ b/contracts/DelayVaultProvider/MigratorV1/IMigrator.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IMigrator { + function getUserV1Amount(address user) external view returns (uint256 amount); +} diff --git a/contracts/LockDealNFT/ILockDealNFTEvents.sol b/contracts/LockDealNFT/ILockDealNFTEvents.sol index c7d10044..04b8b39d 100644 --- a/contracts/LockDealNFT/ILockDealNFTEvents.sol +++ b/contracts/LockDealNFT/ILockDealNFTEvents.sol @@ -6,7 +6,7 @@ import "../interfaces/IProvider.sol"; /// @title ILockDealNFTEvents interface /// @notice Contains all events emitted by the LockDealNFT interface ILockDealNFTEvents { - event ProviderApproved(IProvider indexed provider, bool status); + event ProviderApproved(address indexed provider, bool status); event BaseURIChanged(string oldBaseURI, string newBaseURI); event TokenWithdrawn(uint256 poolId, address indexed owner, uint256 withdrawnAmount, uint256 leftAmount); event PoolSplit( diff --git a/contracts/LockDealNFT/LockDealNFT.sol b/contracts/LockDealNFT/LockDealNFT.sol index 36c54828..0c8d4093 100644 --- a/contracts/LockDealNFT/LockDealNFT.sol +++ b/contracts/LockDealNFT/LockDealNFT.sol @@ -10,14 +10,14 @@ contract LockDealNFT is LockDealNFTInternal, IERC721Receiver { constructor(address _vaultManager, string memory _baseURI) ERC721("LockDealNFT", "LDNFT") { _notZeroAddress(_vaultManager); vaultManager = IVaultManager(_vaultManager); - approvedProviders[IProvider(address(this))] = true; + approvedProviders[address(this)] = true; baseURI = _baseURI; } function mintForProvider( address owner, IProvider provider - ) external onlyApprovedProvider(provider) notZeroAddress(owner) returns (uint256 poolId) { + ) external onlyApprovedProvider(address(provider)) notZeroAddress(owner) returns (uint256 poolId) { poolId = _mint(owner, provider); } @@ -29,7 +29,7 @@ contract LockDealNFT is LockDealNFTInternal, IERC721Receiver { IProvider provider ) public - onlyApprovedProvider(provider) + onlyApprovedProvider(address(provider)) notZeroAddress(owner) notZeroAddress(token) notZeroAmount(amount) @@ -43,14 +43,14 @@ contract LockDealNFT is LockDealNFTInternal, IERC721Receiver { function copyVaultId( uint256 fromId, uint256 toId - ) external onlyApprovedProvider(IProvider(msg.sender)) validPoolId(fromId) validPoolId(toId) { + ) external onlyApprovedProvider(msg.sender) validPoolId(fromId) validPoolId(toId) { poolIdToVaultId[toId] = poolIdToVaultId[fromId]; } /// @dev Sets the approved status of a provider /// @param provider The address of the provider /// @param status The new approved status (true or false) - function setApprovedProvider(IProvider provider, bool status) external onlyOwner onlyContract(address(provider)) { + function setApprovedProvider(address provider, bool status) external onlyOwner onlyContract(address(provider)) { approvedProviders[provider] = status; emit ProviderApproved(provider, status); } diff --git a/contracts/LockDealNFT/LockDealNFTInternal.sol b/contracts/LockDealNFT/LockDealNFTInternal.sol index 06d43f36..2ab5a119 100644 --- a/contracts/LockDealNFT/LockDealNFTInternal.sol +++ b/contracts/LockDealNFT/LockDealNFTInternal.sol @@ -15,7 +15,7 @@ abstract contract LockDealNFTInternal is LockDealNFTModifiers { IBeforeTransfer(address(poolIdToProvider[poolId])).beforeTransfer(from, to, poolId); } // check for split and withdraw transfers - if (!(approvedProviders[IProvider(to)] || approvedProviders[IProvider(from)])) { + if (!(approvedProviders[to] || approvedProviders[from])) { require(approvedPoolUserTransfers[from], "Pool transfer not approved by user"); require( vaultManager.vaultIdToTradeStartTime(poolIdToVaultId[poolId]) < block.timestamp, diff --git a/contracts/LockDealNFT/LockDealNFTModifiers.sol b/contracts/LockDealNFT/LockDealNFTModifiers.sol index 377f821f..f2ddfb89 100644 --- a/contracts/LockDealNFT/LockDealNFTModifiers.sol +++ b/contracts/LockDealNFT/LockDealNFTModifiers.sol @@ -4,10 +4,10 @@ pragma solidity ^0.8.0; import "./LockDealNFTState.sol"; abstract contract LockDealNFTModifiers is LockDealNFTState { - modifier onlyApprovedProvider(IProvider provider) { + modifier onlyApprovedProvider(address provider) { _onlyApprovedProvider(provider); if (address(provider) != msg.sender) { - _onlyApprovedProvider(IProvider(msg.sender)); + _onlyApprovedProvider(msg.sender); } _; } @@ -40,7 +40,7 @@ abstract contract LockDealNFTModifiers is LockDealNFTState { require(Address.isContract(contractAddress), "Invalid contract address"); } - function _onlyApprovedProvider(IProvider provider) internal view { + function _onlyApprovedProvider(address provider) internal view { require(approvedProviders[provider], "Provider not approved"); } diff --git a/contracts/LockDealNFT/LockDealNFTState.sol b/contracts/LockDealNFT/LockDealNFTState.sol index 1060b749..ba0c95ef 100644 --- a/contracts/LockDealNFT/LockDealNFTState.sol +++ b/contracts/LockDealNFT/LockDealNFTState.sol @@ -20,7 +20,7 @@ abstract contract LockDealNFTState is ERC721Enumerable, ILockDealNFTEvents, Owna mapping(uint256 => IProvider) public poolIdToProvider; mapping(uint256 => uint256) public poolIdToVaultId; mapping(address => bool) public approvedPoolUserTransfers; - mapping(IProvider => bool) public approvedProviders; + mapping(address => bool) public approvedProviders; function getData(uint256 poolId) public view returns (BasePoolInfo memory poolInfo) { if (_exists(poolId)) { diff --git a/contracts/SimpleProviders/Provider/ProviderModifiers.sol b/contracts/SimpleProviders/Provider/ProviderModifiers.sol index e5b1b0ed..173a0b81 100644 --- a/contracts/SimpleProviders/Provider/ProviderModifiers.sol +++ b/contracts/SimpleProviders/Provider/ProviderModifiers.sol @@ -52,7 +52,7 @@ abstract contract ProviderModifiers is ProviderState { } function _onlyProvider() private view { - require(lockDealNFT.approvedProviders(IProvider(msg.sender)), "invalid provider address"); + require(lockDealNFT.approvedProviders(msg.sender), "invalid provider address"); } function _validProviderInterface(IProvider provider, bytes4 interfaceId) internal view { diff --git a/contracts/interfaces/ILockDealNFT.sol b/contracts/interfaces/ILockDealNFT.sol index 42b06a95..a81fc954 100644 --- a/contracts/interfaces/ILockDealNFT.sol +++ b/contracts/interfaces/ILockDealNFT.sol @@ -5,7 +5,7 @@ import "./IProvider.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; interface ILockDealNFT is IERC721Enumerable { - function approvedProviders(IProvider provider) external view returns (bool); + function approvedProviders(address provider) external view returns (bool); function mintAndTransfer( address owner, From 6a0a32452eee77af3ad2abe6475ca3cfe4d73c9d Mon Sep 17 00:00:00 2001 From: Stan Goldin <48094744+Lomet@users.noreply.github.com> Date: Tue, 3 Oct 2023 23:22:47 +0300 Subject: [PATCH 29/42] Update LockDealNFT.sol --- contracts/LockDealNFT/LockDealNFT.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/LockDealNFT/LockDealNFT.sol b/contracts/LockDealNFT/LockDealNFT.sol index 951de1c4..575e1315 100644 --- a/contracts/LockDealNFT/LockDealNFT.sol +++ b/contracts/LockDealNFT/LockDealNFT.sol @@ -53,7 +53,6 @@ contract LockDealNFT is LockDealNFTInternal, IERC721Receiver { function setApprovedContract(address contractAddress, bool status) external onlyOwner onlyContract(contractAddress) { approvedContracts[contractAddress] = status; emit ContractApproved(contractAddress, status); - } function approvePoolTransfers(bool status) external { From 553ba0ff6a0c04bfcf5e9f845b9599f66329bac2 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 23:29:28 +0300 Subject: [PATCH 30/42] add else if --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 2 +- contracts/DelayVaultProvider/DelayVaultState.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 59b96472..51d4bd69 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -58,6 +58,6 @@ contract DelayVaultProvider is DelayVaultState { } function _isAllowedChanheType(address owner) internal view returns (bool) { - return owner == msg.sender || lockDealNFT.approvedProviders(msg.sender); + return owner == msg.sender || lockDealNFT.approvedContracts(msg.sender); } } diff --git a/contracts/DelayVaultProvider/DelayVaultState.sol b/contracts/DelayVaultProvider/DelayVaultState.sol index 55373bdb..c6b2c485 100644 --- a/contracts/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/DelayVaultProvider/DelayVaultState.sol @@ -15,7 +15,7 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold 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 { + else if (from != address(0) && !nftContract.approvedContracts(from)) { _handleTransfer(from, to, poolId); } } From 2e3707c9a4b9c9369b5d54878b9cc35509f06aa0 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 23:32:40 +0300 Subject: [PATCH 31/42] remove return --- .../DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol b/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol index 1ac364d6..af041758 100644 --- a/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol +++ b/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol @@ -31,9 +31,8 @@ contract DelayVaultMigrator is IDelayVaultData { newVault.createNewDelayVault(msg.sender, params); } - function getUserV1Amount(address user) public view returns (uint256) { - (uint256 amount, , , ) = oldVault.VaultMap(newVault.Token(), user); - return amount; + function getUserV1Amount(address user) public view returns (uint256 amount) { + (amount, , , ) = oldVault.VaultMap(newVault.Token(), user); } function withdrawTokensFromV1Vault() external { From 1bb4c337a17405ad7e6023420b9d4f59a805923e Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Tue, 3 Oct 2023 23:52:19 +0300 Subject: [PATCH 32/42] refactor --- .../DelayVaultProvider/DelayVaultProvider.sol | 8 ++---- contracts/DelayVaultProvider/HoldersSum.sol | 8 ++++++ .../MigratorV1/DelayVaultMigrator.sol | 26 +++++++++++++------ contracts/LockDealNFT/LockDealNFTState.sol | 4 +++ contracts/interfaces/ILockDealNFT.sol | 2 ++ 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index 51d4bd69..e1f47bb7 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -4,18 +4,14 @@ pragma solidity ^0.8.0; import "./DelayVaultState.sol"; contract DelayVaultProvider is DelayVaultState { - constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { + constructor(address _token, ILockDealNFT _nftContract, ProviderData[] calldata _providersData) { require(address(_token) != address(0x0), "invalid address"); require(address(_nftContract) != address(0x0), "invalid address"); require(_providersData.length <= 255, "too many providers"); name = "DelayVaultProvider"; Token = _token; lockDealNFT = _nftContract; - typesCount = uint8(_providersData.length); - uint256 limit = 0; - for (uint8 i = 0; i < typesCount; i++) { - limit = _setTypeToProviderData(i, limit, _providersData[i]); - } + _finilize(); } //params[0] = amount diff --git a/contracts/DelayVaultProvider/HoldersSum.sol b/contracts/DelayVaultProvider/HoldersSum.sol index ce7934d2..f3f11c97 100644 --- a/contracts/DelayVaultProvider/HoldersSum.sol +++ b/contracts/DelayVaultProvider/HoldersSum.sol @@ -58,6 +58,14 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { emit HoldersSumChanged(user, amount); } + function _finilize(ProviderData[] calldata _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, diff --git a/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol b/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol index af041758..2ccda1db 100644 --- a/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol +++ b/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol @@ -11,15 +11,24 @@ contract DelayVaultMigrator is IDelayVaultData { address public token; address public vaultManager; ILockDealNFT public nftContract; + bool public isInitialized; + address public owner = msg.sender; // Initialize owner at declaration - constructor(IDelayVaultProvider _newVault, IDelayVaultV1 _oldVault, address _vaultManager) { - newVault = _newVault; + constructor(IDelayVaultV1 _oldVault) { oldVault = _oldVault; + } + + function finilize(IDelayVaultProvider _newVault) external { + require(owner != address(0), "DelayVaultMigrator: already initialized"); + require(msg.sender == owner, "DelayVaultMigrator: not owner"); + newVault = _newVault; token = newVault.Token(); - vaultManager = _vaultManager; - nftContract = _newVault.nftContract(); + nftContract = newVault.nftContract(); + vaultManager = nftContract.vaultManagerAddress(); + 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 { require(oldVault.Allowance(token, msg.sender), "DelayVaultMigrator: not allowed"); uint256 amount = getUserV1Amount(msg.sender); @@ -31,10 +40,7 @@ contract DelayVaultMigrator is IDelayVaultData { newVault.createNewDelayVault(msg.sender, params); } - function getUserV1Amount(address user) public view returns (uint256 amount) { - (amount, , , ) = oldVault.VaultMap(newVault.Token(), user); - } - + //this option is to get tokens from the DelayVaultV1 and deposit them to the LockDealNFT (v3) function withdrawTokensFromV1Vault() external { require(oldVault.Allowance(token, msg.sender), "DelayVaultMigrator: not allowed"); uint256 amount = getUserV1Amount(msg.sender); @@ -52,4 +58,8 @@ contract DelayVaultMigrator is IDelayVaultData { uint256[] memory params = newVault.getWithdrawPoolParams(amount, theType); providerData.provider.registerPool(newPoolId, params); } + + function getUserV1Amount(address user) public view returns (uint256 amount) { + (amount, , , ) = oldVault.VaultMap(token, user); + } } diff --git a/contracts/LockDealNFT/LockDealNFTState.sol b/contracts/LockDealNFT/LockDealNFTState.sol index d925c92f..64f1a935 100644 --- a/contracts/LockDealNFT/LockDealNFTState.sol +++ b/contracts/LockDealNFT/LockDealNFTState.sol @@ -22,6 +22,10 @@ abstract contract LockDealNFTState is ERC721Enumerable, ILockDealNFTEvents, Owna mapping(address => bool) public approvedPoolUserTransfers; mapping(address => bool) public approvedContracts; + function vaultManagerAddress() external view returns (address) { + return address(vaultManager); + } + function getData(uint256 poolId) public view returns (BasePoolInfo memory poolInfo) { if (_exists(poolId)) { IProvider provider = poolIdToProvider[poolId]; diff --git a/contracts/interfaces/ILockDealNFT.sol b/contracts/interfaces/ILockDealNFT.sol index 165e55f1..6b184ca9 100644 --- a/contracts/interfaces/ILockDealNFT.sol +++ b/contracts/interfaces/ILockDealNFT.sol @@ -27,6 +27,8 @@ interface ILockDealNFT is IERC721Enumerable { function getWithdrawableAmount(uint256 poolId) external view returns (uint256 withdrawalAmount); + function vaultManagerAddress() external view returns (address); + struct BasePoolInfo { IProvider provider; uint256 poolId; From 322e28a4d147f6a546165ef21bc19ee1768912ad Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Wed, 4 Oct 2023 00:00:11 +0300 Subject: [PATCH 33/42] refaactor --- contracts/DelayVaultProvider/DelayVaultProvider.sol | 4 ++-- contracts/DelayVaultProvider/HoldersSum.sol | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/DelayVaultProvider/DelayVaultProvider.sol index e1f47bb7..b4558dfc 100644 --- a/contracts/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/DelayVaultProvider/DelayVaultProvider.sol @@ -4,14 +4,14 @@ pragma solidity ^0.8.0; import "./DelayVaultState.sol"; contract DelayVaultProvider is DelayVaultState { - constructor(address _token, ILockDealNFT _nftContract, ProviderData[] calldata _providersData) { + constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { require(address(_token) != address(0x0), "invalid address"); require(address(_nftContract) != address(0x0), "invalid address"); require(_providersData.length <= 255, "too many providers"); name = "DelayVaultProvider"; Token = _token; lockDealNFT = _nftContract; - _finilize(); + _finilize(_providersData); } //params[0] = amount diff --git a/contracts/DelayVaultProvider/HoldersSum.sol b/contracts/DelayVaultProvider/HoldersSum.sol index f3f11c97..05e17e10 100644 --- a/contracts/DelayVaultProvider/HoldersSum.sol +++ b/contracts/DelayVaultProvider/HoldersSum.sol @@ -58,7 +58,7 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { emit HoldersSumChanged(user, amount); } - function _finilize(ProviderData[] calldata _providersData) internal { + function _finilize(ProviderData[] memory _providersData) internal { typesCount = uint8(_providersData.length); uint256 limit = 0; for (uint8 i = 0; i < typesCount; i++) { From b47bb7f833b676c20a586b042b2ee70065a948e8 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Wed, 4 Oct 2023 00:28:05 +0300 Subject: [PATCH 34/42] some renames --- .../DelayVaultProvider/DelayVaultProvider.sol | 0 .../DelayVaultProvider/DelayVaultState.sol | 5 ++--- .../DelayVaultProvider/HoldersSum.sol | 8 ++++---- .../DelayVaultProvider/LastPoolOwnerState.sol | 2 +- .../DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol | 0 .../DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol | 4 ++-- .../DelayVaultProvider/MigratorV1/IDelayVaultV1.sol | 0 .../DelayVaultProvider/MigratorV1/IMigrator.sol | 0 8 files changed, 9 insertions(+), 10 deletions(-) rename contracts/{ => AdvancedProviders}/DelayVaultProvider/DelayVaultProvider.sol (100%) rename contracts/{ => AdvancedProviders}/DelayVaultProvider/DelayVaultState.sol (96%) rename contracts/{ => AdvancedProviders}/DelayVaultProvider/HoldersSum.sol (93%) rename contracts/{ => AdvancedProviders}/DelayVaultProvider/LastPoolOwnerState.sol (92%) rename contracts/{ => AdvancedProviders}/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol (100%) rename contracts/{ => AdvancedProviders}/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol (91%) rename contracts/{ => AdvancedProviders}/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol (100%) rename contracts/{ => AdvancedProviders}/DelayVaultProvider/MigratorV1/IMigrator.sol (100%) diff --git a/contracts/DelayVaultProvider/DelayVaultProvider.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol similarity index 100% rename from contracts/DelayVaultProvider/DelayVaultProvider.sol rename to contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol diff --git a/contracts/DelayVaultProvider/DelayVaultState.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol similarity index 96% rename from contracts/DelayVaultProvider/DelayVaultState.sol rename to contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol index c6b2c485..6a0c18e6 100644 --- a/contracts/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol @@ -1,15 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../SimpleProviders/DealProvider/DealProviderState.sol"; +import "../../SimpleProviders/DealProvider/DealProviderState.sol"; +import "../../util/CalcUtils.sol"; import "./LastPoolOwnerState.sol"; import "./HoldersSum.sol"; -import "../util/CalcUtils.sol"; abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, HoldersSum { using CalcUtils for uint256; ILockDealNFT public nftContract; - address public Token; function beforeTransfer(address from, address to, uint256 poolId) external override onlyNFT { if (to == address(lockDealNFT)) diff --git a/contracts/DelayVaultProvider/HoldersSum.sol b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol similarity index 93% rename from contracts/DelayVaultProvider/HoldersSum.sol rename to contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol index 05e17e10..1d0942ac 100644 --- a/contracts/DelayVaultProvider/HoldersSum.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../SimpleProviders/Provider/ProviderModifiers.sol"; +import "../../SimpleProviders/Provider/ProviderModifiers.sol"; import "./MigratorV1/IDelayVaultProvider.sol"; import "./MigratorV1/IMigrator.sol"; @@ -10,12 +10,12 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { //the amount is the amount of the pool // params[0] = startTimeDelta (empty for DealProvider) // params[1] = endTimeDelta (only for TimedLockDealProvider) - event HoldersSumChanged(address indexed user, uint256 amount); + event VaultValueChanged(address indexed Token, address indexed Owner, uint256 Amount); 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} lentgh uint8 public typesCount; //max type + 1 - + address public Token; IMigrator public Migrator; function getTotalAmount(address user) public view returns (uint256) { @@ -55,7 +55,7 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { require(newType <= UserToType[user], "type must be the same or lower"); } UserToAmount[user] = amount; - emit HoldersSumChanged(user, amount); + emit VaultValueChanged(Token, user, amount); } function _finilize(ProviderData[] memory _providersData) internal { diff --git a/contracts/DelayVaultProvider/LastPoolOwnerState.sol b/contracts/AdvancedProviders/DelayVaultProvider/LastPoolOwnerState.sol similarity index 92% rename from contracts/DelayVaultProvider/LastPoolOwnerState.sol rename to contracts/AdvancedProviders/DelayVaultProvider/LastPoolOwnerState.sol index de65666a..a1a039ed 100644 --- a/contracts/DelayVaultProvider/LastPoolOwnerState.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/LastPoolOwnerState.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/IBeforeTransfer.sol"; +import "../../interfaces/IBeforeTransfer.sol"; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; abstract contract LastPoolOwnerState is IBeforeTransfer, IERC165 { diff --git a/contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol similarity index 100% rename from contracts/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol rename to contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol diff --git a/contracts/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol similarity index 91% rename from contracts/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol rename to contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol index 9aa32ba2..4771c0e9 100644 --- a/contracts/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../interfaces/IProvider.sol"; -import "../../interfaces/ILockDealNFT.sol"; +import "../../../interfaces/IProvider.sol"; +import "../../../interfaces/ILockDealNFT.sol"; interface IDelayVaultProvider { function createNewDelayVault(address owner, uint256[] memory params) external; diff --git a/contracts/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol similarity index 100% rename from contracts/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol rename to contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol diff --git a/contracts/DelayVaultProvider/MigratorV1/IMigrator.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IMigrator.sol similarity index 100% rename from contracts/DelayVaultProvider/MigratorV1/IMigrator.sol rename to contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IMigrator.sol From 4b2c9cd41f0f1f33bede8a0cd18ad772f2d6a02a Mon Sep 17 00:00:00 2001 From: Andrew Dmytrenko <68740472+YouStillAlive@users.noreply.github.com> Date: Wed, 4 Oct 2023 13:08:06 +0300 Subject: [PATCH 35/42] requires fix (#338) * requires fix * add owner check * use currentParamsTargetLenght for requires --- .../DelayVaultProvider/DelayVaultProvider.sol | 10 +++++++--- .../DelayVaultProvider/DelayVaultState.sol | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol index b4558dfc..8ff2e925 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol @@ -16,11 +16,14 @@ contract DelayVaultProvider is DelayVaultState { //params[0] = amount //params[1] = allowTypeChange, 0 = false, 1(or any) = true - function registerPool(uint256 poolId, uint256[] calldata params) public override onlyProvider onlyProvider { + function registerPool( + uint256 poolId, + uint256[] calldata params + ) public override onlyProvider validProviderId(poolId) { + require(params.length == currentParamsTargetLenght(), "invalid params length"); uint256 amount = params[0]; bool allowTypeChange = params[1] > 0; address owner = nftContract.ownerOf(poolId); - require(params.length == 2, "invalid params length"); _addHoldersSum(owner, amount, allowTypeChange); poolIdToAmount[poolId] = amount; } @@ -44,9 +47,10 @@ contract DelayVaultProvider is DelayVaultState { } 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]; bool allowTypeChange = params[1] > 0; - require(params.length == 2, "invalid params length"); require(!allowTypeChange || _isAllowedChanheType(owner), "only owner can upgrade type"); require(amount > 0, "amount must be bigger than 0"); PoolId = nftContract.mintAndTransfer(owner, Token, msg.sender, amount, this); diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol index 6a0c18e6..f1b72dc8 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol @@ -74,4 +74,8 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold _handleTransfer(oldOwner, newOwner, oldPoolId); } } + + function currentParamsTargetLenght() public view virtual override returns (uint256) { + return 2; + } } From da47a99570aa3aa7bdc2672aab950e591e09e420 Mon Sep 17 00:00:00 2001 From: Andrew Dmytrenko <68740472+YouStillAlive@users.noreply.github.com> Date: Wed, 4 Oct 2023 13:10:51 +0300 Subject: [PATCH 36/42] avoid duplicate vaultManager address (#340) --- .../DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol | 8 ++++---- contracts/LockDealNFT/LockDealNFTState.sol | 5 ----- contracts/interfaces/ILockDealNFT.sol | 3 ++- test/LockDealNFT.ts | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol index 2ccda1db..67cc8ccd 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol @@ -9,7 +9,7 @@ contract DelayVaultMigrator is IDelayVaultData { IDelayVaultV1 public oldVault; IDelayVaultProvider public newVault; address public token; - address public vaultManager; + IVaultManager public vaultManager; ILockDealNFT public nftContract; bool public isInitialized; address public owner = msg.sender; // Initialize owner at declaration @@ -24,7 +24,7 @@ contract DelayVaultMigrator is IDelayVaultData { newVault = _newVault; token = newVault.Token(); nftContract = newVault.nftContract(); - vaultManager = nftContract.vaultManagerAddress(); + vaultManager = nftContract.vaultManager(); owner = address(0); // Set owner to zero address } @@ -36,7 +36,7 @@ contract DelayVaultMigrator is IDelayVaultData { uint256[] memory params = new uint256[](2); params[0] = amount; params[1] = 1; //allow type change - IERC20(token).approve(vaultManager, amount); + IERC20(token).approve(address(vaultManager), amount); newVault.createNewDelayVault(msg.sender, params); } @@ -47,7 +47,7 @@ contract DelayVaultMigrator is IDelayVaultData { oldVault.redeemTokensFromVault(token, msg.sender, amount); uint8 theType = newVault.theTypeOf(newVault.getTotalAmount(msg.sender)); ProviderData memory providerData = newVault.TypeToProviderData(theType); - IERC20(token).approve(vaultManager, amount); + IERC20(token).approve(address(vaultManager), amount); uint256 newPoolId = nftContract.mintAndTransfer( msg.sender, token, diff --git a/contracts/LockDealNFT/LockDealNFTState.sol b/contracts/LockDealNFT/LockDealNFTState.sol index 64f1a935..b4f8f8f7 100644 --- a/contracts/LockDealNFT/LockDealNFTState.sol +++ b/contracts/LockDealNFT/LockDealNFTState.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import "@poolzfinance/poolz-helper-v2/contracts/interfaces/IVaultManager.sol"; import "@poolzfinance/poolz-helper-v2/contracts/Array.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./ILockDealNFTEvents.sol"; @@ -22,10 +21,6 @@ abstract contract LockDealNFTState is ERC721Enumerable, ILockDealNFTEvents, Owna mapping(address => bool) public approvedPoolUserTransfers; mapping(address => bool) public approvedContracts; - function vaultManagerAddress() external view returns (address) { - return address(vaultManager); - } - function getData(uint256 poolId) public view returns (BasePoolInfo memory poolInfo) { if (_exists(poolId)) { IProvider provider = poolIdToProvider[poolId]; diff --git a/contracts/interfaces/ILockDealNFT.sol b/contracts/interfaces/ILockDealNFT.sol index 6b184ca9..c31ad6d5 100644 --- a/contracts/interfaces/ILockDealNFT.sol +++ b/contracts/interfaces/ILockDealNFT.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import "./IProvider.sol"; +import "@poolzfinance/poolz-helper-v2/contracts/interfaces/IVaultManager.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; interface ILockDealNFT is IERC721Enumerable { @@ -27,7 +28,7 @@ interface ILockDealNFT is IERC721Enumerable { function getWithdrawableAmount(uint256 poolId) external view returns (uint256 withdrawalAmount); - function vaultManagerAddress() external view returns (address); + function vaultManager() external view returns (IVaultManager); struct BasePoolInfo { IProvider provider; diff --git a/test/LockDealNFT.ts b/test/LockDealNFT.ts index 4ac33d39..0c921321 100644 --- a/test/LockDealNFT.ts +++ b/test/LockDealNFT.ts @@ -277,7 +277,7 @@ describe('LockDealNFT', function () { }); it('check if the contract supports ILockDealNFT interface', async () => { - expect(await lockDealNFT.supportsInterface('0xca3ff009')).to.equal(true); + expect(await lockDealNFT.supportsInterface('0x40752f2d')).to.equal(true); }); it('shuld return royalty', async () => { From 68725e443d790923017b2a8d6e0ed76bc9fcab09 Mon Sep 17 00:00:00 2001 From: Andrew Dmytrenko <68740472+YouStillAlive@users.noreply.github.com> Date: Wed, 4 Oct 2023 13:34:59 +0300 Subject: [PATCH 37/42] use camelCase (#339) --- .../DelayVaultProvider/DelayVaultProvider.sol | 16 ++++----- .../DelayVaultProvider/DelayVaultState.sol | 14 ++++---- .../DelayVaultProvider/HoldersSum.sol | 35 ++++++++++--------- .../DelayVaultProvider/LastPoolOwnerState.sol | 2 +- 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol index 8ff2e925..59637243 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol @@ -9,7 +9,7 @@ contract DelayVaultProvider is DelayVaultState { require(address(_nftContract) != address(0x0), "invalid address"); require(_providersData.length <= 255, "too many providers"); name = "DelayVaultProvider"; - Token = _token; + token = _token; lockDealNFT = _nftContract; _finilize(_providersData); } @@ -38,26 +38,26 @@ contract DelayVaultProvider is DelayVaultState { } function upgradeType(uint8 newType) public { - uint8 oldType = UserToType[msg.sender]; + 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; + userToType[msg.sender] = newType; } - function createNewDelayVault(address owner, uint256[] calldata params) external returns (uint256 PoolId) { + 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]; bool allowTypeChange = params[1] > 0; - require(!allowTypeChange || _isAllowedChanheType(owner), "only owner can upgrade type"); + require(!allowTypeChange || _isAllowedChangeType(owner), "only owner can upgrade type"); require(amount > 0, "amount must be bigger than 0"); - PoolId = nftContract.mintAndTransfer(owner, Token, msg.sender, amount, this); - registerPool(PoolId, params); + poolId = nftContract.mintAndTransfer(owner, token, msg.sender, amount, this); + registerPool(poolId, params); } - function _isAllowedChanheType(address owner) internal view returns (bool) { + function _isAllowedChangeType(address owner) internal view returns (bool) { return owner == msg.sender || lockDealNFT.approvedContracts(msg.sender); } } diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol index f1b72dc8..f2488ddf 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol @@ -13,7 +13,7 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold 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 + lastPoolOwner[poolId] = from; //this is the only way to know the owner of the pool else if (from != address(0) && !nftContract.approvedContracts(from)) { _handleTransfer(from, to, poolId); } @@ -26,7 +26,7 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold } function getWithdrawPoolParams(uint256 amount, uint8 theType) public view returns (uint256[] memory params) { - uint256[] memory settings = TypeToProviderData[theType].params; + uint256[] memory settings = typeToProviderData[theType].params; params = _getWithdrawPoolParams(amount, settings); } @@ -44,20 +44,20 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold //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]; + 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); if (getTotalAmount(owner) == 0) { - UserToType[owner] = 0; //reset the type + userToType[owner] = 0; //reset the type } } function _createLockNFT(address owner, uint256 amount, uint8 theType, uint tokenId) internal { - ProviderData memory providerData = TypeToProviderData[theType]; + ProviderData memory providerData = typeToProviderData[theType]; uint256 newPoolId = nftContract.mintForProvider(owner, providerData.provider); nftContract.copyVaultId(tokenId, newPoolId); uint256[] memory params = getWithdrawPoolParams(amount, theType); @@ -65,7 +65,7 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold } function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override onlyNFT { - address oldOwner = LastPoolOwner[oldPoolId]; + address oldOwner = lastPoolOwner[oldPoolId]; address newOwner = nftContract.ownerOf(newPoolId); uint256 amount = poolIdToAmount[oldPoolId].calcAmount(ratio); poolIdToAmount[oldPoolId] -= amount; diff --git a/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol index 1d0942ac..9281e762 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol @@ -10,21 +10,22 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { //the amount is the amount of the pool // params[0] = startTimeDelta (empty for DealProvider) // params[1] = endTimeDelta (only for TimedLockDealProvider) - event VaultValueChanged(address indexed Token, address indexed Owner, uint256 Amount); - 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} lentgh + 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; + 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); + 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) { + if (amount <= typeToProviderData[i].limit) { theType = i; break; } @@ -32,12 +33,12 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { } function _addHoldersSum(address user, uint256 amount, bool allowTypeUpgrade) internal { - uint256 newAmount = UserToAmount[user] + amount; + uint256 newAmount = userToAmount[user] + amount; _setHoldersSum(user, newAmount, allowTypeUpgrade); } function _subHoldersSum(address user, uint256 amount) internal { - uint256 oldAmount = UserToAmount[user]; + uint256 oldAmount = userToAmount[user]; require(oldAmount >= amount, "amount exceeded"); uint256 newAmount = oldAmount - amount; _setHoldersSum(user, newAmount, false); @@ -47,15 +48,15 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { uint8 newType = theTypeOf(getTotalAmount(user) + amount); if (allowTypeUpgrade) { // Upgrade the user type if the newType is greater - if (newType > UserToType[user]) { - UserToType[user] = newType; + if (newType > userToType[user]) { + userToType[user] = newType; } } else { // Ensure the type doesn't change if upgrades are not allowed - require(newType <= UserToType[user], "type must be the same or lower"); + require(newType <= userToType[user], "type must be the same or lower"); } - UserToAmount[user] = amount; - emit VaultValueChanged(Token, user, amount); + userToAmount[user] = amount; + emit VaultValueChanged(token, user, amount); } function _finilize(ProviderData[] memory _providersData) internal { @@ -75,9 +76,9 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { 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; + 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 + typeToProviderData[theType].limit = type(uint256).max; //the last one is the max, token supply is out of the scope } } } diff --git a/contracts/AdvancedProviders/DelayVaultProvider/LastPoolOwnerState.sol b/contracts/AdvancedProviders/DelayVaultProvider/LastPoolOwnerState.sol index a1a039ed..50c39098 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/LastPoolOwnerState.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/LastPoolOwnerState.sol @@ -5,7 +5,7 @@ import "../../interfaces/IBeforeTransfer.sol"; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; abstract contract LastPoolOwnerState is IBeforeTransfer, IERC165 { - mapping(uint256 => address) internal LastPoolOwner; + mapping(uint256 => address) internal lastPoolOwner; function beforeTransfer(address from, address to, uint256 poolId) external virtual override; From 86e2b0c174c884f353ce3157084859310d842a91 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Thu, 5 Oct 2023 15:51:57 +0300 Subject: [PATCH 38/42] add ILockDealV2 --- .../MigratorV1/DelayVaultMigrator.sol | 27 ++++++++++++++++++- .../MigratorV1/ILockDealV2.sol | 13 +++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/ILockDealV2.sol diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol index 67cc8ccd..6489e3c6 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol @@ -4,8 +4,9 @@ pragma solidity ^0.8.0; import "./IDelayVaultProvider.sol"; import "./IDelayVaultV1.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./ILockDealV2.sol"; -contract DelayVaultMigrator is IDelayVaultData { +contract DelayVaultMigrator is IDelayVaultData, ILockDealV2 { IDelayVaultV1 public oldVault; IDelayVaultProvider public newVault; address public token; @@ -62,4 +63,28 @@ contract DelayVaultMigrator is IDelayVaultData { function getUserV1Amount(address user) public view returns (uint256 amount) { (amount, , , ) = oldVault.VaultMap(token, user); } + + function CreateNewPool( + address _Token, //token to lock address + uint256 _StartTime, //Until what time the pool will start + uint256 _CliffTime, //Before CliffTime can't withdraw tokens + uint256 _FinishTime, //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 { + require(msg.sender == address(oldVault), "DelayVaultMigrator: not DelayVaultV1"); + uint8 theType = newVault.theTypeOf(newVault.getTotalAmount(msg.sender)); + ProviderData memory providerData = newVault.TypeToProviderData(theType); + IERC20(token).transferFrom(msg.sender, address(this), _StartAmount); + IERC20(token).approve(address(vaultManager), _StartAmount); + uint256 newPoolId = nftContract.mintAndTransfer( + _Owner, + _Token, + address(this), + _StartAmount, + providerData.provider + ); + uint256[] memory params = newVault.getWithdrawPoolParams(_StartAmount, theType); + providerData.provider.registerPool(newPoolId, params); + } } diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/ILockDealV2.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/ILockDealV2.sol new file mode 100644 index 00000000..44a44f16 --- /dev/null +++ b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/ILockDealV2.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface ILockDealV2 { + function CreateNewPool( + address _Token, //token to lock address + uint256 _StartTime, //Until what time the pool will start + uint256 _CliffTime, //Before CliffTime can't withdraw tokens + uint256 _FinishTime, //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; +} From e4c396cc0648a31bef9e470219badaf1399249b9 Mon Sep 17 00:00:00 2001 From: Andrew Dmytrenko <68740472+YouStillAlive@users.noreply.github.com> Date: Thu, 5 Oct 2023 16:00:28 +0300 Subject: [PATCH 39/42] added tests (#342) * added tests * fix DelayVaultProvider params length * add more tests * added more tests * tests refactor * reduce duplication --------- Co-authored-by: Stan Goldin <48094744+Lomet@users.noreply.github.com> --- .../DelayVaultProvider/DelayVaultProvider.sol | 24 +- .../DelayVaultProvider/DelayVaultState.sol | 13 +- .../DelayVaultProvider/HoldersSum.sol | 7 +- test/DelayVaultProvider.ts | 268 ++++++++++++++++++ 4 files changed, 288 insertions(+), 24 deletions(-) create mode 100644 test/DelayVaultProvider.ts diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol index 59637243..0ec0902a 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol @@ -14,22 +14,24 @@ contract DelayVaultProvider is DelayVaultState { _finilize(_providersData); } - //params[0] = amount - //params[1] = allowTypeChange, 0 = false, 1(or any) = true + ///@param params[0] = amount function registerPool( uint256 poolId, uint256[] calldata params ) public override onlyProvider validProviderId(poolId) { require(params.length == currentParamsTargetLenght(), "invalid params length"); + _registerPool(poolId, params); + } + + function _registerPool(uint256 poolId, uint256[] calldata params) internal { uint256 amount = params[0]; - bool allowTypeChange = params[1] > 0; - address owner = nftContract.ownerOf(poolId); - _addHoldersSum(owner, amount, allowTypeChange); + address owner = lockDealNFT.ownerOf(poolId); + _addHoldersSum(owner, amount, owner == msg.sender); poolIdToAmount[poolId] = amount; } function getParams(uint256 poolId) external view override returns (uint256[] memory params) { - params = new uint256[](2); + params = new uint256[](1); params[0] = poolIdToAmount[poolId]; } @@ -50,14 +52,8 @@ contract DelayVaultProvider is DelayVaultState { require(params.length == currentParamsTargetLenght(), "invalid params length"); require(owner != address(0), "invalid owner address"); uint256 amount = params[0]; - bool allowTypeChange = params[1] > 0; - require(!allowTypeChange || _isAllowedChangeType(owner), "only owner can upgrade type"); require(amount > 0, "amount must be bigger than 0"); - poolId = nftContract.mintAndTransfer(owner, token, msg.sender, amount, this); - registerPool(poolId, params); - } - - function _isAllowedChangeType(address owner) internal view returns (bool) { - return owner == msg.sender || lockDealNFT.approvedContracts(msg.sender); + poolId = lockDealNFT.mintAndTransfer(owner, token, msg.sender, amount, this); + _registerPool(poolId, params); } } diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol index f2488ddf..907545ee 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol @@ -8,13 +8,12 @@ import "./HoldersSum.sol"; abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, HoldersSum { using CalcUtils for uint256; - ILockDealNFT public nftContract; 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) && !nftContract.approvedContracts(from)) { + else if (from != address(0) && !lockDealNFT.approvedContracts(from)) { _handleTransfer(from, to, poolId); } } @@ -58,15 +57,15 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold function _createLockNFT(address owner, uint256 amount, uint8 theType, uint tokenId) internal { ProviderData memory providerData = typeToProviderData[theType]; - uint256 newPoolId = nftContract.mintForProvider(owner, providerData.provider); - nftContract.copyVaultId(tokenId, newPoolId); + uint256 newPoolId = lockDealNFT.mintForProvider(owner, providerData.provider); + lockDealNFT.copyVaultId(tokenId, newPoolId); 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 = nftContract.ownerOf(newPoolId); + address newOwner = lockDealNFT.ownerOf(newPoolId); uint256 amount = poolIdToAmount[oldPoolId].calcAmount(ratio); poolIdToAmount[oldPoolId] -= amount; poolIdToAmount[newPoolId] = amount; @@ -75,7 +74,7 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold } } - function currentParamsTargetLenght() public view virtual override returns (uint256) { - return 2; + function getTypeToProviderData(uint8 theType) public view virtual returns (ProviderData memory providerData) { + providerData = typeToProviderData[theType]; } } diff --git a/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol index 9281e762..f73fb076 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol @@ -20,11 +20,12 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { event VaultValueChanged(address indexed token, address indexed owner, uint256 amount); function getTotalAmount(address user) public view returns (uint256) { - return userToAmount[user] + migrator.getUserV1Amount(user); + // TODO: return userToAmount[user] + migrator.getUserV1Amount(user); + return userToAmount[user]; } function theTypeOf(uint256 amount) public view returns (uint8 theType) { - for (uint8 i = 0; i < typesCount; i++) { + for (uint8 i = 0; i < typesCount; ++i) { if (amount <= typeToProviderData[i].limit) { theType = i; break; @@ -62,7 +63,7 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { function _finilize(ProviderData[] memory _providersData) internal { typesCount = uint8(_providersData.length); uint256 limit = 0; - for (uint8 i = 0; i < typesCount; i++) { + for (uint8 i = 0; i < typesCount; ++i) { limit = _setTypeToProviderData(i, limit, _providersData[i]); } } diff --git a/test/DelayVaultProvider.ts b/test/DelayVaultProvider.ts new file mode 100644 index 00000000..4825b8cb --- /dev/null +++ b/test/DelayVaultProvider.ts @@ -0,0 +1,268 @@ +import { LockDealProvider } from '../typechain-types'; +import { TimedDealProvider } from '../typechain-types'; +import { LockDealNFT } from '../typechain-types'; +import { DealProvider } from '../typechain-types'; +import { MockProvider } from '../typechain-types'; +import { MockVaultManager } from '../typechain-types'; +import { DelayVaultProvider } from '../typechain-types'; +import { IDelayVaultData } from '../typechain-types/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider'; +import { deployed, token, MAX_RATIO, _createUsers } from './helper'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { BigNumber } from 'ethers'; +import { ethers } from 'hardhat'; + +describe('DelayVault Provider', function () { + let timedDealProvider: TimedDealProvider; + let lockProvider: LockDealProvider; + let dealProvider: DealProvider; + let lockDealNFT: LockDealNFT; + let mockProvider: MockProvider; + let mockVaultManager: MockVaultManager; + let delayVaultProvider: DelayVaultProvider; + let poolId: BigNumber; + let vaultId: BigNumber; + let receiver: SignerWithAddress; + let user1: SignerWithAddress; + let user2: SignerWithAddress; + let user3: SignerWithAddress; + let user4: SignerWithAddress; + let newOwner: SignerWithAddress; + let startTime: number, finishTime: number; + let providerData: IDelayVaultData.ProviderDataStruct[]; + const tier1 = ethers.BigNumber.from(250); + const tier2 = ethers.BigNumber.from(3500); + const tier3 = ethers.BigNumber.from(20000); + const ratio = MAX_RATIO.div(2); // half of the amount + const gasLimit = 130_000_000; + + before(async () => { + [receiver, newOwner, user1, user2, user3, user4] = await ethers.getSigners(); + mockVaultManager = await deployed('MockVaultManager'); + lockDealNFT = await deployed('LockDealNFT', mockVaultManager.address, ''); + dealProvider = await deployed('DealProvider', lockDealNFT.address); + lockProvider = await deployed('LockDealProvider', lockDealNFT.address, dealProvider.address); + timedDealProvider = await deployed('TimedDealProvider', lockDealNFT.address, lockProvider.address); + mockProvider = await deployed('MockProvider', lockDealNFT.address, timedDealProvider.address); + const DelayVaultProvider = await ethers.getContractFactory('DelayVaultProvider'); + const ONE_DAY = 86400; + const week = ONE_DAY * 7; + startTime = week; + finishTime = week * 4; + providerData = [ + { provider: dealProvider.address, params: [], limit: tier1 }, + { provider: lockProvider.address, params: [startTime], limit: tier2 }, + { provider: timedDealProvider.address, params: [startTime, finishTime], limit: tier3 }, + ]; + delayVaultProvider = await DelayVaultProvider.deploy(token, lockDealNFT.address, providerData, { + gasLimit: gasLimit, + }); + await lockDealNFT.setApprovedContract(dealProvider.address, true); + await lockDealNFT.setApprovedContract(lockProvider.address, true); + await lockDealNFT.setApprovedContract(timedDealProvider.address, true); + await lockDealNFT.setApprovedContract(mockProvider.address, true); + await lockDealNFT.setApprovedContract(delayVaultProvider.address, true); + }); + + beforeEach(async () => { + poolId = await lockDealNFT.totalSupply(); + }); + + it('should check provider name', async () => { + expect(await delayVaultProvider.name()).to.equal('DelayVaultProvider'); + }); + + it("should check provider's token", async () => { + expect(await delayVaultProvider.token()).to.equal(token); + }); + + it("should check provider's lockDealNFT", async () => { + expect(await delayVaultProvider.lockDealNFT()).to.equal(lockDealNFT.address); + }); + + it('should check _finilize constructor data', async () => { + for (let i = 0; i < providerData.length; i++) { + const data = await delayVaultProvider.getTypeToProviderData(i); + expect(data.provider).to.equal(providerData[i].provider); + expect(data.params).to.deep.equal(providerData[i].params); + i != providerData.length - 1 + ? expect(data.limit).to.equal(providerData[i].limit) + : expect(data.limit).to.equal(ethers.constants.MaxUint256); + } + }); + + it('should return new provider poolId', async () => { + const params = [tier1]; + const lastPoolId = (await lockDealNFT.totalSupply()).sub(1); + await delayVaultProvider.createNewDelayVault(receiver.address, params); + expect((await lockDealNFT.totalSupply()).sub(1)).to.equal(lastPoolId.add(1)); + }); + + it('should check vault data with tier 1', async () => { + const params = [tier1]; + await delayVaultProvider.connect(user2).createNewDelayVault(user1.address, params); + const newAmount = await delayVaultProvider.userToAmount(user1.address); + const type = await delayVaultProvider.userToType(user1.address); + expect(newAmount).to.equal(tier1); + // 0 - tier1 + // 1 - tier2 + // 2 - tier3 + expect(type).to.equal(0); + }); + + it('should check delayVault data with tier 2', async () => { + const params = [tier2]; + await delayVaultProvider.connect(user2).createNewDelayVault(user2.address, params); + const newAmount = await delayVaultProvider.userToAmount(user2.address); + const type = await delayVaultProvider.userToType(user2.address); + expect(newAmount).to.equal(tier2); + expect(type).to.equal(1); + }); + + it('should check delayVault data with tier 3', async () => { + const params = [tier3]; + await delayVaultProvider.connect(newOwner).createNewDelayVault(newOwner.address, params); + const newAmount = await delayVaultProvider.userToAmount(newOwner.address); + const type = await delayVaultProvider.userToType(newOwner.address); + expect(newAmount).to.equal(tier3); + expect(type).to.equal(2); + }); + + describe('delayVault withdraw', async () => { + it('should withdraw from delayVault with tier 1', async () => { + const params = [tier1]; + await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); + await lockDealNFT + .connect(user3) + ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); + const newAmount = await delayVaultProvider.userToAmount(user3.address); + const type = await delayVaultProvider.userToType(user3.address); + expect(newAmount).to.equal(0); + expect(type).to.equal(0); + }); + + it('should withdraw from delayVault with tier 2', async () => { + const params = [tier2]; + await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); + await lockDealNFT + .connect(user3) + ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); + const newAmount = await delayVaultProvider.userToAmount(user3.address); + const type = await delayVaultProvider.userToType(user3.address); + expect(newAmount).to.equal(0); + expect(type).to.equal(0); + }); + + it('should withdraw from delayVault with tier 3', async () => { + const params = [tier3]; + const poolId = await lockDealNFT.totalSupply(); + await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); + await lockDealNFT + .connect(user3) + ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); + const newAmount = await delayVaultProvider.userToAmount(user3.address); + const type = await delayVaultProvider.userToType(user3.address); + expect(newAmount).to.equal(0); + expect(type).to.equal(0); + }); + + it('should create new deal provider nft after withdraw with first tier', async () => { + const params = [tier1]; + await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); + await lockDealNFT + .connect(user3) + ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); + vaultId = await mockVaultManager.Id(); + const simpleNFTdata = await lockDealNFT.getData(poolId.add(1)); + expect(simpleNFTdata.provider).to.equal(dealProvider.address); + expect(simpleNFTdata.owner).to.equal(user3.address); + expect(simpleNFTdata.token).to.equal(token); + expect(simpleNFTdata.vaultId).to.equal(vaultId); + expect(simpleNFTdata.params).to.deep.equal([tier1]); + }); + + it('should create new lock provider nft after withdraw with second tier', async () => { + const params = [tier2]; + await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); + await lockDealNFT + .connect(user3) + ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); + const time = await ethers.provider.getBlock('latest').then(block => block.timestamp); + vaultId = await mockVaultManager.Id(); + const simpleNFTdata = await lockDealNFT.getData(poolId.add(1)); + expect(simpleNFTdata.provider).to.equal(lockProvider.address); + expect(simpleNFTdata.owner).to.equal(user3.address); + expect(simpleNFTdata.token).to.equal(token); + expect(simpleNFTdata.vaultId).to.equal(vaultId); + expect(simpleNFTdata.params).to.deep.equal([tier2, time + startTime]); + }); + + it('should create new timed provider nft after withdraw with third tier', async () => { + const params = [tier3]; + await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); + await lockDealNFT + .connect(user3) + ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); + const time = await ethers.provider.getBlock('latest').then(block => block.timestamp); + vaultId = await mockVaultManager.Id(); + const simpleNFTdata = await lockDealNFT.getData(poolId.add(1)); + expect(simpleNFTdata.provider).to.equal(timedDealProvider.address); + expect(simpleNFTdata.owner).to.equal(user3.address); + expect(simpleNFTdata.token).to.equal(token); + expect(simpleNFTdata.vaultId).to.equal(vaultId); + expect(simpleNFTdata.params).to.deep.equal([tier3, time + startTime, time + finishTime, tier3]); + }); + }); + + describe('delayVault split', async () => { + it('should return half amount in old pool after split', async () => { + const params = [tier1]; + const packedData = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [ratio, user4.address]); + await delayVaultProvider.connect(user4).createNewDelayVault(user4.address, params); + await lockDealNFT.connect(user4)['safeTransferFrom(address,address,uint256,bytes)'](user4.address, lockDealNFT.address, poolId, packedData); + const data = await lockDealNFT.getData(poolId); + expect(data.owner).to.equal(user4.address); + expect(data.provider).to.equal(delayVaultProvider.address); + expect(data.params).to.deep.equal([tier1.div(2)]); + }); + + it('should create new delay nft after split with first tier', async () => { + const params = [tier1]; + const packedData = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [ratio, user3.address]); + await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); + await lockDealNFT + .connect(user3) + ['safeTransferFrom(address,address,uint256,bytes)'](user3.address, lockDealNFT.address, poolId, packedData); + const data = await lockDealNFT.getData(poolId.add(1)); + expect(data.owner).to.equal(user3.address); + expect(data.provider).to.equal(delayVaultProvider.address); + expect(data.params).to.deep.equal([tier1.div(2)]); + }); + + it('should create new delay nft after split with second tier', async () => { + const params = [tier2]; + const packedData = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [ratio, user3.address]); + await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); + await lockDealNFT + .connect(user3) + ['safeTransferFrom(address,address,uint256,bytes)'](user3.address, lockDealNFT.address, poolId, packedData); + const data = await lockDealNFT.getData(poolId.add(1)); + expect(data.owner).to.equal(user3.address); + expect(data.provider).to.equal(delayVaultProvider.address); + expect(data.params).to.deep.equal([tier2.div(2)]); + }); + + it('should create new delay nft after split with third tier', async () => { + const params = [tier3]; + await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); + const packedData = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [ratio, user3.address]); + await lockDealNFT + .connect(user3) + ['safeTransferFrom(address,address,uint256,bytes)'](user3.address, lockDealNFT.address, poolId, packedData); + const data = await lockDealNFT.getData(poolId.add(1)); + expect(data.owner).to.equal(user3.address); + expect(data.provider).to.equal(delayVaultProvider.address); + expect(data.params).to.deep.equal([tier3.div(2)]); + }); + }); +}); From c0604ac6413b8a003b418991dd3582b0bb02b354 Mon Sep 17 00:00:00 2001 From: Andrew Dmytrenko <68740472+YouStillAlive@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:44:54 +0300 Subject: [PATCH 40/42] `DelayProvider` tests (#345) * experiments with typescript * tests refactor * fix amount bug * name fix * _subHoldersSum fix * revert _subHoldersSum fix * fix split bug * tests progress * update DelayVaultProvider * name fix * fix type check --- .../DelayVaultProvider/DelayVaultProvider.sol | 2 + .../DelayVaultProvider/DelayVaultState.sol | 12 +- .../DelayVaultProvider/HoldersSum.sol | 29 +- .../MigratorV1/DelayVaultMigrator.sol | 8 +- contracts/mock/MockDelayMigrator.sol | 10 + test/DelayVaultProvider.ts | 268 ------------------ test/DelayVaultProvider/DelayVaultProvider.ts | 88 ++++++ test/DelayVaultProvider/DelayVaultSplit.ts | 99 +++++++ test/DelayVaultProvider/DelayVaultTypeTier.ts | 61 ++++ test/DelayVaultProvider/DelayVaultView.ts | 33 +++ test/DelayVaultProvider/DelayVaultWithdraw.ts | 99 +++++++ test/DelayVaultProvider/setupTests.ts | 68 +++++ 12 files changed, 491 insertions(+), 286 deletions(-) create mode 100644 contracts/mock/MockDelayMigrator.sol delete mode 100644 test/DelayVaultProvider.ts create mode 100644 test/DelayVaultProvider/DelayVaultProvider.ts create mode 100644 test/DelayVaultProvider/DelayVaultSplit.ts create mode 100644 test/DelayVaultProvider/DelayVaultTypeTier.ts create mode 100644 test/DelayVaultProvider/DelayVaultView.ts create mode 100644 test/DelayVaultProvider/DelayVaultWithdraw.ts create mode 100644 test/DelayVaultProvider/setupTests.ts diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol index 0ec0902a..05bbc1b5 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import "./DelayVaultState.sol"; +import "../../mock/MockDelayMigrator.sol"; contract DelayVaultProvider is DelayVaultState { constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { @@ -11,6 +12,7 @@ contract DelayVaultProvider is DelayVaultState { name = "DelayVaultProvider"; token = _token; lockDealNFT = _nftContract; + migrator = new MockDelayMigrator(); _finilize(_providersData); } diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol index 907545ee..55b52c1c 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol @@ -50,9 +50,7 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold isFinal = true; withdrawnAmount = poolIdToAmount[tokenId] = 0; _subHoldersSum(owner, amount); - if (getTotalAmount(owner) == 0) { - userToType[owner] = 0; //reset the type - } + _resetTypeIfEmpty(owner); } function _createLockNFT(address owner, uint256 amount, uint8 theType, uint tokenId) internal { @@ -70,7 +68,13 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold poolIdToAmount[oldPoolId] -= amount; poolIdToAmount[newPoolId] = amount; if (newOwner != oldOwner) { - _handleTransfer(oldOwner, newOwner, oldPoolId); + _handleTransfer(oldOwner, newOwner, newPoolId); + } + } + + function _resetTypeIfEmpty(address user) internal { + if (getTotalAmount(user) == 0) { + userToType[user] = 0; //reset the type } } diff --git a/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol index f73fb076..d2040f44 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol @@ -20,8 +20,7 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { event VaultValueChanged(address indexed token, address indexed owner, uint256 amount); function getTotalAmount(address user) public view returns (uint256) { - // TODO: return userToAmount[user] + migrator.getUserV1Amount(user); - return userToAmount[user]; + return userToAmount[user] + migrator.getUserV1Amount(user); } function theTypeOf(uint256 amount) public view returns (uint8 theType) { @@ -45,19 +44,29 @@ abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { _setHoldersSum(user, newAmount, false); } - function _setHoldersSum(address user, uint256 amount, bool allowTypeUpgrade) internal { - uint8 newType = theTypeOf(getTotalAmount(user) + amount); + function _setHoldersSum(address user, uint256 newAmount, bool allowTypeUpgrade) internal { + uint8 newType = theTypeOf(migrator.getUserV1Amount(user) + newAmount); if (allowTypeUpgrade) { - // Upgrade the user type if the newType is greater - if (newType > userToType[user]) { - userToType[user] = newType; - } + _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] = amount; - emit VaultValueChanged(token, user, amount); + 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; + } } function _finilize(ProviderData[] memory _providersData) internal { diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol index 6489e3c6..6c25016b 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol @@ -66,14 +66,14 @@ contract DelayVaultMigrator is IDelayVaultData, ILockDealV2 { function CreateNewPool( address _Token, //token to lock address - uint256 _StartTime, //Until what time the pool will start - uint256 _CliffTime, //Before CliffTime can't withdraw tokens - uint256 _FinishTime, //Until what time the pool will end + 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 { require(msg.sender == address(oldVault), "DelayVaultMigrator: not DelayVaultV1"); - uint8 theType = newVault.theTypeOf(newVault.getTotalAmount(msg.sender)); + uint8 theType = newVault.theTypeOf(newVault.getTotalAmount(_Owner)); ProviderData memory providerData = newVault.TypeToProviderData(theType); IERC20(token).transferFrom(msg.sender, address(this), _StartAmount); IERC20(token).approve(address(vaultManager), _StartAmount); diff --git a/contracts/mock/MockDelayMigrator.sol b/contracts/mock/MockDelayMigrator.sol new file mode 100644 index 00000000..c0eec3ca --- /dev/null +++ b/contracts/mock/MockDelayMigrator.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../AdvancedProviders/DelayVaultProvider/MigratorV1/IMigrator.sol"; + +contract MockDelayMigrator is IMigrator { + function getUserV1Amount(address) external pure returns (uint256 amount) { + amount = 0; + } +} diff --git a/test/DelayVaultProvider.ts b/test/DelayVaultProvider.ts deleted file mode 100644 index 4825b8cb..00000000 --- a/test/DelayVaultProvider.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { LockDealProvider } from '../typechain-types'; -import { TimedDealProvider } from '../typechain-types'; -import { LockDealNFT } from '../typechain-types'; -import { DealProvider } from '../typechain-types'; -import { MockProvider } from '../typechain-types'; -import { MockVaultManager } from '../typechain-types'; -import { DelayVaultProvider } from '../typechain-types'; -import { IDelayVaultData } from '../typechain-types/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider'; -import { deployed, token, MAX_RATIO, _createUsers } from './helper'; -import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { BigNumber } from 'ethers'; -import { ethers } from 'hardhat'; - -describe('DelayVault Provider', function () { - let timedDealProvider: TimedDealProvider; - let lockProvider: LockDealProvider; - let dealProvider: DealProvider; - let lockDealNFT: LockDealNFT; - let mockProvider: MockProvider; - let mockVaultManager: MockVaultManager; - let delayVaultProvider: DelayVaultProvider; - let poolId: BigNumber; - let vaultId: BigNumber; - let receiver: SignerWithAddress; - let user1: SignerWithAddress; - let user2: SignerWithAddress; - let user3: SignerWithAddress; - let user4: SignerWithAddress; - let newOwner: SignerWithAddress; - let startTime: number, finishTime: number; - let providerData: IDelayVaultData.ProviderDataStruct[]; - const tier1 = ethers.BigNumber.from(250); - const tier2 = ethers.BigNumber.from(3500); - const tier3 = ethers.BigNumber.from(20000); - const ratio = MAX_RATIO.div(2); // half of the amount - const gasLimit = 130_000_000; - - before(async () => { - [receiver, newOwner, user1, user2, user3, user4] = await ethers.getSigners(); - mockVaultManager = await deployed('MockVaultManager'); - lockDealNFT = await deployed('LockDealNFT', mockVaultManager.address, ''); - dealProvider = await deployed('DealProvider', lockDealNFT.address); - lockProvider = await deployed('LockDealProvider', lockDealNFT.address, dealProvider.address); - timedDealProvider = await deployed('TimedDealProvider', lockDealNFT.address, lockProvider.address); - mockProvider = await deployed('MockProvider', lockDealNFT.address, timedDealProvider.address); - const DelayVaultProvider = await ethers.getContractFactory('DelayVaultProvider'); - const ONE_DAY = 86400; - const week = ONE_DAY * 7; - startTime = week; - finishTime = week * 4; - providerData = [ - { provider: dealProvider.address, params: [], limit: tier1 }, - { provider: lockProvider.address, params: [startTime], limit: tier2 }, - { provider: timedDealProvider.address, params: [startTime, finishTime], limit: tier3 }, - ]; - delayVaultProvider = await DelayVaultProvider.deploy(token, lockDealNFT.address, providerData, { - gasLimit: gasLimit, - }); - await lockDealNFT.setApprovedContract(dealProvider.address, true); - await lockDealNFT.setApprovedContract(lockProvider.address, true); - await lockDealNFT.setApprovedContract(timedDealProvider.address, true); - await lockDealNFT.setApprovedContract(mockProvider.address, true); - await lockDealNFT.setApprovedContract(delayVaultProvider.address, true); - }); - - beforeEach(async () => { - poolId = await lockDealNFT.totalSupply(); - }); - - it('should check provider name', async () => { - expect(await delayVaultProvider.name()).to.equal('DelayVaultProvider'); - }); - - it("should check provider's token", async () => { - expect(await delayVaultProvider.token()).to.equal(token); - }); - - it("should check provider's lockDealNFT", async () => { - expect(await delayVaultProvider.lockDealNFT()).to.equal(lockDealNFT.address); - }); - - it('should check _finilize constructor data', async () => { - for (let i = 0; i < providerData.length; i++) { - const data = await delayVaultProvider.getTypeToProviderData(i); - expect(data.provider).to.equal(providerData[i].provider); - expect(data.params).to.deep.equal(providerData[i].params); - i != providerData.length - 1 - ? expect(data.limit).to.equal(providerData[i].limit) - : expect(data.limit).to.equal(ethers.constants.MaxUint256); - } - }); - - it('should return new provider poolId', async () => { - const params = [tier1]; - const lastPoolId = (await lockDealNFT.totalSupply()).sub(1); - await delayVaultProvider.createNewDelayVault(receiver.address, params); - expect((await lockDealNFT.totalSupply()).sub(1)).to.equal(lastPoolId.add(1)); - }); - - it('should check vault data with tier 1', async () => { - const params = [tier1]; - await delayVaultProvider.connect(user2).createNewDelayVault(user1.address, params); - const newAmount = await delayVaultProvider.userToAmount(user1.address); - const type = await delayVaultProvider.userToType(user1.address); - expect(newAmount).to.equal(tier1); - // 0 - tier1 - // 1 - tier2 - // 2 - tier3 - expect(type).to.equal(0); - }); - - it('should check delayVault data with tier 2', async () => { - const params = [tier2]; - await delayVaultProvider.connect(user2).createNewDelayVault(user2.address, params); - const newAmount = await delayVaultProvider.userToAmount(user2.address); - const type = await delayVaultProvider.userToType(user2.address); - expect(newAmount).to.equal(tier2); - expect(type).to.equal(1); - }); - - it('should check delayVault data with tier 3', async () => { - const params = [tier3]; - await delayVaultProvider.connect(newOwner).createNewDelayVault(newOwner.address, params); - const newAmount = await delayVaultProvider.userToAmount(newOwner.address); - const type = await delayVaultProvider.userToType(newOwner.address); - expect(newAmount).to.equal(tier3); - expect(type).to.equal(2); - }); - - describe('delayVault withdraw', async () => { - it('should withdraw from delayVault with tier 1', async () => { - const params = [tier1]; - await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); - await lockDealNFT - .connect(user3) - ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); - const newAmount = await delayVaultProvider.userToAmount(user3.address); - const type = await delayVaultProvider.userToType(user3.address); - expect(newAmount).to.equal(0); - expect(type).to.equal(0); - }); - - it('should withdraw from delayVault with tier 2', async () => { - const params = [tier2]; - await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); - await lockDealNFT - .connect(user3) - ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); - const newAmount = await delayVaultProvider.userToAmount(user3.address); - const type = await delayVaultProvider.userToType(user3.address); - expect(newAmount).to.equal(0); - expect(type).to.equal(0); - }); - - it('should withdraw from delayVault with tier 3', async () => { - const params = [tier3]; - const poolId = await lockDealNFT.totalSupply(); - await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); - await lockDealNFT - .connect(user3) - ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); - const newAmount = await delayVaultProvider.userToAmount(user3.address); - const type = await delayVaultProvider.userToType(user3.address); - expect(newAmount).to.equal(0); - expect(type).to.equal(0); - }); - - it('should create new deal provider nft after withdraw with first tier', async () => { - const params = [tier1]; - await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); - await lockDealNFT - .connect(user3) - ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); - vaultId = await mockVaultManager.Id(); - const simpleNFTdata = await lockDealNFT.getData(poolId.add(1)); - expect(simpleNFTdata.provider).to.equal(dealProvider.address); - expect(simpleNFTdata.owner).to.equal(user3.address); - expect(simpleNFTdata.token).to.equal(token); - expect(simpleNFTdata.vaultId).to.equal(vaultId); - expect(simpleNFTdata.params).to.deep.equal([tier1]); - }); - - it('should create new lock provider nft after withdraw with second tier', async () => { - const params = [tier2]; - await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); - await lockDealNFT - .connect(user3) - ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); - const time = await ethers.provider.getBlock('latest').then(block => block.timestamp); - vaultId = await mockVaultManager.Id(); - const simpleNFTdata = await lockDealNFT.getData(poolId.add(1)); - expect(simpleNFTdata.provider).to.equal(lockProvider.address); - expect(simpleNFTdata.owner).to.equal(user3.address); - expect(simpleNFTdata.token).to.equal(token); - expect(simpleNFTdata.vaultId).to.equal(vaultId); - expect(simpleNFTdata.params).to.deep.equal([tier2, time + startTime]); - }); - - it('should create new timed provider nft after withdraw with third tier', async () => { - const params = [tier3]; - await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); - await lockDealNFT - .connect(user3) - ['safeTransferFrom(address,address,uint256)'](user3.address, lockDealNFT.address, poolId); - const time = await ethers.provider.getBlock('latest').then(block => block.timestamp); - vaultId = await mockVaultManager.Id(); - const simpleNFTdata = await lockDealNFT.getData(poolId.add(1)); - expect(simpleNFTdata.provider).to.equal(timedDealProvider.address); - expect(simpleNFTdata.owner).to.equal(user3.address); - expect(simpleNFTdata.token).to.equal(token); - expect(simpleNFTdata.vaultId).to.equal(vaultId); - expect(simpleNFTdata.params).to.deep.equal([tier3, time + startTime, time + finishTime, tier3]); - }); - }); - - describe('delayVault split', async () => { - it('should return half amount in old pool after split', async () => { - const params = [tier1]; - const packedData = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [ratio, user4.address]); - await delayVaultProvider.connect(user4).createNewDelayVault(user4.address, params); - await lockDealNFT.connect(user4)['safeTransferFrom(address,address,uint256,bytes)'](user4.address, lockDealNFT.address, poolId, packedData); - const data = await lockDealNFT.getData(poolId); - expect(data.owner).to.equal(user4.address); - expect(data.provider).to.equal(delayVaultProvider.address); - expect(data.params).to.deep.equal([tier1.div(2)]); - }); - - it('should create new delay nft after split with first tier', async () => { - const params = [tier1]; - const packedData = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [ratio, user3.address]); - await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); - await lockDealNFT - .connect(user3) - ['safeTransferFrom(address,address,uint256,bytes)'](user3.address, lockDealNFT.address, poolId, packedData); - const data = await lockDealNFT.getData(poolId.add(1)); - expect(data.owner).to.equal(user3.address); - expect(data.provider).to.equal(delayVaultProvider.address); - expect(data.params).to.deep.equal([tier1.div(2)]); - }); - - it('should create new delay nft after split with second tier', async () => { - const params = [tier2]; - const packedData = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [ratio, user3.address]); - await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); - await lockDealNFT - .connect(user3) - ['safeTransferFrom(address,address,uint256,bytes)'](user3.address, lockDealNFT.address, poolId, packedData); - const data = await lockDealNFT.getData(poolId.add(1)); - expect(data.owner).to.equal(user3.address); - expect(data.provider).to.equal(delayVaultProvider.address); - expect(data.params).to.deep.equal([tier2.div(2)]); - }); - - it('should create new delay nft after split with third tier', async () => { - const params = [tier3]; - await delayVaultProvider.connect(user3).createNewDelayVault(user3.address, params); - const packedData = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [ratio, user3.address]); - await lockDealNFT - .connect(user3) - ['safeTransferFrom(address,address,uint256,bytes)'](user3.address, lockDealNFT.address, poolId, packedData); - const data = await lockDealNFT.getData(poolId.add(1)); - expect(data.owner).to.equal(user3.address); - expect(data.provider).to.equal(delayVaultProvider.address); - expect(data.params).to.deep.equal([tier3.div(2)]); - }); - }); -}); diff --git a/test/DelayVaultProvider/DelayVaultProvider.ts b/test/DelayVaultProvider/DelayVaultProvider.ts new file mode 100644 index 00000000..9a7d14b2 --- /dev/null +++ b/test/DelayVaultProvider/DelayVaultProvider.ts @@ -0,0 +1,88 @@ +import { token } from '../helper'; +import { delayVault } from './setupTests'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +describe('DelayVault Provider', function () { + before(async () => { + await delayVault.initialize(); + }); + + beforeEach(async () => { + delayVault.poolId = await delayVault.lockDealNFT.totalSupply(); + }); + + it('should check provider name', async () => { + expect(await delayVault.delayVaultProvider.name()).to.equal('DelayVaultProvider'); + }); + + it("should check provider's token", async () => { + expect(await delayVault.delayVaultProvider.token()).to.equal(token); + }); + + it("should check provider's lockDealNFT", async () => { + expect(await delayVault.delayVaultProvider.lockDealNFT()).to.equal(delayVault.lockDealNFT.address); + }); + + it('should check _finilize constructor data', async () => { + for (let i = 0; i < delayVault.providerData.length; i++) { + const data = await delayVault.delayVaultProvider.getTypeToProviderData(i); + expect(data.provider).to.equal(delayVault.providerData[i].provider); + expect(data.params).to.deep.equal(delayVault.providerData[i].params); + i != delayVault.providerData.length - 1 + ? expect(data.limit).to.equal(delayVault.providerData[i].limit) + : expect(data.limit).to.equal(ethers.constants.MaxUint256); + } + }); + + it('should return new provider poolId', async () => { + const params = [delayVault.tier1]; + const lastPoolId = (await delayVault.lockDealNFT.totalSupply()).sub(1); + await delayVault.delayVaultProvider.createNewDelayVault(delayVault.receiver.address, params); + expect((await delayVault.lockDealNFT.totalSupply()).sub(1)).to.equal(lastPoolId.add(1)); + }); + + it('should check vault data with tier 1', async () => { + const params = [delayVault.tier1]; + await delayVault.delayVaultProvider.connect(delayVault.user2).createNewDelayVault(delayVault.user1.address, params); + const newAmount = await delayVault.delayVaultProvider.userToAmount(delayVault.user1.address); + const type = await delayVault.delayVaultProvider.userToType(delayVault.user1.address); + expect(newAmount).to.equal(delayVault.tier1); + // 0 - tier1 + // 1 - tier2 + // 2 - tier3 + expect(type).to.equal(0); + }); + + it('should check delayVault data with tier 2', async () => { + const params = [delayVault.tier2]; + await delayVault.delayVaultProvider.connect(delayVault.user2).createNewDelayVault(delayVault.user2.address, params); + const newAmount = await delayVault.delayVaultProvider.userToAmount(delayVault.user2.address); + const type = await delayVault.delayVaultProvider.userToType(delayVault.user2.address); + expect(newAmount).to.equal(delayVault.tier2); + expect(type).to.equal(1); + }); + + it('should check delayVault data with tier 3', async () => { + const params = [delayVault.tier3]; + await delayVault.delayVaultProvider + .connect(delayVault.newOwner) + .createNewDelayVault(delayVault.newOwner.address, params); + const newAmount = await delayVault.delayVaultProvider.userToAmount(delayVault.newOwner.address); + const type = await delayVault.delayVaultProvider.userToType(delayVault.newOwner.address); + expect(newAmount).to.equal(delayVault.tier3); + expect(type).to.equal(2); + }); + + it("can't upgrade type another user tier by using transfer", async () => { + expect(await delayVault.delayVaultProvider.userToType(delayVault.user4.address)).to.equal(0); + const params = [delayVault.tier2]; + const owner = delayVault.newOwner; + await delayVault.delayVaultProvider.connect(owner).createNewDelayVault(owner.address, params); + await expect( + delayVault.lockDealNFT + .connect(owner) + ['safeTransferFrom(address,address,uint256)'](owner.address, delayVault.user4.address, delayVault.poolId), + ).to.be.revertedWith('type must be the same or lower'); + }); +}); diff --git a/test/DelayVaultProvider/DelayVaultSplit.ts b/test/DelayVaultProvider/DelayVaultSplit.ts new file mode 100644 index 00000000..077d9fe1 --- /dev/null +++ b/test/DelayVaultProvider/DelayVaultSplit.ts @@ -0,0 +1,99 @@ +import { MAX_RATIO } from '../helper'; +import { delayVault } from './setupTests'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { BigNumber } from 'ethers'; +import { ethers } from 'hardhat'; + +describe('delayVault split', async () => { + before(async () => { + await delayVault.initialize(); + }); + + beforeEach(async () => { + delayVault.poolId = await delayVault.lockDealNFT.totalSupply(); + }); + + async function split(creator: SignerWithAddress, userToSplit: SignerWithAddress, params: BigNumber[]) { + await delayVault.delayVaultProvider.connect(creator).createNewDelayVault(creator.address, params); + const bytes = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [delayVault.ratio, creator.address]); + await delayVault.lockDealNFT + .connect(creator) + ['safeTransferFrom(address,address,uint256,bytes)']( + userToSplit.address, + delayVault.lockDealNFT.address, + delayVault.poolId, + bytes, + ); + } + + it('should return half amount in old pool after split', async () => { + await split(delayVault.user4, delayVault.user4, [delayVault.tier1]); + const data = await delayVault.lockDealNFT.getData(delayVault.poolId); + expect(data.owner).to.equal(delayVault.user4.address); + expect(data.provider).to.equal(delayVault.delayVaultProvider.address); + expect(data.params).to.deep.equal([delayVault.tier1.div(2)]); + }); + + it('should create new delay nft after split with first tier', async () => { + await split(delayVault.user3, delayVault.user3, [delayVault.tier1]); + const data = await delayVault.lockDealNFT.getData(delayVault.poolId.add(1)); + expect(data.owner).to.equal(delayVault.user3.address); + expect(data.provider).to.equal(delayVault.delayVaultProvider.address); + expect(data.params).to.deep.equal([delayVault.tier1.div(2)]); + }); + + it('should create new delay nft after split with second tier', async () => { + await split(delayVault.user3, delayVault.user3, [delayVault.tier2]); + const data = await delayVault.lockDealNFT.getData(delayVault.poolId.add(1)); + expect(data.owner).to.equal(delayVault.user3.address); + expect(data.provider).to.equal(delayVault.delayVaultProvider.address); + expect(data.params).to.deep.equal([delayVault.tier2.div(2)]); + }); + + it('should create new delay nft after split with third tier', async () => { + await split(delayVault.user3, delayVault.user3, [delayVault.tier3]); + const data = await delayVault.lockDealNFT.getData(delayVault.poolId.add(1)); + expect(data.owner).to.equal(delayVault.user3.address); + expect(data.provider).to.equal(delayVault.delayVaultProvider.address); + expect(data.params).to.deep.equal([delayVault.tier3.div(2)]); + }); + + it('the level should not decrease after split', async () => { + const params = [delayVault.tier2]; + const owner = delayVault.newOwner; + await delayVault.delayVaultProvider.connect(owner).createNewDelayVault(owner.address, params); + expect(await delayVault.delayVaultProvider.userToType(owner.address)).to.equal(1); + const rate = MAX_RATIO.sub(MAX_RATIO.div(10)); // 90% + const bytes = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [rate, delayVault.user3.address]); + let newAmount = await delayVault.delayVaultProvider.userToAmount(owner.address); + await delayVault.lockDealNFT + .connect(owner) + ['safeTransferFrom(address,address,uint256,bytes)']( + owner.address, + delayVault.lockDealNFT.address, + delayVault.poolId, + bytes, + ); + newAmount = await delayVault.delayVaultProvider.userToAmount(owner.address); + expect(await delayVault.delayVaultProvider.userToType(owner.address)).to.equal(1); + }); + + it("can't upgrade type another user tier by using split", async () => { + expect(await delayVault.delayVaultProvider.userToType(delayVault.receiver.address)).to.equal(0); + const params = [delayVault.tier2]; + const owner = delayVault.newOwner; + await delayVault.delayVaultProvider.connect(owner).createNewDelayVault(owner.address, params); + const bytes = ethers.utils.defaultAbiCoder.encode(['uint256', 'address'], [MAX_RATIO, delayVault.receiver.address]); + await expect( + delayVault.lockDealNFT + .connect(owner) + ['safeTransferFrom(address,address,uint256,bytes)']( + owner.address, + delayVault.lockDealNFT.address, + delayVault.poolId, + bytes, + ), + ).to.be.revertedWith('type must be the same or lower'); + }); +}); diff --git a/test/DelayVaultProvider/DelayVaultTypeTier.ts b/test/DelayVaultProvider/DelayVaultTypeTier.ts new file mode 100644 index 00000000..bff3e206 --- /dev/null +++ b/test/DelayVaultProvider/DelayVaultTypeTier.ts @@ -0,0 +1,61 @@ +import { delayVault } from './setupTests'; +import { expect } from 'chai'; + +describe('DelayVaultProvider type tier tests', async () => { + before(async () => { + await delayVault.initialize(); + }); + + beforeEach(async () => { + delayVault.poolId = await delayVault.lockDealNFT.totalSupply(); + }); + + it('checking default type tier', async () => { + expect(await delayVault.delayVaultProvider.userToType(delayVault.user1.address)).to.equal(0); + }); + + it('should upgrade type tier', async () => { + const params = [delayVault.tier1]; + const newType = 2; + await delayVault.delayVaultProvider.connect(delayVault.user1).createNewDelayVault(delayVault.user1.address, params); + await delayVault.delayVaultProvider.connect(delayVault.user1).upgradeType(newType); + expect(await delayVault.delayVaultProvider.userToType(delayVault.user1.address)).to.equal(newType); + }); + + it("should revert if user doesn't have delayVault", async () => { + await expect(delayVault.delayVaultProvider.connect(delayVault.user2).upgradeType(2)).to.be.revertedWith( + 'amount must be bigger than 0', + ); + }); + + it('should revert if new tier smaller that old one', async () => { + const params = [delayVault.tier2]; + await delayVault.delayVaultProvider.connect(delayVault.user2).createNewDelayVault(delayVault.user2.address, params); + await expect(delayVault.delayVaultProvider.connect(delayVault.user2).upgradeType(0)).to.be.revertedWith( + 'new type must be bigger than the old one', + ); + }); + + it('should revert if set new tier bigger than max tier', async () => { + await expect(delayVault.delayVaultProvider.connect(delayVault.user2).upgradeType(255)).to.be.revertedWith( + 'new type must be smaller than the types count', + ); + }); + + it("upgradeType call after one user created delayVault for another user's address", async () => { + const params = [delayVault.tier1]; + const newType = 2; + await delayVault.delayVaultProvider.connect(delayVault.user2).createNewDelayVault(delayVault.user3.address, params); + await delayVault.delayVaultProvider.connect(delayVault.user3).upgradeType(newType); + expect(await delayVault.delayVaultProvider.userToType(delayVault.user3.address)).to.equal(newType); + }); + + it('The type level should be increased if the user will have multiple nfts', async () => { + let params = [delayVault.tier1]; + await delayVault.delayVaultProvider.connect(delayVault.user4).createNewDelayVault(delayVault.user4.address, params); + params = [delayVault.tier1]; + await delayVault.delayVaultProvider.connect(delayVault.user4).createNewDelayVault(delayVault.user4.address, params); + expect(await delayVault.delayVaultProvider.userToType(delayVault.user4.address)).to.equal(1); + }); + +}); diff --git a/test/DelayVaultProvider/DelayVaultView.ts b/test/DelayVaultProvider/DelayVaultView.ts new file mode 100644 index 00000000..f6c30567 --- /dev/null +++ b/test/DelayVaultProvider/DelayVaultView.ts @@ -0,0 +1,33 @@ +import { delayVault } from './setupTests'; +import { expect } from 'chai'; + +describe('DelayVaultProvider view tests', async () => { + before(async () => { + await delayVault.initialize(); + }); + + beforeEach(async () => { + delayVault.poolId = await delayVault.lockDealNFT.totalSupply(); + }); + + it('should return getWithdrawableAmount from created pool', async () => { + const params = [delayVault.tier2]; + const owner = delayVault.newOwner; + await delayVault.delayVaultProvider.connect(owner).createNewDelayVault(owner.address, params); + expect(await delayVault.delayVaultProvider.getWithdrawableAmount(delayVault.poolId)).to.be.equal(delayVault.tier2); + }); + + it('should return type of tier', async () => { + expect(await delayVault.delayVaultProvider.theTypeOf(delayVault.tier1)).to.be.equal(0); + expect(await delayVault.delayVaultProvider.theTypeOf(delayVault.tier2)).to.be.equal(1); + expect(await delayVault.delayVaultProvider.theTypeOf(delayVault.tier3)).to.be.equal(2); + }); + + it('should return total user amount', async () => { + const params = [delayVault.tier2]; + const owner = delayVault.user1; + await delayVault.delayVaultProvider.connect(owner).createNewDelayVault(owner.address, params); + await delayVault.delayVaultProvider.connect(owner).createNewDelayVault(owner.address, params); + expect(await delayVault.delayVaultProvider.getTotalAmount(owner.address)).to.be.equal(delayVault.tier2.mul(2)); + }); +}); diff --git a/test/DelayVaultProvider/DelayVaultWithdraw.ts b/test/DelayVaultProvider/DelayVaultWithdraw.ts new file mode 100644 index 00000000..2462951f --- /dev/null +++ b/test/DelayVaultProvider/DelayVaultWithdraw.ts @@ -0,0 +1,99 @@ +import { token } from '../helper'; +import { delayVault } from './setupTests'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { BigNumber } from 'ethers'; +import { ethers } from 'hardhat'; + +describe('delayVault withdraw', async () => { + before(async () => { + await delayVault.initialize(); + }); + + beforeEach(async () => { + delayVault.poolId = await delayVault.lockDealNFT.totalSupply(); + }); + + async function withdraw(user: SignerWithAddress, params: BigNumber[]) { + await delayVault.delayVaultProvider.connect(user).createNewDelayVault(user.address, params); + await delayVault.lockDealNFT + .connect(user) + ['safeTransferFrom(address,address,uint256)'](user.address, delayVault.lockDealNFT.address, delayVault.poolId); + } + + it('should withdraw from delayVault with tier 1', async () => { + await withdraw(delayVault.user3, [delayVault.tier1]); + const newAmount = await delayVault.delayVaultProvider.userToAmount(delayVault.user3.address); + const type = await delayVault.delayVaultProvider.userToType(delayVault.user3.address); + expect(newAmount).to.equal(0); + expect(type).to.equal(0); + }); + + it('should withdraw from delayVault with tier 2', async () => { + await withdraw(delayVault.user3, [delayVault.tier2]); + const newAmount = await delayVault.delayVaultProvider.userToAmount(delayVault.user3.address); + const type = await delayVault.delayVaultProvider.userToType(delayVault.user3.address); + expect(newAmount).to.equal(0); + expect(type).to.equal(0); + }); + + it('should withdraw from delayVault with tier 3', async () => { + await withdraw(delayVault.user3, [delayVault.tier3]); + const newAmount = await delayVault.delayVaultProvider.userToAmount(delayVault.user3.address); + const type = await delayVault.delayVaultProvider.userToType(delayVault.user3.address); + expect(newAmount).to.equal(0); + expect(type).to.equal(0); + }); + + it('should create new deal provider nft after withdraw with first tier', async () => { + await withdraw(delayVault.user3, [delayVault.tier1]); + delayVault.vaultId = await delayVault.mockVaultManager.Id(); + const simpleNFTdata = await delayVault.lockDealNFT.getData(delayVault.poolId.add(1)); + expect(simpleNFTdata.provider).to.equal(delayVault.dealProvider.address); + expect(simpleNFTdata.owner).to.equal(delayVault.user3.address); + expect(simpleNFTdata.token).to.equal(token); + expect(simpleNFTdata.vaultId).to.equal(delayVault.vaultId); + expect(simpleNFTdata.params).to.deep.equal([delayVault.tier1]); + }); + + it('should create new lock provider nft after withdraw with second tier', async () => { + await withdraw(delayVault.user3, [delayVault.tier2]); + const time = await ethers.provider.getBlock('latest').then(block => block.timestamp); + delayVault.vaultId = await delayVault.mockVaultManager.Id(); + const simpleNFTdata = await delayVault.lockDealNFT.getData(delayVault.poolId.add(1)); + expect(simpleNFTdata.provider).to.equal(delayVault.lockProvider.address); + expect(simpleNFTdata.owner).to.equal(delayVault.user3.address); + expect(simpleNFTdata.token).to.equal(token); + expect(simpleNFTdata.vaultId).to.equal(delayVault.vaultId); + expect(simpleNFTdata.params).to.deep.equal([delayVault.tier2, time + delayVault.startTime]); + }); + + it('should create new timed provider nft after withdraw with third tier', async () => { + await withdraw(delayVault.user3, [delayVault.tier3]); + const time = await ethers.provider.getBlock('latest').then(block => block.timestamp); + delayVault.vaultId = await delayVault.mockVaultManager.Id(); + const simpleNFTdata = await delayVault.lockDealNFT.getData(delayVault.poolId.add(1)); + expect(simpleNFTdata.provider).to.equal(delayVault.timedDealProvider.address); + expect(simpleNFTdata.owner).to.equal(delayVault.user3.address); + expect(simpleNFTdata.token).to.equal(token); + expect(simpleNFTdata.vaultId).to.equal(delayVault.vaultId); + expect(simpleNFTdata.params).to.deep.equal([ + delayVault.tier3, + time + delayVault.startTime, + time + delayVault.finishTime, + delayVault.tier3, + ]); + }); + + it("can't deacrease tier level after user withdraw half amount", async () => { + const params = [delayVault.tier1]; + const user = delayVault.user3; + await delayVault.delayVaultProvider.connect(user).createNewDelayVault(user.address, params); + await delayVault.delayVaultProvider.connect(user).createNewDelayVault(user.address, params); + expect(await delayVault.delayVaultProvider.userToType(user.address)).to.equal(1); + await delayVault.lockDealNFT + .connect(user) + ['safeTransferFrom(address,address,uint256)'](user.address, delayVault.lockDealNFT.address, delayVault.poolId); + expect(await delayVault.delayVaultProvider.userToType(user.address)).to.equal(1); + }); +}); diff --git a/test/DelayVaultProvider/setupTests.ts b/test/DelayVaultProvider/setupTests.ts new file mode 100644 index 00000000..ae2fa811 --- /dev/null +++ b/test/DelayVaultProvider/setupTests.ts @@ -0,0 +1,68 @@ +import { LockDealProvider } from '../../typechain-types'; +import { TimedDealProvider } from '../../typechain-types'; +import { LockDealNFT } from '../../typechain-types'; +import { DealProvider } from '../../typechain-types'; +import { MockProvider } from '../../typechain-types'; +import { MockVaultManager } from '../../typechain-types'; +import { DelayVaultProvider } from '../../typechain-types'; +import { IDelayVaultData } from '../../typechain-types/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider'; +import { deployed, token, MAX_RATIO, _createUsers } from '../helper'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { BigNumber } from 'ethers'; +import { ethers } from 'hardhat'; + +export class DelayVault { + public delayVaultProvider!: DelayVaultProvider; + public lockDealNFT!: LockDealNFT; + public timedDealProvider!: TimedDealProvider; + public lockProvider!: LockDealProvider; + public dealProvider!: DealProvider; + public mockProvider!: MockProvider; + public mockVaultManager!: MockVaultManager; + public poolId!: BigNumber; + public vaultId!: BigNumber; + public receiver!: SignerWithAddress; + public user1!: SignerWithAddress; + public user2!: SignerWithAddress; + public user3!: SignerWithAddress; + public user4!: SignerWithAddress; + public newOwner!: SignerWithAddress; + public startTime!: number; + public finishTime!: number; + public providerData!: IDelayVaultData.ProviderDataStruct[]; + public tier1: BigNumber = ethers.BigNumber.from(250); + public tier2: BigNumber = ethers.BigNumber.from(3500); + public tier3: BigNumber = ethers.BigNumber.from(20000); + public ratio: BigNumber = MAX_RATIO.div(2); + gasLimit: number = 130_000_000; + + async initialize() { + [this.receiver, this.newOwner, this.user1, this.user2, this.user3, this.user4] = await ethers.getSigners(); + this.mockVaultManager = await deployed('MockVaultManager'); + this.lockDealNFT = await deployed('LockDealNFT', this.mockVaultManager.address, ''); + this.dealProvider = await deployed('DealProvider', this.lockDealNFT.address); + this.lockProvider = await deployed('LockDealProvider', this.lockDealNFT.address, this.dealProvider.address); + this.timedDealProvider = await deployed('TimedDealProvider', this.lockDealNFT.address, this.lockProvider.address); + this.mockProvider = await deployed('MockProvider', this.lockDealNFT.address, this.timedDealProvider.address); + const DelayVaultProvider = await ethers.getContractFactory('DelayVaultProvider'); + const ONE_DAY = 86400; + const week = ONE_DAY * 7; + this.startTime = week; + this.finishTime = week * 4; + this.providerData = [ + { provider: this.dealProvider.address, params: [], limit: this.tier1 }, + { provider: this.lockProvider.address, params: [this.startTime], limit: this.tier2 }, + { provider: this.timedDealProvider.address, params: [this.startTime, this.finishTime], limit: this.tier3 }, + ]; + this.delayVaultProvider = await DelayVaultProvider.deploy(token, this.lockDealNFT.address, this.providerData, { + gasLimit: this.gasLimit, + }); + await this.lockDealNFT.setApprovedContract(this.dealProvider.address, true); + await this.lockDealNFT.setApprovedContract(this.lockProvider.address, true); + await this.lockDealNFT.setApprovedContract(this.timedDealProvider.address, true); + await this.lockDealNFT.setApprovedContract(this.mockProvider.address, true); + await this.lockDealNFT.setApprovedContract(this.delayVaultProvider.address, true); + } +} + +export const delayVault = new DelayVault(); \ No newline at end of file From 5e413271c8388f3818762730b3b062542a3b7347 Mon Sep 17 00:00:00 2001 From: Andrew Dmytrenko Date: Fri, 13 Oct 2023 14:15:43 +0300 Subject: [PATCH 41/42] build fixing --- .../AdvancedProviders/DelayVaultProvider/DelayVaultState.sol | 2 +- test/LockDealNFT.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol index 55b52c1c..4d5fc526 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol @@ -56,7 +56,7 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold function _createLockNFT(address owner, uint256 amount, uint8 theType, uint tokenId) internal { ProviderData memory providerData = typeToProviderData[theType]; uint256 newPoolId = lockDealNFT.mintForProvider(owner, providerData.provider); - lockDealNFT.copyVaultId(tokenId, newPoolId); + lockDealNFT.cloneVaultId(newPoolId, tokenId); uint256[] memory params = getWithdrawPoolParams(amount, theType); providerData.provider.registerPool(newPoolId, params); } diff --git a/test/LockDealNFT.ts b/test/LockDealNFT.ts index 866a911e..fd41657b 100644 --- a/test/LockDealNFT.ts +++ b/test/LockDealNFT.ts @@ -277,7 +277,7 @@ describe('LockDealNFT', function () { }); it('check if the contract supports ILockDealNFT interface', async () => { - expect(await lockDealNFT.supportsInterface('0x22fd0654')).to.equal(true); + expect(await lockDealNFT.supportsInterface('0xa8b7d970')).to.equal(true); }); it('shuld return royalty', async () => { From fa24c5fc13be8e97cc5111e4c44800e55b249949 Mon Sep 17 00:00:00 2001 From: Andrew Dmytrenko <68740472+YouStillAlive@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:15:13 +0300 Subject: [PATCH 42/42] migrator preparations (#352) * migrator preparations * split logic * build fixing * add migrator revert tests * delete unused data * remove getLockDealNFT * fix params length * allow migrator to change type --- .../BundleProvider/BundleProvider.sol | 1 - .../DelayVaultProvider/DelayVaultProvider.sol | 11 +- .../DelayVaultProvider/DelayVaultState.sol | 4 + .../DelayVaultProvider/HoldersSum.sol | 7 +- .../MigratorV1/DelayMigratorState.sol | 25 ++++ .../MigratorV1/DelayVaultMigrator.sol | 47 ++++--- .../IDelayVaultProvider.sol | 26 ++-- .../IDelayVaultV1.sol | 0 .../MigratorV1 => interfaces}/ILockDealV2.sol | 0 .../MigratorV1 => interfaces}/IMigrator.sol | 4 + contracts/mock/MockDelayMigrator.sol | 10 -- contracts/mock/MockDelayVault.sol | 33 +++++ test/Builder/SimpleBuilder.ts | 2 +- test/DelayMigrator/DelayMigrator.ts | 121 ++++++++++++++++++ test/DelayVaultProvider/DelayVaultProvider.ts | 2 + test/DelayVaultProvider/setupTests.ts | 27 ++-- test/helper.ts | 7 +- 17 files changed, 254 insertions(+), 73 deletions(-) create mode 100644 contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayMigratorState.sol rename contracts/{AdvancedProviders/DelayVaultProvider/MigratorV1 => interfaces}/IDelayVaultProvider.sol (55%) rename contracts/{AdvancedProviders/DelayVaultProvider/MigratorV1 => interfaces}/IDelayVaultV1.sol (100%) rename contracts/{AdvancedProviders/DelayVaultProvider/MigratorV1 => interfaces}/ILockDealV2.sol (100%) rename contracts/{AdvancedProviders/DelayVaultProvider/MigratorV1 => interfaces}/IMigrator.sol (63%) delete mode 100644 contracts/mock/MockDelayMigrator.sol create mode 100644 contracts/mock/MockDelayVault.sol create mode 100644 test/DelayMigrator/DelayMigrator.ts diff --git a/contracts/AdvancedProviders/BundleProvider/BundleProvider.sol b/contracts/AdvancedProviders/BundleProvider/BundleProvider.sol index ee0a45ea..8b285591 100644 --- a/contracts/AdvancedProviders/BundleProvider/BundleProvider.sol +++ b/contracts/AdvancedProviders/BundleProvider/BundleProvider.sol @@ -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 { diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol index 05bbc1b5..152c5134 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider.sol @@ -2,17 +2,16 @@ pragma solidity ^0.8.0; import "./DelayVaultState.sol"; -import "../../mock/MockDelayMigrator.sol"; contract DelayVaultProvider is DelayVaultState { - constructor(address _token, ILockDealNFT _nftContract, ProviderData[] memory _providersData) { + constructor(address _token, IMigrator _migrator, ProviderData[] memory _providersData) { require(address(_token) != address(0x0), "invalid address"); - require(address(_nftContract) != address(0x0), "invalid address"); + require(address(_migrator) != address(0x0), "invalid address"); require(_providersData.length <= 255, "too many providers"); name = "DelayVaultProvider"; token = _token; - lockDealNFT = _nftContract; - migrator = new MockDelayMigrator(); + migrator = _migrator; + lockDealNFT = _migrator.lockDealNFT(); _finilize(_providersData); } @@ -28,7 +27,7 @@ contract DelayVaultProvider is DelayVaultState { function _registerPool(uint256 poolId, uint256[] calldata params) internal { uint256 amount = params[0]; address owner = lockDealNFT.ownerOf(poolId); - _addHoldersSum(owner, amount, owner == msg.sender); + _addHoldersSum(owner, amount, owner == msg.sender || msg.sender == address(migrator)); poolIdToAmount[poolId] = amount; } diff --git a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol index 4d5fc526..0c211cc9 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultState.sol @@ -81,4 +81,8 @@ abstract contract DelayVaultState is DealProviderState, LastPoolOwnerState, Hold 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); + } } diff --git a/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol index d2040f44..b7a9aacf 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/HoldersSum.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.0; import "../../SimpleProviders/Provider/ProviderModifiers.sol"; -import "./MigratorV1/IDelayVaultProvider.sol"; -import "./MigratorV1/IMigrator.sol"; +import "../../interfaces/IDelayVaultProvider.sol"; +import "../../interfaces/IDelayVaultV1.sol"; +import "../../interfaces/IMigrator.sol"; -abstract contract HoldersSum is ProviderModifiers, IDelayVaultData { +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) diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayMigratorState.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayMigratorState.sol new file mode 100644 index 00000000..995d9cb8 --- /dev/null +++ b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayMigratorState.sol @@ -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"); + } +} diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol index 6c25016b..d729edb4 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol +++ b/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/DelayVaultMigrator.sol @@ -1,55 +1,52 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./IDelayVaultProvider.sol"; -import "./IDelayVaultV1.sol"; +import "./DelayMigratorState.sol"; +import "../../../interfaces/ILockDealV2.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "./ILockDealV2.sol"; +import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; -contract DelayVaultMigrator is IDelayVaultData, ILockDealV2 { - IDelayVaultV1 public oldVault; - IDelayVaultProvider public newVault; - address public token; - IVaultManager public vaultManager; - ILockDealNFT public nftContract; - bool public isInitialized; - address public owner = msg.sender; // Initialize owner at declaration - - constructor(IDelayVaultV1 _oldVault) { +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(); - nftContract = newVault.nftContract(); - vaultManager = nftContract.vaultManager(); + 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 { + 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[](2); + uint256[] memory params = new uint256[](1); params[0] = amount; - params[1] = 1; //allow type change IERC20(token).approve(address(vaultManager), amount); newVault.createNewDelayVault(msg.sender, params); } //this option is to get tokens from the DelayVaultV1 and deposit them to the LockDealNFT (v3) - function withdrawTokensFromV1Vault() external { + 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)); - ProviderData memory providerData = newVault.TypeToProviderData(theType); + IDelayVaultProvider.ProviderData memory providerData = newVault.getTypeToProviderData(theType); IERC20(token).approve(address(vaultManager), amount); - uint256 newPoolId = nftContract.mintAndTransfer( + uint256 newPoolId = lockDealNFT.mintAndTransfer( msg.sender, token, address(this), @@ -71,13 +68,13 @@ contract DelayVaultMigrator is IDelayVaultData, ILockDealV2 { 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 { + ) external payable override afterInit { require(msg.sender == address(oldVault), "DelayVaultMigrator: not DelayVaultV1"); uint8 theType = newVault.theTypeOf(newVault.getTotalAmount(_Owner)); - ProviderData memory providerData = newVault.TypeToProviderData(theType); + IDelayVaultProvider.ProviderData memory providerData = newVault.getTypeToProviderData(theType); IERC20(token).transferFrom(msg.sender, address(this), _StartAmount); IERC20(token).approve(address(vaultManager), _StartAmount); - uint256 newPoolId = nftContract.mintAndTransfer( + uint256 newPoolId = lockDealNFT.mintAndTransfer( _Owner, _Token, address(this), diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol b/contracts/interfaces/IDelayVaultProvider.sol similarity index 55% rename from contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol rename to contracts/interfaces/IDelayVaultProvider.sol index 4771c0e9..ddc0c481 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultProvider.sol +++ b/contracts/interfaces/IDelayVaultProvider.sol @@ -1,31 +1,25 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../interfaces/IProvider.sol"; -import "../../../interfaces/ILockDealNFT.sol"; +import "./IProvider.sol"; +import "./ILockDealNFT.sol"; interface IDelayVaultProvider { - function createNewDelayVault(address owner, uint256[] memory params) external; + struct ProviderData { + IProvider provider; + uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider + uint256 limit; + } - function Token() external view returns (address); + function createNewDelayVault(address owner, uint256[] memory params) external returns (uint256 poolId); - function getLeftAmount(address owner, uint8 theType) external view returns (uint256); + function token() external view returns (address); function theTypeOf(uint256 amount) external view returns (uint8); - function nftContract() external view returns (ILockDealNFT); - function getTotalAmount(address user) external view returns (uint256); - function TypeToProviderData(uint8 theType) external view returns (IDelayVaultData.ProviderData memory providerData); + function getTypeToProviderData(uint8 theType) external view returns (ProviderData memory providerData); function getWithdrawPoolParams(uint256 amount, uint8 theType) external view returns (uint256[] memory params); } - -interface IDelayVaultData { - struct ProviderData { - IProvider provider; - uint256[] params; // 0 for DealProvider,1 for LockProvider ,2 for TimedDealProvider - uint256 limit; - } -} diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol b/contracts/interfaces/IDelayVaultV1.sol similarity index 100% rename from contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IDelayVaultV1.sol rename to contracts/interfaces/IDelayVaultV1.sol diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/ILockDealV2.sol b/contracts/interfaces/ILockDealV2.sol similarity index 100% rename from contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/ILockDealV2.sol rename to contracts/interfaces/ILockDealV2.sol diff --git a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IMigrator.sol b/contracts/interfaces/IMigrator.sol similarity index 63% rename from contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IMigrator.sol rename to contracts/interfaces/IMigrator.sol index 37e5cb71..579d84e1 100644 --- a/contracts/AdvancedProviders/DelayVaultProvider/MigratorV1/IMigrator.sol +++ b/contracts/interfaces/IMigrator.sol @@ -1,6 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import "./ILockDealNFT.sol"; + interface IMigrator { function getUserV1Amount(address user) external view returns (uint256 amount); + + function lockDealNFT() external view returns (ILockDealNFT); } diff --git a/contracts/mock/MockDelayMigrator.sol b/contracts/mock/MockDelayMigrator.sol deleted file mode 100644 index c0eec3ca..00000000 --- a/contracts/mock/MockDelayMigrator.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "../AdvancedProviders/DelayVaultProvider/MigratorV1/IMigrator.sol"; - -contract MockDelayMigrator is IMigrator { - function getUserV1Amount(address) external pure returns (uint256 amount) { - amount = 0; - } -} diff --git a/contracts/mock/MockDelayVault.sol b/contracts/mock/MockDelayVault.sol new file mode 100644 index 00000000..a7b61283 --- /dev/null +++ b/contracts/mock/MockDelayVault.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../interfaces/IDelayVaultV1.sol"; + +contract MockDelayVault is IDelayVaultV1 { + mapping(address => mapping(address => Vault)) public VaultMap; + mapping(address => mapping(address => bool)) public Allowance; + + struct Vault { + uint256 Amount; + uint256 StartDelay; + uint256 CliffDelay; + uint256 FinishDelay; + } + + // input data for VaultMap + constructor(address token, Vault[] memory vaults, address[] memory owners) { + uint256 length = vaults.length; + require(length == owners.length, "MockDelayVault: wrong input data"); + for (uint256 i = 0; i < length; ++i) { + VaultMap[token][owners[i]] = vaults[i]; + } + } + + function CreateNewPool(address token, uint256 startAmount, address owner) external {} + + function approveTokenRedemption(address token, bool status) external { + Allowance[token][msg.sender] = status; + } + + function redeemTokensFromVault(address token, address owner, uint256 amount) external {} +} diff --git a/test/Builder/SimpleBuilder.ts b/test/Builder/SimpleBuilder.ts index 41ccdd02..f153f7f1 100644 --- a/test/Builder/SimpleBuilder.ts +++ b/test/Builder/SimpleBuilder.ts @@ -8,7 +8,7 @@ import { deployed, token, _createUsers, _logGasPrice } from '../helper'; import { time } from '@nomicfoundation/hardhat-network-helpers'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { expect } from 'chai'; -import { BigNumber, ContractReceipt } from 'ethers'; +import { BigNumber } from 'ethers'; import { ethers } from 'hardhat'; import { BuilderState } from '../../typechain-types/contracts/Builders/SimpleBuilder/SimpleBuilder'; diff --git a/test/DelayMigrator/DelayMigrator.ts b/test/DelayMigrator/DelayMigrator.ts new file mode 100644 index 00000000..7317c020 --- /dev/null +++ b/test/DelayMigrator/DelayMigrator.ts @@ -0,0 +1,121 @@ +import { MockVaultManager } from '../../typechain-types'; +import { DealProvider } from '../../typechain-types'; +import { LockDealNFT } from '../../typechain-types'; +import { LockDealProvider } from '../../typechain-types'; +import { TimedDealProvider } from '../../typechain-types'; +import { DelayVaultMigrator } from '../../typechain-types'; +import { DelayVaultProvider } from '../../typechain-types/contracts/AdvancedProviders/DelayVaultProvider'; +import { IDelayVaultProvider } from '../../typechain-types/contracts/interfaces/IDelayVaultProvider'; +import { MockDelayVault } from '../../typechain-types/contracts/mock/MockDelayVault'; +import { deployed, token } from '../helper'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { BigNumber, constants } from 'ethers'; +import { ethers } from 'hardhat'; + +describe('Delay Migrator tests', function () { + let lockProvider: LockDealProvider; + let dealProvider: DealProvider; + let timedProvider: TimedDealProvider; + let mockVaultManager: MockVaultManager; + let mockDelayVault: MockDelayVault; + let delayVaultMigrator: DelayVaultMigrator; + let delayVaultProvider: DelayVaultProvider; + let lockDealNFT: LockDealNFT; + let user1: SignerWithAddress; + let user2: SignerWithAddress; + let user3: SignerWithAddress; + let providerData: IDelayVaultProvider.ProviderDataStruct[]; + const tier1: BigNumber = ethers.BigNumber.from(250); + const tier2: BigNumber = ethers.BigNumber.from(3500); + const tier3: BigNumber = ethers.BigNumber.from(20000); + let startTime: number, finishTime: number; + const amount = ethers.utils.parseEther('100'); + const ONE_DAY = 86400; + const userVaults: MockDelayVault.VaultStruct[] = [ + { + Amount: amount, + StartDelay: ONE_DAY, + CliffDelay: 0, + FinishDelay: 0, + }, + { + Amount: amount.mul(2), + StartDelay: 0, + CliffDelay: 0, + FinishDelay: ONE_DAY, + }, + { + Amount: amount.div(2), + StartDelay: 0, + CliffDelay: ONE_DAY, + FinishDelay: 0, + }, + ]; + + before(async () => { + [user1, user2, user3] = await ethers.getSigners(); + mockVaultManager = await deployed('MockVaultManager'); + lockDealNFT = await deployed('LockDealNFT', mockVaultManager.address, ''); + dealProvider = await deployed('DealProvider', lockDealNFT.address); + lockProvider = await deployed('LockDealProvider', lockDealNFT.address, dealProvider.address); + timedProvider = await deployed('TimedDealProvider', lockDealNFT.address, lockProvider.address); + const mockDelay = await ethers.getContractFactory('MockDelayVault'); + mockDelayVault = await mockDelay.deploy(token, userVaults, [user1.address, user2.address, user3.address]); + delayVaultMigrator = await deployed('DelayVaultMigrator', lockDealNFT.address, mockDelayVault.address); + const week = ONE_DAY * 7; + startTime = week; + finishTime = week * 4; + providerData = [ + { provider: dealProvider.address, params: [], limit: tier1 }, + { provider: lockProvider.address, params: [startTime], limit: tier2 }, + { provider: timedProvider.address, params: [startTime, finishTime], limit: tier3 }, + ]; + const DelayVaultProvider = await ethers.getContractFactory('DelayVaultProvider'); + delayVaultProvider = await DelayVaultProvider.deploy(token, delayVaultMigrator.address, providerData); + await lockDealNFT.setApprovedContract(lockProvider.address, true); + await lockDealNFT.setApprovedContract(dealProvider.address, true); + await lockDealNFT.setApprovedContract(timedProvider.address, true); + await lockDealNFT.setApprovedContract(lockDealNFT.address, true); + await lockDealNFT.setApprovedContract(delayVaultProvider.address, true); + }); + + it('should revert invalid delayVaultProvider', async () => { + await expect(delayVaultMigrator.finilize(mockDelayVault.address)).to.be.revertedWith( + 'DelayVaultMigrator: Invalid new delay vault contract', + ); + }); + + it('should revert invalid owner call', async () => { + await expect(delayVaultMigrator.connect(user2).finilize(delayVaultProvider.address)).to.be.revertedWith( + 'DelayVaultMigrator: not owner', + ); + }); + + it('should revert not initialized migrate call', async () => { + delayVaultMigrator = await deployed('DelayVaultMigrator', lockDealNFT.address, mockDelayVault.address); + await expect(delayVaultMigrator.fullMigrate()).to.be.revertedWith('DelayVaultMigrator: not initialized'); + }); + + it('should finilize data', async () => { + await delayVaultMigrator.finilize(delayVaultProvider.address); + expect(await delayVaultMigrator.newVault()).to.be.equal(delayVaultProvider.address); + expect(await delayVaultMigrator.token()).to.be.equal(token); + expect(await delayVaultMigrator.vaultManager()).to.be.equal(mockVaultManager.address); + expect(await delayVaultMigrator.owner()).to.be.equal(constants.AddressZero); + }); + + it('should revert not approved migrate call', async () => { + await expect(delayVaultMigrator.fullMigrate()).to.be.revertedWith('DelayVaultMigrator: not allowed'); + }); + + it('should revert not approved withdrawTokensFromV1Vault call', async () => { + await expect(delayVaultMigrator.withdrawTokensFromV1Vault()).to.be.revertedWith('DelayVaultMigrator: not allowed'); + }); + + it('should revert not DelayVaultV1 CreateNewPool call', async () => { + await expect(delayVaultMigrator.CreateNewPool(token, 0, 0, 0, 0, user1.address)).to.be.revertedWith( + 'DelayVaultMigrator: not DelayVaultV1', + ); + }); +}); diff --git a/test/DelayVaultProvider/DelayVaultProvider.ts b/test/DelayVaultProvider/DelayVaultProvider.ts index 9a7d14b2..de3a5e26 100644 --- a/test/DelayVaultProvider/DelayVaultProvider.ts +++ b/test/DelayVaultProvider/DelayVaultProvider.ts @@ -1,3 +1,4 @@ +import { lockDealNft } from '../../typechain-types/contracts'; import { token } from '../helper'; import { delayVault } from './setupTests'; import { expect } from 'chai'; @@ -78,6 +79,7 @@ describe('DelayVault Provider', function () { expect(await delayVault.delayVaultProvider.userToType(delayVault.user4.address)).to.equal(0); const params = [delayVault.tier2]; const owner = delayVault.newOwner; + await delayVault.lockDealNFT.connect(owner).approvePoolTransfers(true); await delayVault.delayVaultProvider.connect(owner).createNewDelayVault(owner.address, params); await expect( delayVault.lockDealNFT diff --git a/test/DelayVaultProvider/setupTests.ts b/test/DelayVaultProvider/setupTests.ts index ae2fa811..4286b3d9 100644 --- a/test/DelayVaultProvider/setupTests.ts +++ b/test/DelayVaultProvider/setupTests.ts @@ -5,8 +5,10 @@ import { DealProvider } from '../../typechain-types'; import { MockProvider } from '../../typechain-types'; import { MockVaultManager } from '../../typechain-types'; import { DelayVaultProvider } from '../../typechain-types'; -import { IDelayVaultData } from '../../typechain-types/contracts/AdvancedProviders/DelayVaultProvider/DelayVaultProvider'; -import { deployed, token, MAX_RATIO, _createUsers } from '../helper'; +import { DelayVaultMigrator } from '../../typechain-types'; +import { MockDelayVault } from '../../typechain-types'; +import { IDelayVaultProvider } from '../../typechain-types/contracts/interfaces/IDelayVaultProvider'; +import { deployed, token, MAX_RATIO, _createUsers, gasLimit } from '../helper'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { BigNumber } from 'ethers'; import { ethers } from 'hardhat'; @@ -16,6 +18,8 @@ export class DelayVault { public lockDealNFT!: LockDealNFT; public timedDealProvider!: TimedDealProvider; public lockProvider!: LockDealProvider; + public delayVaultMigrator!: DelayVaultMigrator; + public mockDelayVault!: MockDelayVault; public dealProvider!: DealProvider; public mockProvider!: MockProvider; public mockVaultManager!: MockVaultManager; @@ -29,12 +33,11 @@ export class DelayVault { public newOwner!: SignerWithAddress; public startTime!: number; public finishTime!: number; - public providerData!: IDelayVaultData.ProviderDataStruct[]; + public providerData!: IDelayVaultProvider.ProviderDataStruct[]; public tier1: BigNumber = ethers.BigNumber.from(250); public tier2: BigNumber = ethers.BigNumber.from(3500); public tier3: BigNumber = ethers.BigNumber.from(20000); public ratio: BigNumber = MAX_RATIO.div(2); - gasLimit: number = 130_000_000; async initialize() { [this.receiver, this.newOwner, this.user1, this.user2, this.user3, this.user4] = await ethers.getSigners(); @@ -44,6 +47,9 @@ export class DelayVault { this.lockProvider = await deployed('LockDealProvider', this.lockDealNFT.address, this.dealProvider.address); this.timedDealProvider = await deployed('TimedDealProvider', this.lockDealNFT.address, this.lockProvider.address); this.mockProvider = await deployed('MockProvider', this.lockDealNFT.address, this.timedDealProvider.address); + const mockDelay = await ethers.getContractFactory('MockDelayVault'); + this.mockDelayVault = await mockDelay.deploy(token, [], []); + this.delayVaultMigrator = await deployed('DelayVaultMigrator', this.lockDealNFT.address, this.mockDelayVault.address); const DelayVaultProvider = await ethers.getContractFactory('DelayVaultProvider'); const ONE_DAY = 86400; const week = ONE_DAY * 7; @@ -54,9 +60,14 @@ export class DelayVault { { provider: this.lockProvider.address, params: [this.startTime], limit: this.tier2 }, { provider: this.timedDealProvider.address, params: [this.startTime, this.finishTime], limit: this.tier3 }, ]; - this.delayVaultProvider = await DelayVaultProvider.deploy(token, this.lockDealNFT.address, this.providerData, { - gasLimit: this.gasLimit, - }); + this.delayVaultProvider = await DelayVaultProvider.deploy( + token, + this.delayVaultMigrator.address, + this.providerData, + { + gasLimit: gasLimit, + }, + ); await this.lockDealNFT.setApprovedContract(this.dealProvider.address, true); await this.lockDealNFT.setApprovedContract(this.lockProvider.address, true); await this.lockDealNFT.setApprovedContract(this.timedDealProvider.address, true); @@ -65,4 +76,4 @@ export class DelayVault { } } -export const delayVault = new DelayVault(); \ No newline at end of file +export const delayVault = new DelayVault(); diff --git a/test/helper.ts b/test/helper.ts index 6b9932f7..8fc7c50f 100644 --- a/test/helper.ts +++ b/test/helper.ts @@ -1,17 +1,18 @@ import { SimpleBuilder } from '../typechain-types'; +import { BuilderState } from '../typechain-types/contracts/Builders/SimpleBuilder/SimpleBuilder'; import { ContractReceipt, utils } from 'ethers'; import { ethers } from 'hardhat'; -import { BuilderState } from '../typechain-types/contracts/Builders/SimpleBuilder/SimpleBuilder'; export const deployed = async (contractName: string, ...args: string[]): Promise => { const Contract = await ethers.getContractFactory(contractName); - const contract = await Contract.deploy(...args); + const contract = await Contract.deploy(...args, { gasLimit: gasLimit }); return contract.deployed() as Promise; }; export const token = '0xCcf41440a137299CB6af95114cb043Ce4e28679A'; export const BUSD = '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56'; export const MAX_RATIO = utils.parseUnits('1', 21); // 100% +export const gasLimit: number = 130_000_000; export function _createUsers(amount: string, userCount: string): BuilderState.BuilderStruct { const pools = []; @@ -32,4 +33,4 @@ export function _logGasPrice(txReceipt: ContractReceipt, userLength: number) { const GREEN_TEXT = '\x1b[32m'; console.log(`${GREEN_TEXT}Gas Used: ${gasUsed.toString()}`); console.log(`Price per one pool: ${gasUsed.div(userLength)}`); -} \ No newline at end of file +}