-
Notifications
You must be signed in to change notification settings - Fork 261
[ETHEREUM-CONTRACTS] allow connecting pools on behalf of members (with some constraints) #2093
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
Changes from 20 commits
ba1b067
f76ce16
62697d9
ab01e42
ea53653
9c433c5
b56c0f3
d6687ab
5dad0c3
882f654
e27cb41
5a0fb64
b856b8a
cd864bd
88e17f3
8db285b
101bdfc
701ea33
4dce3b7
5a603b2
77e3f9d
d3bfd95
d6c9135
2aa5ccd
b4e6342
c195923
bd1d158
c76c167
64484ae
d8ea0dc
79109ec
d578842
dff96ab
c855ecf
e0ca43f
4ca4195
ae36ff0
365b087
5ec58cd
7b2e30f
7aef0ee
cdf0482
9b4da71
283402a
c5fd4d5
088eba3
03b81ba
5652c9d
21da9df
5608475
5a3639d
a8264c0
0d29e7a
1588c53
7935a0e
027a203
2ab51c9
31bf0b3
d182827
ce3c48a
47f155e
4eb4dd0
71918b4
c6cbeb5
5e4332c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ pragma solidity ^0.8.23; | |
|
|
||
| import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; | ||
|
|
||
| import { ISuperfluid, ISuperfluidGovernance } from "../../interfaces/superfluid/ISuperfluid.sol"; | ||
| import { ISuperfluid, ISuperfluidGovernance, IAccessControl } from "../../interfaces/superfluid/ISuperfluid.sol"; | ||
| import { | ||
| BasicParticle, | ||
| PDPoolIndex, | ||
|
|
@@ -48,6 +48,12 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi | |
|
|
||
| address public constant SUPERFLUID_POOL_DEPLOYER_ADDRESS = address(SuperfluidPoolDeployerLibrary); | ||
|
|
||
| // @dev The max number of slots which can be used for connecting pools on behalf of a member (per token) | ||
| uint32 public constant MAX_POOL_AUTO_CONNECT_SLOTS = 4; | ||
|
|
||
| bytes32 constant public ACL_POOL_CONNECT_EXCLUSIVE_ROLE = keccak256("ACL_POOL_CONNECT_EXCLUSIVE_ROLE"); | ||
| bytes32 constant public ACL_POOL_CONNECT_EXCLUSIVE_ROLE_ADMIN = keccak256("ACL_POOL_CONNECT_EXCLUSIVE_ROLE_ADMIN"); | ||
|
|
||
| /// @dev Pool member state slot id for storing subs bitmap | ||
| uint256 private constant _POOL_SUBS_BITMAP_STATE_SLOT_ID = 1; | ||
| /// @dev Pool member state slot id starting point for pool connections | ||
|
|
@@ -89,7 +95,7 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi | |
| for (uint256 i = 0; i < slotIds.length; ++i) { | ||
| address pool = address(uint160(uint256(pidList[i]))); | ||
| _assertPoolConnectivity(token, account, ISuperfluidPool(pool)); | ||
| totalConnectedFromPools += ISuperfluidPool(pool).getClaimable(account, uint32(time)); | ||
| totalConnectedFromPools += SuperfluidPool(pool).getUnsettledValue(account, uint32(time)); | ||
| } | ||
| } | ||
| rtb += totalConnectedFromPools; | ||
|
|
@@ -305,49 +311,100 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi | |
| pool.claimAll(memberAddress); | ||
| } | ||
|
|
||
| // @note setPoolConnection function naming | ||
| function connectPool(ISuperfluidPool pool, bool doConnect, bytes calldata ctx) | ||
| public | ||
| returns (bytes memory newCtx) | ||
| /// @inheritdoc IGeneralDistributionAgreementV1 | ||
| function connectPool(ISuperfluidPool pool, bytes calldata ctx) external override returns (bytes memory newCtx) { | ||
| newCtx = ctx; | ||
| _setPoolConnection(pool, address(0), true, false, ctx); | ||
| } | ||
|
|
||
| /// @inheritdoc IGeneralDistributionAgreementV1 | ||
| function tryConnectPoolFor(ISuperfluidPool pool, address memberAddr, bytes calldata ctx) | ||
| external | ||
| override | ||
| returns (bool success, bytes memory newCtx) | ||
| { | ||
| newCtx = ctx; | ||
|
|
||
| // check if the member has opted out of autoconnect | ||
| IAccessControl simpleACL = ISuperfluid(_host).getSimpleACL(); | ||
| if (simpleACL.hasRole(ACL_POOL_CONNECT_EXCLUSIVE_ROLE, memberAddr)) { | ||
| success = false; | ||
| } else { | ||
| success = _setPoolConnection(pool, memberAddr, true, true, ctx); | ||
| } | ||
| } | ||
|
|
||
| function setConnectPermission(bool allow) external override { | ||
| IAccessControl simpleACL = ISuperfluid(_host).getSimpleACL(); | ||
| if (!allow) { | ||
| simpleACL.grantRole(ACL_POOL_CONNECT_EXCLUSIVE_ROLE, msg.sender); | ||
| } else { | ||
| simpleACL.revokeRole(ACL_POOL_CONNECT_EXCLUSIVE_ROLE, msg.sender); | ||
| } | ||
| } | ||
|
|
||
| /// @inheritdoc IGeneralDistributionAgreementV1 | ||
| function disconnectPool(ISuperfluidPool pool, bytes calldata ctx) external override returns (bytes memory newCtx) { | ||
| newCtx = ctx; | ||
| _setPoolConnection(pool, address(0), false, true /* ignored */, ctx); | ||
| } | ||
|
|
||
| // @note memberAddr has override semantics - if set to address(0), it will be set to the msgSender | ||
| function _setPoolConnection( | ||
| ISuperfluidPool pool, | ||
| address memberAddr, | ||
| bool doConnect, | ||
| bool onlyAutoConnectSlots, | ||
| bytes memory ctx | ||
| ) | ||
| internal | ||
| returns (bool success) | ||
| { | ||
| ISuperfluidToken token = pool.superToken(); | ||
| ISuperfluid.Context memory currentContext = AgreementLibrary.authorizeTokenAccess(token, ctx); | ||
| address msgSender = currentContext.msgSender; | ||
| newCtx = ctx; | ||
| bool isConnected = token.isPoolMemberConnected(this, pool, msgSender); | ||
| if (doConnect != isConnected) { | ||
| assert( | ||
| SuperfluidPool(address(pool)).operatorConnectMember( | ||
| msgSender, doConnect, uint32(currentContext.timestamp) | ||
| ) | ||
| ); | ||
|
|
||
| if (memberAddr == address(0)) { | ||
| memberAddr = currentContext.msgSender; | ||
| } | ||
|
|
||
| bool isConnected = token.isPoolMemberConnected(this, pool, memberAddr); | ||
|
|
||
| if (doConnect != isConnected) { | ||
| if (doConnect) { | ||
| uint32 poolSlotId = | ||
| _findAndFillPoolConnectionsBitmap(token, msgSender, bytes32(uint256(uint160(address(pool))))); | ||
| if (onlyAutoConnectSlots) { | ||
| // check if we're below the slot limit for autoconnect | ||
| (uint32[] memory slotIds, ) = SlotsBitmapLibrary.listData( | ||
d10r marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| token, memberAddr, _POOL_SUBS_BITMAP_STATE_SLOT_ID, _POOL_CONNECTIONS_DATA_STATE_SLOT_ID_START | ||
| ); | ||
| if (slotIds.length >= MAX_POOL_AUTO_CONNECT_SLOTS) { | ||
hellwolf marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return false; | ||
| } | ||
| } | ||
|
|
||
| uint32 poolSlotId = _findAndFillPoolConnectionsBitmap( | ||
| token, memberAddr, bytes32(uint256(uint160(address(pool)))) | ||
| ); | ||
|
|
||
| token.createPoolConnectivity | ||
| (msgSender, GDAv1StorageLib.PoolConnectivity({ slotId: poolSlotId, pool: pool })); | ||
| (memberAddr, GDAv1StorageLib.PoolConnectivity({ slotId: poolSlotId, pool: pool })); | ||
| } else { | ||
| (, GDAv1StorageLib.PoolConnectivity memory poolConnectivity) = | ||
| token.getPoolConnectivity(this, msgSender, pool); | ||
| token.deletePoolConnectivity(msgSender, pool); | ||
| token.getPoolConnectivity(this, memberAddr, pool); | ||
| token.deletePoolConnectivity(memberAddr, pool); | ||
|
|
||
| _clearPoolConnectionsBitmap(token, msgSender, poolConnectivity.slotId); | ||
| _clearPoolConnectionsBitmap(token, memberAddr, poolConnectivity.slotId); | ||
| } | ||
|
|
||
| emit PoolConnectionUpdated(token, pool, msgSender, doConnect, currentContext.userData); | ||
| } | ||
| } | ||
| assert( | ||
| SuperfluidPool(address(pool)).operatorConnectMember( | ||
| memberAddr, doConnect, uint32(currentContext.timestamp) | ||
| ) | ||
| ); | ||
|
|
||
| /// @inheritdoc IGeneralDistributionAgreementV1 | ||
| function connectPool(ISuperfluidPool pool, bytes calldata ctx) external override returns (bytes memory newCtx) { | ||
| return connectPool(pool, true, ctx); | ||
| } | ||
| emit PoolConnectionUpdated(token, pool, memberAddr, doConnect, currentContext.userData); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without adding anything, is there an easy way to know if the connection was an "auto-connect" from event logs?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think there is.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be an issue. An option is to supplement with a new event type. |
||
| } | ||
|
|
||
| /// @inheritdoc IGeneralDistributionAgreementV1 | ||
| function disconnectPool(ISuperfluidPool pool, bytes calldata ctx) external override returns (bytes memory newCtx) { | ||
| return connectPool(pool, false, ctx); | ||
| return true; | ||
| } | ||
|
|
||
| /// @inheritdoc IGeneralDistributionAgreementV1 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
who is the admins of simpleACL??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's still the GH agent, but after deploying this it should be handed over to SF gov or SF gov owner.