feat: Vote delegation is profile to address operation

This commit is contained in:
donosonaumczuk
2022-11-23 23:54:48 +00:00
parent b480cd1d10
commit 1fc8f90565
3 changed files with 41 additions and 55 deletions

View File

@@ -47,7 +47,8 @@ contract FollowNFT is HubRestricted, LensNFTBase, IFollowNFT {
uint16 internal constant BASIS_POINTS = 10000;
mapping(address => mapping(uint256 => Snapshot)) internal _snapshots;
mapping(address => address) internal _delegates;
// TODO: Check that nobody has used this feature before doing this mapping modifiation, otherwise use new slot.
mapping(uint256 => address) internal _delegates;
mapping(address => uint256) internal _snapshotCount;
mapping(uint256 => Snapshot) internal _delSupplySnapshots;
uint256 internal _delSupplySnapshotCount;
@@ -178,6 +179,7 @@ contract FollowNFT is HubRestricted, LensNFTBase, IFollowNFT {
if (currentFollower != 0) {
// As it has a follower, unfollow first.
_followIdByFollowerId[currentFollower] = 0;
_delegate(currentFollower, address(0));
ILensHub(HUB).emitUnfollowedEvent(
currentFollower,
_followedProfileId,
@@ -441,34 +443,44 @@ contract FollowNFT is HubRestricted, LensNFTBase, IFollowNFT {
}
/// @inheritdoc IFollowNFT
function delegate(address delegatee) external override {
_delegate(msg.sender, delegatee);
function delegate(uint256 delegatorProfile, address delegatee) external override {
if (_followIdByFollowerId[delegatorProfile] == 0) {
revert NotFollowing();
}
if (msg.sender != IERC721(HUB).ownerOf(delegatorProfile)) {
revert Errors.NotProfileOwner();
}
_delegate(delegatorProfile, delegatee);
}
/// @inheritdoc IFollowNFT
function delegateBySig(
address delegator,
uint256 delegatorProfile,
address delegatee,
DataTypes.EIP712Signature calldata sig
) external override {
if (_followIdByFollowerId[delegatorProfile] == 0) {
revert NotFollowing();
}
address delegatorOwner = IERC721(HUB).ownerOf(delegatorProfile);
unchecked {
MetaTxHelpers._validateRecoveredAddress(
_calculateDigest(
keccak256(
abi.encode(
DELEGATE_BY_SIG_TYPEHASH,
delegator,
delegatorProfile,
delegatee,
sigNonces[delegator]++,
sigNonces[delegatorOwner]++,
sig.deadline
)
)
),
delegator,
delegatorOwner,
sig
);
}
_delegate(delegator, delegatee);
_delegate(delegatorProfile, delegatee);
}
/// @inheritdoc IFollowNFT
@@ -522,6 +534,7 @@ contract FollowNFT is HubRestricted, LensNFTBase, IFollowNFT {
}
function _unfollow(uint256 unfollower, uint256 followId) internal {
_delegate(unfollower, address(0));
delete _followIdByFollowerId[unfollower];
delete _followDataByFollowId[followId];
unchecked {
@@ -577,12 +590,7 @@ contract FollowNFT is HubRestricted, LensNFTBase, IFollowNFT {
address to,
uint256 tokenId
) internal override {
address fromDelegatee = _delegates[from];
address toDelegatee = _delegates[to];
address followModule = ILensHub(HUB).getFollowModule(_followedProfileId);
_moveDelegate(fromDelegatee, toDelegatee, 1);
super._beforeTokenTransfer(from, to, tokenId);
ILensHub(HUB).emitFollowNFTTransferEvent(_followedProfileId, tokenId, from, to);
if (followModule != address(0)) {
@@ -625,48 +633,39 @@ contract FollowNFT is HubRestricted, LensNFTBase, IFollowNFT {
}
}
function _delegate(address delegator, address delegatee) internal {
uint256 delegatorBalance = balanceOf(delegator); // TODO: This is only getting the wrapped tokens balance
address previousDelegate = _delegates[delegator];
_delegates[delegator] = delegatee;
_moveDelegate(previousDelegate, delegatee, delegatorBalance);
function _delegate(uint256 delegatorProfile, address delegatee) internal {
address previousDelegate = _delegates[delegatorProfile];
if (previousDelegate != delegatee) {
_delegates[delegatorProfile] = delegatee;
_moveDelegate(previousDelegate, delegatee);
}
}
function _moveDelegate(
address from,
address to,
uint256 amount
) internal {
function _moveDelegate(address from, address to) internal {
unchecked {
bool fromZero = from == address(0);
if (!fromZero) {
uint256 fromSnapshotCount = _snapshotCount[from];
// Underflow is impossible since, if from != address(0), then a delegation must have occurred (at least 1 snapshot)
uint256 previous = _snapshots[from][fromSnapshotCount - 1].value;
uint128 newValue = uint128(previous - amount);
uint128 newValue = _snapshots[from][fromSnapshotCount - 1].value + 1;
_writeSnapshot(from, newValue, fromSnapshotCount);
emit Events.FollowNFTDelegatedPowerChanged(from, newValue, block.timestamp);
}
if (to != address(0)) {
// if from == address(0) then this is an initial delegation (add amount to supply)
// if from == address(0) then this is an initial delegation, increment supply.
if (fromZero) {
// It is expected behavior that the `previousDelSupply` underflows upon the first delegation,
// returning the expected value of zero
uint256 delSupplySnapshotCount = _delSupplySnapshotCount;
uint128 previousDelSupply = _delSupplySnapshots[delSupplySnapshotCount - 1]
.value;
uint128 newDelSupply = uint128(previousDelSupply + amount);
_writeSupplySnapshot(newDelSupply, delSupplySnapshotCount);
_writeSupplySnapshot(
_delSupplySnapshots[delSupplySnapshotCount - 1].value + 1,
delSupplySnapshotCount
);
}
// It is expected behavior that `previous` underflows upon the first delegation to an address,
// returning the expected value of zero
uint256 toSnapshotCount = _snapshotCount[to];
uint128 previous = _snapshots[to][toSnapshotCount - 1].value;
uint128 newValue = uint128(previous + amount);
uint128 newValue = _snapshots[to][toSnapshotCount - 1].value + 1;
_writeSnapshot(to, newValue, toSnapshotCount);
emit Events.FollowNFTDelegatedPowerChanged(to, newValue, block.timestamp);
} else {
@@ -677,9 +676,8 @@ contract FollowNFT is HubRestricted, LensNFTBase, IFollowNFT {
// underflow because if from != address(0), then a delegation must have previously occurred, so
// the snapshot count must be >= 1 and the previous delegated supply must be >= amount
uint256 delSupplySnapshotCount = _delSupplySnapshotCount;
uint128 previousDelSupply = _delSupplySnapshots[delSupplySnapshotCount - 1]
.value;
uint128 newDelSupply = uint128(previousDelSupply - amount);
uint128 newDelSupply = _delSupplySnapshots[delSupplySnapshotCount - 1].value -
1;
_writeSupplySnapshot(newDelSupply, delSupplySnapshotCount);
}
}

View File

@@ -39,22 +39,10 @@ interface IFollowNFT {
function getFollowId(uint256 follower) external view returns (uint256);
/**
* @notice Delegates the caller's governance power to the given delegatee address.
*
* @param delegatee The delegatee address to delegate governance power to.
*/
function delegate(address delegatee) external;
function delegate(uint256 delegatorProfile, address delegatee) external;
/**
* @notice Delegates the delegator's governance power via meta-tx to the given delegatee address.
*
* @param delegator The delegator address, who is the signer.
* @param delegatee The delegatee address, who is receiving the governance power delegation.
* @param sig The EIP712Signature struct containing the necessary parameters to recover the delegator's signature.
*/
function delegateBySig(
address delegator,
uint256 delegatorProfile,
address delegatee,
DataTypes.EIP712Signature calldata sig
) external;

View File

@@ -26,7 +26,7 @@ contract Helper {
address first,
address second
) external {
nft.delegate(first);
nft.delegate(second);
// nft.delegate(first); TODO: Adapt mock to new interface later.
// nft.delegate(second); TODO: Adapt mock to new interface later.
}
}