mirror of
https://github.com/lens-protocol/core.git
synced 2026-01-09 14:18:04 -05:00
332 lines
13 KiB
Solidity
332 lines
13 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.13;
|
|
|
|
import 'test/base/BaseTest.t.sol';
|
|
import 'test/MetaTxNegatives.t.sol';
|
|
import {Typehash} from 'contracts/libraries/constants/Typehash.sol';
|
|
|
|
contract SetBlockStatusTest is BaseTest {
|
|
address constant PROFILE_OWNER = address(0);
|
|
|
|
uint256 constant statusSetterProfileOwnerPk = 0x7357;
|
|
address statusSetterProfileOwner;
|
|
uint256 statusSetterProfileId;
|
|
|
|
uint256 constant blockeeProfileOwnerPk = 0xF01108;
|
|
address blockeeProfileOwner;
|
|
uint256 blockeeProfileId;
|
|
|
|
uint256 constant anotherBlockeeProfileOwnerPk = 0xF01109;
|
|
address anotherBlockeeProfileOwner;
|
|
uint256 anotherBlockeeProfileId;
|
|
|
|
address followNFTAddress;
|
|
|
|
function setUp() public virtual override {
|
|
super.setUp();
|
|
|
|
statusSetterProfileOwner = vm.addr(statusSetterProfileOwnerPk);
|
|
statusSetterProfileId = _createProfile(statusSetterProfileOwner);
|
|
|
|
blockeeProfileOwner = vm.addr(blockeeProfileOwnerPk);
|
|
blockeeProfileId = _createProfile(blockeeProfileOwner);
|
|
|
|
anotherBlockeeProfileOwner = vm.addr(anotherBlockeeProfileOwnerPk);
|
|
anotherBlockeeProfileId = _createProfile(anotherBlockeeProfileOwner);
|
|
|
|
vm.prank(blockeeProfileOwner);
|
|
hub.follow(blockeeProfileId, _toUint256Array(statusSetterProfileId), _toUint256Array(0), _toBytesArray(''));
|
|
|
|
followNFTAddress = hub.getProfile(statusSetterProfileId).followNFT;
|
|
followNFT = FollowNFT(followNFTAddress);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Set block status - Negatives
|
|
//////////////////////////////////////////////////////////
|
|
function testCannotSetBlockStatusIfPaused() public {
|
|
vm.prank(governance);
|
|
hub.setState(Types.ProtocolState.Paused);
|
|
|
|
vm.expectRevert(Errors.Paused.selector);
|
|
|
|
_setBlockStatus({
|
|
pk: statusSetterProfileOwnerPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId),
|
|
blockStatus: _toBoolArray(true)
|
|
});
|
|
}
|
|
|
|
function testCannotSetBlockStatusIfSetterProfileDoesNotExist() public {
|
|
vm.prank(statusSetterProfileOwner);
|
|
hub.burn(statusSetterProfileId);
|
|
|
|
vm.expectRevert(Errors.TokenDoesNotExist.selector);
|
|
|
|
_setBlockStatus({
|
|
pk: statusSetterProfileOwnerPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId),
|
|
blockStatus: _toBoolArray(true)
|
|
});
|
|
}
|
|
|
|
function testCannotSetBlockStatusIfNotOwnerOrApprovedDelegatedExecutorOfSetterProfile(
|
|
uint256 nonOwnerNorDelegatedExecutorPk
|
|
) public {
|
|
nonOwnerNorDelegatedExecutorPk = _boundPk(nonOwnerNorDelegatedExecutorPk);
|
|
address nonOwnerNorDelegatedExecutor = vm.addr(nonOwnerNorDelegatedExecutorPk);
|
|
vm.assume(nonOwnerNorDelegatedExecutor != address(0));
|
|
vm.assume(nonOwnerNorDelegatedExecutor != statusSetterProfileOwner);
|
|
vm.assume(!hub.isDelegatedExecutorApproved(statusSetterProfileId, nonOwnerNorDelegatedExecutor));
|
|
|
|
vm.expectRevert(Errors.ExecutorInvalid.selector);
|
|
|
|
_setBlockStatus({
|
|
pk: nonOwnerNorDelegatedExecutorPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId),
|
|
blockStatus: _toBoolArray(true)
|
|
});
|
|
|
|
vm.expectRevert(Errors.ExecutorInvalid.selector);
|
|
|
|
_setBlockStatus({
|
|
pk: nonOwnerNorDelegatedExecutorPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId),
|
|
blockStatus: _toBoolArray(true)
|
|
});
|
|
}
|
|
|
|
function testCannotSetBlockStatusIfProfilesAndStatusArrayLengthMismatches() public {
|
|
vm.expectRevert(Errors.ArrayMismatch.selector);
|
|
|
|
_setBlockStatus({
|
|
pk: statusSetterProfileOwnerPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId, anotherBlockeeProfileId),
|
|
blockStatus: _toBoolArray(true)
|
|
});
|
|
}
|
|
|
|
function testCannotSetBlockStatusIfBlockeeProfileDoesNotExist() public {
|
|
vm.prank(blockeeProfileOwner);
|
|
hub.burn(blockeeProfileId);
|
|
|
|
vm.expectRevert(Errors.TokenDoesNotExist.selector);
|
|
|
|
_setBlockStatus({
|
|
pk: statusSetterProfileOwnerPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId),
|
|
blockStatus: _toBoolArray(true)
|
|
});
|
|
}
|
|
|
|
function testCannotBlockItself() public {
|
|
vm.expectRevert(Errors.SelfBlock.selector);
|
|
|
|
_setBlockStatus({
|
|
pk: statusSetterProfileOwnerPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(statusSetterProfileId),
|
|
blockStatus: _toBoolArray(true)
|
|
});
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// Set block status - Scenarios
|
|
//////////////////////////////////////////////////////////
|
|
function testSetBlockStatusEmitExpectedEventsAndSetExpectedStatus() public {
|
|
assertFalse(hub.isBlocked(blockeeProfileId, statusSetterProfileId));
|
|
assertFalse(hub.isBlocked(anotherBlockeeProfileId, statusSetterProfileId));
|
|
|
|
vm.expectEmit(true, false, false, true, address(hub));
|
|
emit Events.Blocked(statusSetterProfileId, blockeeProfileId, block.timestamp);
|
|
|
|
vm.expectEmit(true, false, false, true, address(hub));
|
|
emit Events.Blocked(statusSetterProfileId, anotherBlockeeProfileId, block.timestamp);
|
|
|
|
vm.expectCall(followNFTAddress, abi.encodeCall(followNFT.processBlock, (blockeeProfileId)), 2);
|
|
vm.expectCall(followNFTAddress, abi.encodeCall(followNFT.processBlock, (anotherBlockeeProfileId)), 1);
|
|
|
|
_setBlockStatus({
|
|
pk: statusSetterProfileOwnerPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId, anotherBlockeeProfileId),
|
|
blockStatus: _toBoolArray(true, true)
|
|
});
|
|
|
|
assertTrue(hub.isBlocked(blockeeProfileId, statusSetterProfileId));
|
|
assertTrue(hub.isBlocked(anotherBlockeeProfileId, statusSetterProfileId));
|
|
|
|
_refreshCachedNonces();
|
|
|
|
vm.expectEmit(true, false, false, true, address(hub));
|
|
emit Events.Blocked(statusSetterProfileId, blockeeProfileId, block.timestamp);
|
|
|
|
vm.expectEmit(true, false, false, true, address(hub));
|
|
emit Events.Unblocked(statusSetterProfileId, anotherBlockeeProfileId, block.timestamp);
|
|
|
|
_setBlockStatus({
|
|
pk: statusSetterProfileOwnerPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId, anotherBlockeeProfileId),
|
|
blockStatus: _toBoolArray(true, false)
|
|
});
|
|
|
|
assertTrue(hub.isBlocked(blockeeProfileId, statusSetterProfileId));
|
|
assertFalse(hub.isBlocked(anotherBlockeeProfileId, statusSetterProfileId));
|
|
}
|
|
|
|
function testSetBlockStatusAsBlockedForFollowerMakesHimUnfollowFirst() public {
|
|
assertTrue(hub.isFollowing(blockeeProfileId, statusSetterProfileId));
|
|
|
|
vm.expectEmit(true, false, false, true, address(hub));
|
|
emit Events.Unfollowed(blockeeProfileId, statusSetterProfileId, block.timestamp);
|
|
|
|
vm.expectEmit(true, false, false, true, address(hub));
|
|
emit Events.Blocked(statusSetterProfileId, blockeeProfileId, block.timestamp);
|
|
|
|
vm.expectCall(followNFTAddress, abi.encodeCall(followNFT.processBlock, (blockeeProfileId)), 1);
|
|
|
|
_setBlockStatus({
|
|
pk: statusSetterProfileOwnerPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId),
|
|
blockStatus: _toBoolArray(true)
|
|
});
|
|
|
|
assertTrue(hub.isBlocked(blockeeProfileId, statusSetterProfileId));
|
|
assertFalse(hub.isFollowing(blockeeProfileId, statusSetterProfileId));
|
|
}
|
|
|
|
function testSetBlockStatusAsBlockedDoesNotCallFollowNFTIfNotDeployed() public {
|
|
// Creates a fresh profile so it doesn't have a Follow NFT collection deployed yet.
|
|
statusSetterProfileId = _createProfile(statusSetterProfileOwner);
|
|
|
|
// As the Follow NFT has not been deployed yet, the address is zero, so if a `followNFT.processBlock(...)` call
|
|
// is performed to it, this test must revert.
|
|
assertEq(hub.getProfile(statusSetterProfileId).followNFT, address(0));
|
|
|
|
vm.expectEmit(true, false, false, true, address(hub));
|
|
emit Events.Blocked(statusSetterProfileId, blockeeProfileId, block.timestamp);
|
|
|
|
_setBlockStatus({
|
|
pk: statusSetterProfileOwnerPk,
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId),
|
|
blockStatus: _toBoolArray(true)
|
|
});
|
|
|
|
assertTrue(hub.isBlocked(blockeeProfileId, statusSetterProfileId));
|
|
}
|
|
|
|
function _refreshCachedNonces() internal virtual {
|
|
// Nothing to do there.
|
|
}
|
|
|
|
function _setBlockStatus(
|
|
uint256 pk,
|
|
uint256 byProfileId,
|
|
uint256[] memory idsOfProfilesToSetBlockStatus,
|
|
bool[] memory blockStatus
|
|
) internal virtual {
|
|
vm.prank(vm.addr(pk));
|
|
hub.setBlockStatus(byProfileId, idsOfProfilesToSetBlockStatus, blockStatus);
|
|
}
|
|
}
|
|
|
|
contract SetBlockStatusMetaTxTest is SetBlockStatusTest, MetaTxNegatives {
|
|
mapping(address => uint256) cachedNonceByAddress;
|
|
|
|
function testSetBlockStatusMetaTxTest() public {
|
|
// Prevents being counted in Foundry Coverage
|
|
}
|
|
|
|
function setUp() public override(SetBlockStatusTest, MetaTxNegatives) {
|
|
SetBlockStatusTest.setUp();
|
|
MetaTxNegatives.setUp();
|
|
|
|
cachedNonceByAddress[statusSetterProfileOwner] = hub.nonces(statusSetterProfileOwner);
|
|
}
|
|
|
|
function _refreshCachedNonces() internal override {
|
|
cachedNonceByAddress[statusSetterProfileOwner] = hub.nonces(statusSetterProfileOwner);
|
|
}
|
|
|
|
function _setBlockStatus(
|
|
uint256 pk,
|
|
uint256 byProfileId,
|
|
uint256[] memory idsOfProfilesToSetBlockStatus,
|
|
bool[] memory blockStatus
|
|
) internal override {
|
|
address signer = vm.addr(pk);
|
|
hub.setBlockStatusWithSig({
|
|
byProfileId: byProfileId,
|
|
idsOfProfilesToSetBlockStatus: idsOfProfilesToSetBlockStatus,
|
|
blockStatus: blockStatus,
|
|
signature: _getSigStruct({
|
|
signer: signer,
|
|
pKey: pk,
|
|
digest: _calculateSetBlockStatusWithSigDigest({
|
|
byProfileId: byProfileId,
|
|
idsOfProfilesToSetBlockStatus: idsOfProfilesToSetBlockStatus,
|
|
blockStatus: blockStatus,
|
|
nonce: cachedNonceByAddress[signer],
|
|
deadline: type(uint256).max
|
|
}),
|
|
deadline: type(uint256).max
|
|
})
|
|
});
|
|
}
|
|
|
|
function _executeMetaTx(uint256 signerPk, uint256 nonce, uint256 deadline) internal override {
|
|
hub.setBlockStatusWithSig({
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId),
|
|
blockStatus: _toBoolArray(true),
|
|
signature: _getSigStruct({
|
|
signer: vm.addr(_getDefaultMetaTxSignerPk()),
|
|
pKey: signerPk,
|
|
digest: _calculateSetBlockStatusWithSigDigest({
|
|
byProfileId: statusSetterProfileId,
|
|
idsOfProfilesToSetBlockStatus: _toUint256Array(blockeeProfileId),
|
|
blockStatus: _toBoolArray(true),
|
|
nonce: nonce,
|
|
deadline: deadline
|
|
}),
|
|
deadline: deadline
|
|
})
|
|
});
|
|
}
|
|
|
|
function _getDefaultMetaTxSignerPk() internal pure override returns (uint256) {
|
|
return statusSetterProfileOwnerPk;
|
|
}
|
|
|
|
function _calculateSetBlockStatusWithSigDigest(
|
|
uint256 byProfileId,
|
|
uint256[] memory idsOfProfilesToSetBlockStatus,
|
|
bool[] memory blockStatus,
|
|
uint256 nonce,
|
|
uint256 deadline
|
|
) internal view returns (bytes32) {
|
|
return
|
|
_calculateDigest(
|
|
keccak256(
|
|
abi.encode(
|
|
Typehash.SET_BLOCK_STATUS,
|
|
byProfileId,
|
|
keccak256(abi.encodePacked(idsOfProfilesToSetBlockStatus)),
|
|
keccak256(abi.encodePacked(blockStatus)),
|
|
nonce,
|
|
deadline
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|