@gooddollar/goodcollective-contracts 1.0.6-beta.0b8171a → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +14 -1
  2. package/contracts/DirectPayments/DirectPaymentsFactory.sol +31 -13
  3. package/contracts/DirectPayments/DirectPaymentsPool.sol +25 -9
  4. package/contracts/GoodCollective/GoodCollectiveSuperApp.sol +35 -53
  5. package/contracts/GoodCollective/IGoodCollectiveSuperApp.sol +6 -0
  6. package/contracts/UBI/UBIPool.sol +400 -0
  7. package/contracts/UBI/UBIPoolFactory.sol +168 -0
  8. package/contracts/test/HelperLibraryTest.sol +16 -0
  9. package/contracts/utils/HelperLibrary.sol +77 -11
  10. package/contracts/utils/SwapRouterMock.sol +3 -3
  11. package/package.json +7 -5
  12. package/releases/deployment.json +25493 -306
  13. package/typechain-types/@gooddollar/goodprotocol/contracts/token/index.ts +0 -2
  14. package/typechain-types/@gooddollar/goodprotocol/contracts/token/superfluid/ISuperGoodDollar.sol/ISuperGoodDollar.ts +30 -30
  15. package/typechain-types/@superfluid-finance/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1.ts +122 -0
  16. package/typechain-types/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.ts +30 -30
  17. package/typechain-types/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.ts +7 -2
  18. package/typechain-types/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidGovernance.ts +57 -8
  19. package/typechain-types/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/ISETH.sol/ISETH.ts +2905 -0
  20. package/typechain-types/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/ISETH.sol/ISETHCustom.ts +170 -0
  21. package/typechain-types/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/ISETH.sol/index.ts +5 -0
  22. package/typechain-types/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/index.ts +2 -0
  23. package/typechain-types/@uniswap/index.ts +2 -2
  24. package/typechain-types/@uniswap/{v3-periphery/contracts/interfaces/ISwapRouter.ts → swap-router-contracts/contracts/interfaces/IV3SwapRouter.ts} +32 -44
  25. package/typechain-types/{@gooddollar/goodprotocol/contracts/token/FeesFormula.sol → @uniswap/swap-router-contracts/contracts/interfaces}/index.ts +1 -1
  26. package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.sol/DirectPaymentsFactory.ts +1327 -0
  27. package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.sol/IRegistry.ts +102 -0
  28. package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.sol/index.ts +5 -0
  29. package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.ts +139 -0
  30. package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool.ts +49 -0
  31. package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/IIdentityV2.ts +6 -8
  32. package/typechain-types/contracts/GoodCollective/GoodCollectiveSuperApp.ts +49 -0
  33. package/typechain-types/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IRegistry.ts +102 -0
  34. package/typechain-types/{@uniswap/v3-periphery/contracts/interfaces → contracts/GoodCollective/IGoodCollectiveSuperApp.sol}/index.ts +1 -1
  35. package/typechain-types/contracts/GoodCollective/index.ts +2 -0
  36. package/typechain-types/{@gooddollar/goodprotocol/contracts/token/FeesFormula.sol/IFeesFormula.ts → contracts/UBI/UBIPool.sol/IIdentityV2.ts} +25 -37
  37. package/typechain-types/contracts/UBI/UBIPool.sol/IMembersValidator.ts +125 -0
  38. package/typechain-types/contracts/UBI/UBIPool.sol/UBIPool.ts +2377 -0
  39. package/typechain-types/contracts/UBI/UBIPool.sol/index.ts +6 -0
  40. package/typechain-types/contracts/UBI/UBIPoolFactory.ts +1317 -0
  41. package/typechain-types/contracts/UBI/index.ts +6 -0
  42. package/typechain-types/contracts/index.ts +4 -0
  43. package/typechain-types/contracts/test/HelperLibraryTest.ts +147 -0
  44. package/typechain-types/contracts/test/index.ts +4 -0
  45. package/typechain-types/contracts/utils/SwapRouterMock.ts +15 -21
  46. package/typechain-types/factories/@gooddollar/goodprotocol/contracts/token/index.ts +0 -1
  47. package/typechain-types/factories/@gooddollar/goodprotocol/contracts/token/superfluid/ISuperGoodDollar.sol/ISuperGoodDollar__factory.ts +6 -6
  48. package/typechain-types/factories/@superfluid-finance/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1__factory.ts +78 -0
  49. package/typechain-types/factories/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken__factory.ts +6 -6
  50. package/typechain-types/factories/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidGovernance__factory.ts +23 -5
  51. package/typechain-types/factories/@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid__factory.ts +5 -0
  52. package/typechain-types/factories/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/ISETH.sol/ISETHCustom__factory.ts +59 -0
  53. package/typechain-types/factories/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/ISETH.sol/ISETH__factory.ts +1869 -0
  54. package/typechain-types/factories/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/ISETH.sol/index.ts +5 -0
  55. package/typechain-types/factories/@superfluid-finance/ethereum-contracts/contracts/interfaces/tokens/index.ts +1 -0
  56. package/typechain-types/factories/@uniswap/index.ts +1 -1
  57. package/typechain-types/factories/@uniswap/{v3-periphery/contracts/interfaces/ISwapRouter__factory.ts → swap-router-contracts/contracts/interfaces/IV3SwapRouter__factory.ts} +12 -32
  58. package/typechain-types/factories/{@gooddollar/goodprotocol/contracts/token/FeesFormula.sol → @uniswap/swap-router-contracts/contracts/interfaces}/index.ts +1 -1
  59. package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory.sol/DirectPaymentsFactory__factory.ts +1004 -0
  60. package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory.sol/IRegistry__factory.ts +52 -0
  61. package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory.sol/index.ts +5 -0
  62. package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory__factory.ts +75 -1
  63. package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool__factory.ts +60 -4
  64. package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/IIdentityV2__factory.ts +1 -1
  65. package/typechain-types/factories/contracts/GoodCollective/GoodCollectiveSuperApp__factory.ts +58 -2
  66. package/typechain-types/factories/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/IRegistry__factory.ts +52 -0
  67. package/typechain-types/factories/contracts/GoodCollective/IGoodCollectiveSuperApp.sol/index.ts +4 -0
  68. package/typechain-types/factories/contracts/GoodCollective/index.ts +1 -0
  69. package/typechain-types/factories/contracts/UBI/UBIPool.sol/IIdentityV2__factory.ts +45 -0
  70. package/typechain-types/factories/{@gooddollar/goodprotocol/contracts/token/FeesFormula.sol/IFeesFormula__factory.ts → contracts/UBI/UBIPool.sol/IMembersValidator__factory.ts} +21 -21
  71. package/typechain-types/factories/contracts/UBI/UBIPool.sol/UBIPool__factory.ts +1916 -0
  72. package/typechain-types/factories/contracts/UBI/UBIPool.sol/index.ts +6 -0
  73. package/typechain-types/factories/contracts/UBI/UBIPoolFactory__factory.ts +982 -0
  74. package/typechain-types/factories/contracts/UBI/index.ts +5 -0
  75. package/typechain-types/factories/contracts/index.ts +2 -0
  76. package/typechain-types/factories/contracts/test/HelperLibraryTest__factory.ts +154 -0
  77. package/typechain-types/factories/contracts/test/index.ts +4 -0
  78. package/typechain-types/factories/contracts/utils/HelperLibrary__factory.ts +1 -1
  79. package/typechain-types/factories/contracts/utils/SwapRouterMock__factory.ts +3 -13
  80. package/typechain-types/hardhat.d.ts +80 -17
  81. package/typechain-types/index.ts +16 -4
  82. package/typechain-types/factories/@uniswap/v3-periphery/contracts/interfaces/index.ts +0 -4
  83. /package/typechain-types/@uniswap/{v3-periphery → swap-router-contracts}/contracts/index.ts +0 -0
  84. /package/typechain-types/@uniswap/{v3-periphery → swap-router-contracts}/index.ts +0 -0
  85. /package/typechain-types/factories/@uniswap/{v3-periphery → swap-router-contracts}/contracts/index.ts +0 -0
  86. /package/typechain-types/factories/@uniswap/{v3-periphery → swap-router-contracts}/index.ts +0 -0
