Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

immutable withdraw + split #428

Merged
merged 20 commits into from
Mar 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions contracts/SimpleProviders/DealProvider/DealProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,15 @@ contract DealProvider is DealProviderState, BasicProvider {
}

/// @dev Splits a pool into two pools. Used by the LockedDealNFT contract or Provider
function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override firewallProtected onlyProvider {
uint256 splitAmount = poolIdToAmount[oldPoolId].calcAmount(ratio);
require(poolIdToAmount[oldPoolId] >= splitAmount, "Split amount exceeds the available amount");
poolIdToAmount[oldPoolId] -= splitAmount;
function split(uint256 lockDealNFTPoolId, uint256 newPoolId, uint256 ratio) external override firewallProtected onlyProvider {
uint256 splitAmount = poolIdToAmount[lockDealNFTPoolId].calcAmount(ratio);
require(poolIdToAmount[lockDealNFTPoolId] >= splitAmount, "Split amount exceeds the available amount");
poolIdToAmount[newPoolId] = splitAmount;
// save leftAmount to the newly created pool from the old pool
uint256 copyOldPoolId = _mintNewNFT(lockDealNFTPoolId, lockDealNFT.ownerOf(newPoolId));
poolIdToAmount[copyOldPoolId] = poolIdToAmount[lockDealNFTPoolId] - splitAmount;
// set to 0 to finalize the pool
poolIdToAmount[lockDealNFTPoolId] = 0;
}

/**@dev Providers overrides this function to add additional parameters when creating a pool.
Expand All @@ -51,4 +55,19 @@ contract DealProvider is DealProviderState, BasicProvider {
function getWithdrawableAmount(uint256 poolId) public view override returns (uint256) {
return poolIdToAmount[poolId];
}

/// @dev creates a new NFT and clones the vault id from the source pool id.
/// @param sourcePoolId The ID of the source pool.
/// @param to The address of the NFT owner.
/// @return newPoolId The ID of the newly created pool.
/// 0x21de57c4 - represents bytes4(keccak256("_mintNewNFT(uint256,address)"))
function _mintNewNFT(
uint256 sourcePoolId,
address to
) internal firewallProtectedSig(0x21de57c4) returns (uint256 newPoolId) {
IProvider sourceProvider = lockDealNFT.poolIdToProvider(sourcePoolId);
newPoolId = lockDealNFT.mintForProvider(to, sourceProvider);
// clone vault id
lockDealNFT.cloneVaultId(newPoolId, sourcePoolId);
}
}
8 changes: 5 additions & 3 deletions contracts/SimpleProviders/LockProvider/LockDealProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ contract LockDealProvider is BasicProvider, LockDealState {
(withdrawnAmount, isFinal) = provider.withdraw(poolId, amount > withdrawnAmount ? withdrawnAmount : amount);
}

function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external override firewallProtected onlyProvider {
provider.split(oldPoolId, newPoolId, ratio);
poolIdToTime[newPoolId] = poolIdToTime[oldPoolId];
function split(uint256 lockDealNFTPoolId, uint256 newPoolId, uint256 ratio) external override firewallProtected onlyProvider {
provider.split(lockDealNFTPoolId, newPoolId, ratio);
poolIdToTime[newPoolId] = poolIdToTime[lockDealNFTPoolId];
// save startTime to the newly created pool from the old pool
poolIdToTime[newPoolId + 1] = poolIdToTime[lockDealNFTPoolId];
}

function currentParamsTargetLength() public view override(IProvider, ProviderState) returns (uint256) {
Expand Down
62 changes: 54 additions & 8 deletions contracts/SimpleProviders/TimedDealProvider/TimedDealProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import "../LockProvider/LockDealState.sol";
import "../DealProvider/DealProviderState.sol";
import "../Provider/BasicProvider.sol";
import "@poolzfinance/poolz-helper-v2/contracts/CalcUtils.sol";
import "@poolzfinance/poolz-helper-v2/contracts/LastPoolOwnerState.sol";

contract TimedDealProvider is LockDealState, DealProviderState, BasicProvider {
contract TimedDealProvider is LockDealState, DealProviderState, BasicProvider, LastPoolOwnerState {
using CalcUtils for uint256;

/**
Expand All @@ -20,12 +21,34 @@ contract TimedDealProvider is LockDealState, DealProviderState, BasicProvider {
lockDealNFT = _lockDealNFT;
name = "TimedDealProvider";
}

function _withdraw(
uint256 poolId,
uint256 amount
) internal override firewallProtectedSig(0x9e2bf22c) returns (uint256 withdrawnAmount, bool isFinal) {
(withdrawnAmount, isFinal) = provider.withdraw(poolId, amount);
if (amount == 0) return (0, false);
isFinal = true;
withdrawnAmount = amount;
uint256[] memory params = provider.getParams(poolId);
uint256 remainingAmount = params[0] - amount;
if (remainingAmount > 0 && lastPoolOwner[poolId] != address(0)) {
// create immutable NFT
uint256 newPoolId = lockDealNFT.mintForProvider(
lastPoolOwner[poolId],
lockDealNFT.poolIdToProvider(poolId)
);
// clone vault id
lockDealNFT.cloneVaultId(newPoolId, poolId);
// register new pool
params[0] = remainingAmount;
provider.registerPool(newPoolId, params);
poolIdToTime[newPoolId] = poolIdToTime[poolId];
poolIdToAmount[newPoolId] = poolIdToAmount[poolId];
delete lastPoolOwner[poolId];
}
// Reset and update the original pool
params[0] = 0;
provider.registerPool(poolId, params);
}

function getWithdrawableAmount(uint256 poolId) public view override returns (uint256) {
Expand All @@ -44,12 +67,14 @@ contract TimedDealProvider is LockDealState, DealProviderState, BasicProvider {
return debitableAmount - (startAmount - leftAmount);
}

function split(uint256 oldPoolId, uint256 newPoolId, uint256 ratio) external firewallProtected onlyProvider {
provider.split(oldPoolId, newPoolId, ratio);
uint256 newPoolStartAmount = poolIdToAmount[oldPoolId].calcAmount(ratio);
poolIdToAmount[oldPoolId] -= newPoolStartAmount;
function split(uint256 lockDealNFTPoolId, uint256 newPoolId, uint256 ratio) external firewallProtected onlyProvider {
provider.split(lockDealNFTPoolId, newPoolId, ratio);
uint256 newPoolStartAmount = poolIdToAmount[lockDealNFTPoolId].calcAmount(ratio);
poolIdToAmount[newPoolId] = newPoolStartAmount;
poolIdToTime[newPoolId] = poolIdToTime[oldPoolId];
poolIdToTime[newPoolId] = poolIdToTime[lockDealNFTPoolId];
// save startAmount and FinishTime to the newly created pool from the old pool
poolIdToAmount[newPoolId + 1] = poolIdToAmount[lockDealNFTPoolId] - newPoolStartAmount;
poolIdToTime[newPoolId + 1] = poolIdToTime[lockDealNFTPoolId];
}

///@param params[0] = leftAmount = startAmount (leftAmount & startAmount must be same while creating pool)
Expand All @@ -76,4 +101,25 @@ contract TimedDealProvider is LockDealState, DealProviderState, BasicProvider {
function currentParamsTargetLength() public view override(IProvider, ProviderState) returns (uint256) {
return 1 + provider.currentParamsTargetLength();
}

/**
* @dev Executes before a transfer, updating state based on the transfer details.
* @param from Sender address.
* @param to Receiver address.
* @param poolId Pool identifier.
*/
function beforeTransfer(
address from,
address to,
uint256 poolId
) external virtual override firewallProtected 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
}
}

function supportsInterface(bytes4 interfaceId) public view virtual override(BasicProvider, LastPoolOwnerState) returns (bool) {
return BasicProvider.supportsInterface(interfaceId) || LastPoolOwnerState.supportsInterface(interfaceId);
}
}
3 changes: 2 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ const config: HardhatUserConfig = {
{
version: '0.8.25',
settings: {
evmVersion: 'istanbul',
evmVersion: 'cancun',
optimizer: {
enabled: true,
runs: 200,
},
viaIR: true,
},
},
],
Expand Down
Loading