diff --git a/contracts/instance/module/IComponents.sol b/contracts/instance/module/IComponents.sol index b174184cb..f53c9b8d4 100644 --- a/contracts/instance/module/IComponents.sol +++ b/contracts/instance/module/IComponents.sol @@ -43,8 +43,5 @@ interface IComponents { bool isVerifyingApplications; // underwriting requires the pool component checks/confirms the applications UFixed collateralizationLevel; // factor to calculate collateral for sum insurance (default 100%) UFixed retentionLevel; // amount of collateral held in pool (default 100%) - Fee poolFee; // pool fee on net premium - Fee stakingFee; // pool fee on staked capital from investor - Fee performanceFee; // pool fee on profits from capital investors } } diff --git a/contracts/pool/IPoolService.sol b/contracts/pool/IPoolService.sol index c13784e44..2bc17b87e 100644 --- a/contracts/pool/IPoolService.sol +++ b/contracts/pool/IPoolService.sol @@ -40,14 +40,6 @@ interface IPoolService is IService { /// @dev sets the max capital amount for the calling pool function setMaxCapitalAmount(Amount maxCapitalAmount) external; - /// @dev set pool sepecific fees - function setFees( - Fee memory poolFee, - Fee memory stakingFee, - Fee memory performanceFee - ) external; - - /// @dev locks required collateral to cover the specified application (and turn it into a policy) /// - retention level == 1: the full collateral amount will be locked by the specified bundle /// - retention level < 1: a part of the coverage is provided by the specified bundle, the rest by the pool component @@ -102,8 +94,7 @@ interface IPoolService is IService { bytes calldata filter // optional use case specific criteria that define if a policy may be covered by this bundle ) external - returns(NftId bundleNftId); // the nft id of the newly created bundle - // TODO: return netAmount + returns(NftId bundleNftId, Amount netStakedAmount); // the nft id of the newly created bundle /// @dev closes the specified bundle diff --git a/contracts/pool/Pool.sol b/contracts/pool/Pool.sol index 0658120bb..d2244e05e 100644 --- a/contracts/pool/Pool.sol +++ b/contracts/pool/Pool.sol @@ -120,10 +120,7 @@ abstract contract Pool is false, // isExternallyManaged, false, // isVerifyingApplications, UFixedLib.toUFixed(1), // collateralizationLevel, - UFixedLib.toUFixed(1), // retentionLevel, - FeeLib.zero(), // initialPoolFee, - FeeLib.zero(), // initialStakingFee, - FeeLib.zero() // initialPerformanceFee, + UFixedLib.toUFixed(1) // retentionLevel, ); } @@ -299,9 +296,9 @@ abstract contract Pool is bytes memory filter ) internal - returns(NftId bundleNftId) + returns(NftId bundleNftId, Amount netStakedAmount) { - bundleNftId = _getPoolStorage()._poolService.createBundle( + (bundleNftId, netStakedAmount) = _getPoolStorage()._poolService.createBundle( bundleOwner, fee, amount, diff --git a/contracts/pool/PoolService.sol b/contracts/pool/PoolService.sol index dba304385..81c46f7fa 100644 --- a/contracts/pool/PoolService.sol +++ b/contracts/pool/PoolService.sol @@ -109,27 +109,6 @@ contract PoolService is emit LogPoolServiceBundleOwnerRoleSet(poolNftId, bundleOwnerRole); } - - function setFees( - Fee memory poolFee, - Fee memory stakingFee, - Fee memory performanceFee - ) - external - virtual - { - (NftId poolNftId,, IInstance instance) = _getAndVerifyActiveComponent(POOL()); - - IComponents.PoolInfo memory poolInfo = instance.getInstanceReader().getPoolInfo(poolNftId); - poolInfo.poolFee = poolFee; - poolInfo.stakingFee = stakingFee; - poolInfo.performanceFee = performanceFee; - - instance.getInstanceStore().updatePool(poolNftId, poolInfo, KEEP_STATE()); - - // TODO add logging - } - /// @inheritdoc IPoolService function createBundle( address bundleOwner, // initial bundle owner @@ -140,16 +119,13 @@ contract PoolService is ) external virtual - returns(NftId bundleNftId) + returns(NftId bundleNftId, Amount netStakedAmount) { (NftId poolNftId,, IInstance instance) = _getAndVerifyActiveComponent(POOL()); - InstanceReader instanceReader = instance.getInstanceReader(); - - ( - Amount stakingFeeAmount, - Amount stakingNetAmount - ) = FeeLib.calculateFee( - _getStakingFee(instanceReader, poolNftId), + + Amount stakingFeeAmount; + (stakingFeeAmount, netStakedAmount) = FeeLib.calculateFee( + _getStakingFee(instance.getInstanceReader(), poolNftId), stakingAmount); // TODO: staking amount must be be > maxCapitalAmount @@ -159,7 +135,7 @@ contract PoolService is poolNftId, bundleOwner, fee, - stakingNetAmount, + netStakedAmount, lifetime, filter); @@ -167,12 +143,12 @@ contract PoolService is _componentService.increasePoolBalance( instance.getInstanceStore(), poolNftId, - stakingNetAmount, + netStakedAmount, stakingFeeAmount); // pool bookkeeping and collect tokens from bundle owner _collectStakingAmount( - instanceReader, + instance.getInstanceReader(), poolNftId, bundleOwner, stakingAmount); @@ -312,16 +288,6 @@ contract PoolService is return unstakedAmount; } - function _getPerformanceFee(InstanceReader instanceReader, NftId poolNftId) - internal - virtual - view - returns (Fee memory performanceFee) - { - NftId productNftId = instanceReader.getComponentInfo(poolNftId).productNftId; - return instanceReader.getPoolInfo(productNftId).performanceFee; - } - function processSale( NftId bundleNftId, IPolicy.Premium memory premium diff --git a/test/TestBundle.t.sol b/test/TestBundle.t.sol index 7bf26435f..8377fa49a 100644 --- a/test/TestBundle.t.sol +++ b/test/TestBundle.t.sol @@ -39,7 +39,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 2000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -93,7 +93,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 1000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -127,7 +127,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 2000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -156,7 +156,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 2000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -192,7 +192,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 2000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -227,7 +227,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 2000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -278,7 +278,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 2000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -330,7 +330,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 2000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -362,7 +362,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 2000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -391,7 +391,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 2000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -432,7 +432,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 1000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -472,7 +472,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 1000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -511,7 +511,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 1000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, @@ -543,7 +543,7 @@ contract TestBundle is GifTest { token.approve(address(pool.getTokenHandler()), 1000); Seconds lifetime = SecondsLib.toSeconds(0); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 1000, lifetime, diff --git a/test/TestPool.t.sol b/test/TestPool.t.sol index 9b3e40cd9..ed291ce78 100644 --- a/test/TestPool.t.sol +++ b/test/TestPool.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.20; import {console} from "../lib/forge-std/src/Test.sol"; +import {Amount, AmountLib} from "../contracts/type/Amount.sol"; import {BasicPoolAuthorization} from "../contracts/pool/BasicPoolAuthorization.sol"; import {Fee, FeeLib} from "../contracts/type/Fee.sol"; import {IBundle} from "../contracts/instance/module/IBundle.sol"; @@ -105,17 +106,6 @@ contract TestPool is GifTest { assertTrue(componentInfo.productNftId.eqz(), "product nft not zero (not yet linked to product)"); assertEq(poolInfo.bundleOwnerRole.toInt(), PUBLIC_ROLE().toInt(), "unexpected bundle owner role"); - // check fees - Fee memory poolFee = poolInfo.poolFee; - Fee memory stakingFee = poolInfo.stakingFee; - Fee memory performanceFee = poolInfo.performanceFee; - assertEq(poolFee.fractionalFee.toInt(), 0, "pool fee not 0"); - assertEq(poolFee.fixedFee, 0, "pool fee not 0"); - assertEq(stakingFee.fractionalFee.toInt(), 0, "staking fee not 0"); - assertEq(stakingFee.fixedFee, 0, "staking fee not 0"); - assertEq(performanceFee.fractionalFee.toInt(), 0, "performance fee not 0"); - assertEq(performanceFee.fixedFee, 0, "performance fee not 0"); - // check pool balance assertTrue(instanceReader.getBalanceAmount(poolNftId).eqz(), "initial pool balance not zero"); assertTrue(instanceReader.getFeeAmount(poolNftId).eqz(), "initial pool fee not zero"); @@ -174,7 +164,8 @@ contract TestPool is GifTest { token.approve(address(pool.getTokenHandler()), 10000); Seconds lifetime = SecondsLib.toSeconds(604800); - bundleNftId = pool.createBundle( + uint256 netStakedAmount; + (bundleNftId, netStakedAmount) = pool.createBundle( FeeLib.zero(), 10000, lifetime, @@ -184,9 +175,15 @@ contract TestPool is GifTest { // THEN assertTrue(!bundleNftId.eqz(), "bundle nft id is zero"); + assertEq(netStakedAmount, 10000, "net staked amount not 10000"); + + assertEq(token.balanceOf(poolOwner), 0, "pool owner token balance not 0"); + assertEq(token.balanceOf(componentInfo.wallet), 10000, "pool wallet token balance not 10000"); - assertEq(token.balanceOf(poolOwner), 0, "pool owner balance not 0"); - assertEq(token.balanceOf(componentInfo.wallet), 10000, "pool wallet balance not 10000"); + assertEq(instanceReader.getBalanceAmount(poolNftId).toInt(), 10000, "pool balance not 10000"); + assertEq(instanceReader.getFeeAmount(poolNftId).toInt(), 0, "pool fee not 0"); + assertEq(instanceReader.getBalanceAmount(bundleNftId).toInt(), 10000, "bundle balance not 10000"); + assertEq(instanceReader.getFeeAmount(bundleNftId).toInt(), 0, "bundle fee not 0"); assertEq(instanceBundleSet.bundles(poolNftId), 1, "expected only 1 bundle"); assertEq(instanceBundleSet.getBundleNftId(poolNftId, 0).toInt(), bundleNftId.toInt(), "bundle nft id in bundle manager not equal to bundle nft id"); @@ -204,6 +201,42 @@ contract TestPool is GifTest { "unexpected activatedAt"); } + function test_PoolCreateBundle_withStakingFee() public { + // GIVEN + initialStakingFee = FeeLib.percentageFee(10); + _prepareProduct(false); + _fundInvestor(); + + IComponents.ComponentInfo memory componentInfo = instanceReader.getComponentInfo(poolNftId); + + // WHEN + // SimplePool spool = SimplePool(address(pool)); + vm.startPrank(investor); + token.approve(address(pool.getTokenHandler()), 10000); + + Seconds lifetime = SecondsLib.toSeconds(604800); + uint256 netStakedAmount; + (bundleNftId, netStakedAmount) = pool.createBundle( + FeeLib.zero(), + 10000, + lifetime, + "" + ); + vm.stopPrank(); + + // THEN + assertTrue(!bundleNftId.eqz(), "bundle nft id is zero"); + assertEq(netStakedAmount, 9000, "net staked amount not 9000"); + + assertEq(token.balanceOf(poolOwner), 0, "pool owner token balance not 0"); + assertEq(token.balanceOf(componentInfo.wallet), 10000, "pool wallet token balance not 10000"); + + assertEq(instanceReader.getBalanceAmount(poolNftId).toInt(), 10000, "pool balance not 10000"); + assertEq(instanceReader.getFeeAmount(poolNftId).toInt(), 1000, "pool fee not 0"); + assertEq(instanceReader.getBalanceAmount(bundleNftId).toInt(), 9000, "bundle balance not 10000"); + assertEq(instanceReader.getFeeAmount(bundleNftId).toInt(), 0, "bundle fee not 0"); + } + function test_PoolBundleInitialState() public { // GIVEN @@ -330,7 +363,7 @@ contract TestPool is GifTest { IComponents.ComponentInfo memory componentInfo = instanceReader.getComponentInfo(poolNftId); token.approve(address(componentInfo.tokenHandler), 10000); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), 10000, SecondsLib.toSeconds(604800), diff --git a/test/TestProduct.t.sol b/test/TestProduct.t.sol index 0a20ccaa9..3af8c55e3 100644 --- a/test/TestProduct.t.sol +++ b/test/TestProduct.t.sol @@ -931,7 +931,7 @@ contract TestProduct is GifTest { token.approve(address(componentInfo.tokenHandler), bundleCapital); Fee memory bundleFee = FeeLib.toFee(UFixedLib.zero(), 10); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( bundleFee, bundleCapital, SecondsLib.toSeconds(604800), diff --git a/test/base/GifTest.sol b/test/base/GifTest.sol index 3678710e0..7522eb70a 100644 --- a/test/base/GifTest.sol +++ b/test/base/GifTest.sol @@ -486,7 +486,7 @@ contract GifTest is GifDeployer { IComponents.ComponentInfo memory poolComponentInfo = instanceReader.getComponentInfo(poolNftId); token.approve(address(poolComponentInfo.tokenHandler), DEFAULT_BUNDLE_CAPITALIZATION * 10**token.decimals()); - bundleNftId = SimplePool(address(pool)).createBundle( + (bundleNftId,) = SimplePool(address(pool)).createBundle( FeeLib.zero(), DEFAULT_BUNDLE_CAPITALIZATION * 10**token.decimals(), SecondsLib.toSeconds(DEFAULT_BUNDLE_LIFETIME), diff --git a/test/component/distribution/Referral.t.sol b/test/component/distribution/Referral.t.sol index f0a75abb4..825e89adf 100644 --- a/test/component/distribution/Referral.t.sol +++ b/test/component/distribution/Referral.t.sol @@ -306,7 +306,7 @@ contract ReferralTest is ReferralTestBase { token.approve(address(poolInfo.tokenHandler), bundleAmount); // SimplePool spool = SimplePool(address(pool)); - bundleNftId = pool.createBundle( + (bundleNftId,) = pool.createBundle( FeeLib.zero(), bundleAmount, SecondsLib.toSeconds(604800), diff --git a/test/component/product/ProductPayout.t.sol b/test/component/product/ProductPayout.t.sol index fb430fe20..d02440e73 100644 --- a/test/component/product/ProductPayout.t.sol +++ b/test/component/product/ProductPayout.t.sol @@ -906,7 +906,7 @@ contract TestProductClaim is GifTest { token.approve(address(poolComponentInfo.tokenHandler), BUNDLE_CAPITAL); // SimplePool spool = SimplePool(address(pool)); - bundleNftId = SimplePool(address(pool)).createBundle( + (bundleNftId,) = SimplePool(address(pool)).createBundle( FeeLib.zero(), BUNDLE_CAPITAL, SecondsLib.toSeconds(604800), diff --git a/test/instance/service/TestPricingService.t.sol b/test/instance/service/TestPricingService.t.sol index e54d513d0..92f132f83 100644 --- a/test/instance/service/TestPricingService.t.sol +++ b/test/instance/service/TestPricingService.t.sol @@ -387,7 +387,7 @@ contract TestPricingService is GifTest { address(instanceReader.getComponentInfo(poolNftId).tokenHandler), 10000); - bundleNftId = pool.createBundle( + (bundleNftId, ) = pool.createBundle( bundleFee, 10000, SecondsLib.toSeconds(604800), diff --git a/test/mock/SimplePool.sol b/test/mock/SimplePool.sol index 9b8d5f249..f93bf100a 100644 --- a/test/mock/SimplePool.sol +++ b/test/mock/SimplePool.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {AmountLib} from "../../contracts/type/Amount.sol"; +import {Amount, AmountLib} from "../../contracts/type/Amount.sol"; import {BasicPool} from "../../contracts/pool/BasicPool.sol"; import {BasicPoolAuthorization} from "../../contracts/pool/BasicPoolAuthorization.sol"; import {Fee} from "../../contracts/type/Fee.sol"; @@ -59,16 +59,18 @@ contract SimplePool is ) external virtual - returns(NftId bundleNftId) + returns(NftId bundleNftId, uint256 netStakedAmountInt) { address owner = msg.sender; - bundleNftId = _createBundle( + Amount netStakedAmount; + (bundleNftId, netStakedAmount) = _createBundle( owner, fee, AmountLib.toAmount(initialAmount), lifetime, filter ); + netStakedAmountInt = netStakedAmount.toInt(); } } \ No newline at end of file