package/README.md CHANGED
@@ -1 +1,14 @@
1
- # contracts
1
+ # Contracts
2
+
3
+ ## Structs
4
+
5
+ ### Pool Settings
6
+
7
+ - `nftType`: 1, // when you update the settings with setPoolSettings, `nftType` should always match what has been set when creating the pool
8
+ - `uniquenessValidator`: `ethers.constants.AddressZero`,
9
+ - `rewardPerEvent`: `[100, 300]`,
10
+ - `validEvents`: `[1, 2]`, // to be defined
11
+ - `manager`: `<address of the owner/creator of the pool>`,
12
+ - `membersValidator`: `ethers.constants.AddressZero`, // used to only accept certain members (address zero for anyone can join)
13
+ - `rewardToken`: `'0x62B8B11039FcfE5aB0C56E502b1C372A3d2a9c7A'`, // what token will a steward/member receive. currently only supports production G$'s
14
+ - `allowRewardOverride`: `false`,
@@ -15,6 +15,7 @@ import "hardhat/console.sol";
15
15
 
16
16
  contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
17
17
  error NOT_PROJECT_OWNER();
18
+ error NOT_POOL();
18
19
 
19
20
  event PoolCreated(
20
21
  address indexed pool,
@@ -45,6 +46,9 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
45
46
  address public feeRecipient;
46
47
  uint32 public feeBps;
47
48
 
49
+ mapping(address => address[]) public memberPools;
50
+ address[] public pools;
51
+
48
52
  modifier onlyProjectOwnerOrNon(string memory projectId) {
49
53
  DirectPaymentsPool controlPool = projectIdToControlPool[keccak256(bytes(projectId))];
50
54
  // console.log("result %s", controlPool.hasRole(controlPool.DEFAULT_ADMIN_ROLE(), msg.sender));
@@ -56,16 +60,21 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
56
60
  _;
57
61
  }
58
62
 
59
- modifier onlyProjectOwnerByPool(DirectPaymentsPool pool) {
60
- string memory projectId = registry[address(pool)].projectId;
61
- DirectPaymentsPool controlPool = projectIdToControlPool[keccak256(bytes(projectId))];
62
- if (controlPool.hasRole(controlPool.DEFAULT_ADMIN_ROLE(), msg.sender) == false) {
63
+ modifier onlyPoolOwner(DirectPaymentsPool pool) {
64
+ if (pool.hasRole(pool.DEFAULT_ADMIN_ROLE(), msg.sender) == false) {
63
65
  revert NOT_PROJECT_OWNER();
64
66
  }
65
67
 
66
68
  _;
67
69
  }
68
70
 
71
+ modifier onlyPool() {
72
+ if (bytes(registry[msg.sender].projectId).length == 0) {
73
+ revert NOT_POOL();
74
+ }
75
+ _;
76
+ }
77
+
69
78
  function _authorizeUpgrade(address _impl) internal virtual override onlyRole(DEFAULT_ADMIN_ROLE) {}
70
79
 
71
80
  function initialize(
@@ -113,13 +122,7 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
113
122
  //TODO: add check if msg.sender is whitelisted
114
123
 
115
124
  _settings.nftType = nextNftType;
116
- bytes memory initCall = abi.encodeWithSelector(
117
- DirectPaymentsPool.initialize.selector,
118
- nft,
119
- _settings,
120
- _limits,
121
- address(this)
122
- );
125
+ bytes memory initCall = abi.encodeCall(DirectPaymentsPool.initialize, (nft, _settings, _limits, this));
123
126
 
124
127
  if (useBeacon) {
125
128
  pool = DirectPaymentsPool(address(new BeaconProxy(address(impl), initCall)));
@@ -129,7 +132,6 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
129
132
 
130
133
  nft.grantRole(nft.getManagerRole(nextNftType), _settings.manager);
131
134
  nft.grantRole(nft.getManagerRole(nextNftType), address(pool));
132
- pool.grantRole(pool.MINTER_ROLE(), _settings.manager);
133
135
 
134
136
  //access control to project is determinted by the first pool access control rules
135
137
  if (address(projectIdToControlPool[keccak256(bytes(_projectId))]) == address(0))
@@ -137,13 +139,16 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
137
139
  registry[address(pool)].ipfs = _ipfs;
138
140
  registry[address(pool)].projectId = _projectId;
139
141
 
142
+ pool.grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
140
143
  pool.renounceRole(DEFAULT_ADMIN_ROLE, address(this));
144
+ pools.push(address(pool));
145
+
141
146
  emit PoolCreated(address(pool), _projectId, _ipfs, nextNftType, _settings, _limits);
142
147
 
143
148
  nextNftType++;
144
149
  }
145
150
 
146
- function changePoolDetails(DirectPaymentsPool _pool, string memory _ipfs) external onlyProjectOwnerByPool(_pool) {
151
+ function changePoolDetails(DirectPaymentsPool _pool, string memory _ipfs) external onlyPoolOwner(_pool) {
147
152
  registry[address(_pool)].ipfs = _ipfs;
148
153
  emit PoolDetailsChanged(address(_pool), _ipfs);
149
154
  }
@@ -162,4 +167,17 @@ contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
162
167
  feeBps = _feeBps;
163
168
  feeRecipient = _feeRecipient;
164
169
  }
170
+
171
+ function addMember(address member) external onlyPool {
172
+ memberPools[member].push(msg.sender);
173
+ }
174
+
175
+ function removeMember(address member) external onlyPool {
176
+ for (uint i = 0; i < memberPools[member].length; i++) {
177
+ if (memberPools[member][i] == msg.sender) {
178
+ memberPools[member][i] = memberPools[member][memberPools[member].length - 1];
179
+ memberPools[member].pop();
180
+ }
181
+ }
182
+ }
165
183
  }
@@ -21,7 +21,7 @@ interface IMembersValidator {
21
21
  }
22
22
 
23
23
  interface IIdentityV2 {
24
- function getWhitelistedRoot(address member) external returns (address);
24
+ function getWhitelistedRoot(address member) external view returns (address);
25
25
  }
26
26
 
27
27
  /**
@@ -112,7 +112,7 @@ contract DirectPaymentsPool is
112
112
  DirectPaymentsFactory public registry;
113
113
 
114
114
  /// @custom:oz-upgrades-unsafe-allow constructor
115
- constructor(ISuperfluid _host, ISwapRouter _swapRouter) GoodCollectiveSuperApp(_host, _swapRouter) {}
115
+ constructor(ISuperfluid _host, IV3SwapRouter _swapRouter) GoodCollectiveSuperApp(_host, _swapRouter) {}
116
116
 
117
117
  /**
118
118
  * @dev Authorizes an upgrade for the implementation contract.
@@ -120,8 +120,8 @@ contract DirectPaymentsPool is
120
120
  */
121
121
  function _authorizeUpgrade(address impl) internal virtual override onlyRole(DEFAULT_ADMIN_ROLE) {}
122
122
 
123
- function getRegistry() public view override returns (DirectPaymentsFactory) {
124
- return DirectPaymentsFactory(registry);
123
+ function getRegistry() public view override returns (IRegistry) {
124
+ return IRegistry(address(registry));
125
125
  }
126
126
 
127
127
  /**
@@ -140,8 +140,10 @@ contract DirectPaymentsPool is
140
140
  settings = _settings;
141
141
  limits = _limits;
142
142
  nft = _nft;
143
- _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
144
- _setupRole(DEFAULT_ADMIN_ROLE, _settings.manager);
143
+ _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); // when using factory this gives factory role which then set role to the real msg.sender
144
+ _setupRole(MANAGER_ROLE, _settings.manager);
145
+ _setupRole(MINTER_ROLE, _settings.manager);
146
+
145
147
  setSuperToken(ISuperToken(address(settings.rewardToken)));
146
148
  }
147
149
 
@@ -341,10 +343,24 @@ contract DirectPaymentsPool is
341
343
  }
342
344
  }
343
345
 
344
- _setupRole(MEMBER_ROLE, member);
346
+ _grantRole(MEMBER_ROLE, member);
345
347
  return true;
346
348
  }
347
349
 
350
+ function _grantRole(bytes32 role, address account) internal virtual override {
351
+ if (role == MEMBER_ROLE) {
352
+ registry.addMember(account);
353
+ }
354
+ super._grantRole(role, account);
355
+ }
356
+
357
+ function _revokeRole(bytes32 role, address account) internal virtual override {
358
+ if (role == MEMBER_ROLE) {
359
+ registry.removeMember(account);
360
+ }
361
+ super._revokeRole(role, account);
362
+ }
363
+
348
364
  function mintNFT(address _to, ProvableNFT.NFTData memory _nftData, bool withClaim) external onlyRole(MINTER_ROLE) {
349
365
  uint nftId = nft.mintPermissioned(_to, _nftData, true, "");
350
366
  if (withClaim) {
@@ -384,7 +400,7 @@ contract DirectPaymentsPool is
384
400
  * @dev Sets the safety limits for the pool.
385
401
  * @param _limits The new safety limits.
386
402
  */
387
- function setPoolLimits(SafetyLimits memory _limits) public onlyRole(DEFAULT_ADMIN_ROLE) {
403
+ function setPoolLimits(SafetyLimits memory _limits) public onlyRole(MANAGER_ROLE) {
388
404
  limits = _limits;
389
405
  emit PoolLimitsChanged(_limits);
390
406
  }
@@ -393,7 +409,7 @@ contract DirectPaymentsPool is
393
409
  * @dev Sets the settings for the pool.
394
410
  * @param _settings The new pool settings.
395
411
  */
396
- function setPoolSettings(PoolSettings memory _settings) public onlyRole(DEFAULT_ADMIN_ROLE) {
412
+ function setPoolSettings(PoolSettings memory _settings) public onlyRole(MANAGER_ROLE) {
397
413
  if (_settings.nftType != settings.nftType) revert NFTTYPE_CHANGED();
398
414
  if (_settings.manager == address(0)) revert EMPTY_MANAGER();
399
415
 
@@ -9,13 +9,11 @@ import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/cont
9
9
  import { CFAv1Library, IConstantFlowAgreementV1 } from "@superfluid-finance/ethereum-contracts/contracts/apps/CFAv1Library.sol";
10
10
 
11
11
  import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
12
- import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
12
+ import "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol";
13
13
 
14
14
  import "../DirectPayments/DirectPaymentsFactory.sol";
15
15
  import "../utils/HelperLibrary.sol";
16
16
 
17
- // import "hardhat/console.sol";
18
-
19
17
  abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
20
18
  int96 public constant MIN_FLOW_RATE = 386e9;
21
19
 
@@ -51,7 +49,7 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
51
49
  // ask about "receiver" can it be different then app?
52
50
 
53
51
  /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
54
- ISwapRouter public immutable swapRouter;
52
+ IV3SwapRouter public immutable swapRouter;
55
53
 
56
54
  struct SupporterData {
57
55
  uint256 contribution;
@@ -71,12 +69,12 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
71
69
  uint256[48] private _reserved;
72
70
 
73
71
  /// @custom:oz-upgrades-unsafe-allow constructor
74
- constructor(ISuperfluid _host, ISwapRouter _swapRouter) SuperAppBaseFlow(_host) {
72
+ constructor(ISuperfluid _host, IV3SwapRouter _swapRouter) SuperAppBaseFlow(_host) {
75
73
  if (address(_host) == address(0)) revert ZERO_ADDRESS();
76
74
  swapRouter = _swapRouter;
77
75
  }
78
76
 
79
- function getRegistry() public view virtual returns (DirectPaymentsFactory);
77
+ function getRegistry() public view virtual returns (IRegistry);
80
78
 
81
79
  /**
82
80
  * @dev Sets the address of the super token and registers the app with the host
@@ -160,6 +158,28 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
160
158
  return _ctx;
161
159
  }
162
160
 
161
+ /**
162
+ * @dev allow single contribution. user needs to approve tokens first. can be used in superfluid batch actions.
163
+ * @param _sender The address of the sender who is contributing tokens.
164
+ * @param _customData The SwapData struct containing information about the swap
165
+ * @param _ctx The context of the transaction for superfluid in case this was used in superfluid batch. otherwise can be empty.
166
+ * @return Returns the context of the transaction.
167
+ */
168
+ function supportWithSwap(
169
+ address _sender,
170
+ HelperLibrary.SwapData memory _customData,
171
+ bytes memory _ctx
172
+ ) external onlyHostOrSender(_sender) returns (bytes memory) {
173
+ uint256 balance = superToken.balanceOf(address(this));
174
+ HelperLibrary.handleSwap(swapRouter, _customData, address(superToken), _sender, address(this));
175
+ uint256 amountReceived = superToken.balanceOf(address(this)) - balance;
176
+ if (amountReceived == 0) revert ZERO_AMOUNT();
177
+
178
+ // Update the contribution amount for the sender in the supporters mapping
179
+ _updateSupporter(_sender, int256(amountReceived), 0, ""); //we pass empty ctx since this is not a flow but a single donation
180
+ return _ctx;
181
+ }
182
+
163
183
  /**
164
184
  * @dev Handles the swap of tokens using the SwapData struct
165
185
  * @param _customData The SwapData struct containing information about the swap
@@ -247,7 +267,7 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
247
267
  ) internal returns (bytes memory newCtx) {
248
268
  newCtx = _ctx;
249
269
  bool _isFlow = _ctx.length > 0;
250
- _updateStats(_isFlow ? 0 : uint256(_previousFlowRateOrAmount));
270
+ HelperLibrary.updateStats(stats, superToken, getRegistry(), _isFlow ? 0 : uint256(_previousFlowRateOrAmount));
251
271
  // Get the current flow rate for the supporter
252
272
  int96 flowRate = superToken.getFlowRate(_supporter, address(this));
253
273
  uint256 prevContribution = supporters[_supporter].contribution;
@@ -260,7 +280,14 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
260
280
  supporters[_supporter].contribution +=
261
281
  uint96(int96(_previousFlowRateOrAmount)) *
262
282
  (block.timestamp - _lastUpdated);
263
- newCtx = _takeFeeFlow(flowRate - int96(_previousFlowRateOrAmount), _ctx);
283
+ newCtx = HelperLibrary.takeFeeFlow(
284
+ cfaV1,
285
+ stats,
286
+ superToken,
287
+ getRegistry(),
288
+ flowRate - int96(_previousFlowRateOrAmount),
289
+ _ctx
290
+ );
264
291
  // we update the last rate after we do all changes to our own flows
265
292
  stats.lastIncomeRate = superToken.getNetFlowRate(address(this));
266
293
  } else {
@@ -278,51 +305,6 @@ abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow {
278
305
  );
279
306
  }
280
307
 
281
- // this should be called before any flow rate changes
282
- function _updateStats(uint256 _amount) internal {
283
- //use last rate before the current possible rate update
284
- stats.netIncome += uint96(stats.lastIncomeRate) * (block.timestamp - stats.lastUpdate);
285
- uint feeBps;
286
- if (address(getRegistry()) != address(0)) {
287
- feeBps = getRegistry().feeBps();
288
- //fees sent to last recipient, the flowRate to recipient still wasnt updated.
289
- stats.totalFees +=
290
- uint96(superToken.getFlowRate(address(this), stats.lastFeeRecipient)) *
291
- (block.timestamp - stats.lastUpdate);
292
- }
293
- if (_amount > 0) {
294
- stats.netIncome += (_amount * (10000 - feeBps)) / 10000;
295
- stats.totalFees += (_amount * feeBps) / 10000;
296
- }
297
- stats.lastUpdate = block.timestamp;
298
- }
299
-
300
- function _takeFeeFlow(int96 _diffRate, bytes memory _ctx) internal returns (bytes memory newCtx) {
301
- newCtx = _ctx;
302
- if (address(getRegistry()) == address(0)) return newCtx;
303
- address recipient = getRegistry().feeRecipient();
304
- int96 curFeeRate = superToken.getFlowRate(address(this), stats.lastFeeRecipient);
305
- bool newRecipient;
306
- if (recipient != stats.lastFeeRecipient) {
307
- newRecipient = true;
308
- if (stats.lastFeeRecipient != address(0)) {
309
- //delete old recipient flow
310
- if (curFeeRate > 0)
311
- newCtx = cfaV1.deleteFlowWithCtx(newCtx, address(this), stats.lastFeeRecipient, superToken); //passing in the ctx which is sent to the callback here
312
- }
313
- stats.lastFeeRecipient = recipient;
314
- }
315
- if (recipient == address(0)) return newCtx;
316
-
317
- int96 feeRateChange = (_diffRate * int32(getRegistry().feeBps())) / 10000;
318
- int96 newFeeRate = curFeeRate + feeRateChange;
319
- if (newFeeRate <= 0 && newRecipient == false) {
320
- newCtx = cfaV1.deleteFlowWithCtx(newCtx, address(this), recipient, superToken); //passing in the ctx which is sent to the callback here
321
- } else if (curFeeRate > 0 && newRecipient == false) {
322
- newCtx = cfaV1.updateFlowWithCtx(newCtx, recipient, superToken, newFeeRate); //passing in the ctx which is sent to the callback here
323
- } else if (newFeeRate > 0) newCtx = cfaV1.createFlowWithCtx(newCtx, recipient, superToken, newFeeRate); //passing in the ctx which is sent to the callback here
324
- }
325
-
326
308
  function _takeFeeSingle(uint256 _amount) internal {
327
309
  if (address(getRegistry()) == address(0)) return;
328
310
  address recipient = getRegistry().feeRecipient();
@@ -1,6 +1,12 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity >=0.8.0;
3
3
 
4
+ interface IRegistry {
5
+ function feeRecipient() external view returns (address);
6
+
7
+ function feeBps() external view returns (uint32);
8
+ }
9
+
4
10
  interface IGoodCollectiveSuperApp {
5
11
  struct Stats {
6
12
  uint256 netIncome; //without fees