Files
core/test/UnfollowTest.t.sol
donosonaumczuk 8eb7ca8ef0 misc: Redundant getters removed to reduce bytecode size
Co-authored-by: Victor Naumik <vicnaum@gmail.com>
2023-06-09 17:49:03 +02:00

281 lines
10 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import 'test/base/BaseTest.t.sol';
import 'test/MetaTxNegatives.t.sol';
import {Strings} from '@openzeppelin/contracts/utils/Strings.sol';
import {IFollowNFT} from 'contracts/interfaces/IFollowNFT.sol';
import {Typehash} from 'contracts/libraries/constants/Typehash.sol';
contract UnfollowTest is BaseTest {
uint256 constant MINT_NEW_TOKEN = 0;
address constant PROFILE_OWNER = address(0);
address targetProfileOwner = address(0xC0FFEE);
uint256 targetProfileId;
uint256 constant nonFollowingProfileOwnerPk = 0x7357;
address nonFollowingProfileOwner;
uint256 nonFollowingProfileId;
uint256 constant testUnfollowerProfileOwnerPk = 0xF01108;
address testUnfollowerProfileOwner;
uint256 testUnfollowerProfileId;
address targetFollowNFT;
uint256 followTokenId;
function setUp() public virtual override {
super.setUp();
targetProfileId = _createProfile(targetProfileOwner);
nonFollowingProfileOwner = vm.addr(nonFollowingProfileOwnerPk);
nonFollowingProfileId = _createProfile(nonFollowingProfileOwner);
testUnfollowerProfileOwner = vm.addr(testUnfollowerProfileOwnerPk);
testUnfollowerProfileId = _createProfile(testUnfollowerProfileOwner);
vm.prank(testUnfollowerProfileOwner);
followTokenId = hub.follow(
testUnfollowerProfileId,
_toUint256Array(targetProfileId),
_toUint256Array(0),
_toBytesArray('')
)[0];
targetFollowNFT = hub.getProfile(targetProfileId).followNFT;
followNFT = FollowNFT(targetFollowNFT);
}
//////////////////////////////////////////////////////////
// Unfollow - Negatives
//////////////////////////////////////////////////////////
function testCannotUnfollowIfPaused() public {
vm.prank(governance);
hub.setState(Types.ProtocolState.Paused);
vm.expectRevert(Errors.Paused.selector);
_unfollow({
pk: testUnfollowerProfileOwnerPk,
unfollowerProfileId: testUnfollowerProfileId,
idsOfProfilesToUnfollow: _toUint256Array(targetProfileId)
});
}
function testCannotUnfollowIfUnfollowerProfileDoesNotExist() public {
vm.prank(testUnfollowerProfileOwner);
hub.burn(testUnfollowerProfileId);
vm.expectRevert(Errors.TokenDoesNotExist.selector);
_unfollow({
pk: testUnfollowerProfileOwnerPk,
unfollowerProfileId: testUnfollowerProfileId,
idsOfProfilesToUnfollow: _toUint256Array(targetProfileId)
});
}
function testCannotUnfollowIfSomeOfTheProfilesToUnfollowDoNotExist(uint256 unexistentProfileId) public {
vm.assume(!hub.exists(unexistentProfileId));
assertTrue(hub.isFollowing(testUnfollowerProfileId, targetProfileId));
vm.expectRevert(Errors.TokenDoesNotExist.selector);
_unfollow({
pk: testUnfollowerProfileOwnerPk,
unfollowerProfileId: testUnfollowerProfileId,
idsOfProfilesToUnfollow: _toUint256Array(targetProfileId, unexistentProfileId)
});
// Asserts that the unfollow operation has been completely reverted after one of the unfollows failed.
assertTrue(hub.isFollowing(testUnfollowerProfileId, targetProfileId));
}
function testCannotUnfollowIfTheProfileHasNeverBeenFollowedBefore() public {
uint256 hasNeverBeenFollowedProfileId = _createProfile(targetProfileOwner);
vm.expectRevert(Errors.NotFollowing.selector);
_unfollow({
pk: testUnfollowerProfileOwnerPk,
unfollowerProfileId: testUnfollowerProfileId,
idsOfProfilesToUnfollow: _toUint256Array(hasNeverBeenFollowedProfileId)
});
}
function testCannotUnfollowIfNotFollowingTheTargetProfile() public {
vm.expectRevert(Errors.NotFollowing.selector);
_unfollow({
pk: nonFollowingProfileOwnerPk,
unfollowerProfileId: nonFollowingProfileId,
idsOfProfilesToUnfollow: _toUint256Array(targetProfileId)
});
}
function testCannotUnfollowIfNotProfileOwnerOrDelegatedExecutor(uint256 transactionExecutorPk) public {
transactionExecutorPk = bound(
transactionExecutorPk,
1,
115792089237316195423570985008687907852837564279074904382605163141518161494337 - 1
);
address transactionExecutor = vm.addr(transactionExecutorPk);
vm.assume(transactionExecutor != testUnfollowerProfileOwner);
vm.assume(!hub.isDelegatedExecutorApproved(testUnfollowerProfileId, transactionExecutor));
vm.assume(!followNFT.isApprovedForAll(testUnfollowerProfileOwner, transactionExecutor));
followTokenId = followNFT.getFollowTokenId(testUnfollowerProfileId);
vm.prank(testUnfollowerProfileOwner);
followNFT.wrap(followTokenId);
vm.expectRevert(Errors.ExecutorInvalid.selector);
_unfollow({
pk: transactionExecutorPk,
unfollowerProfileId: testUnfollowerProfileId,
idsOfProfilesToUnfollow: _toUint256Array(targetProfileId)
});
}
//////////////////////////////////////////////////////////
// Unfollow - Scenarios
//////////////////////////////////////////////////////////
function testUnfollowAsUnfollowerOwner() public {
vm.expectEmit(true, false, false, true, address(hub));
emit Events.Unfollowed(testUnfollowerProfileId, targetProfileId, block.timestamp);
vm.expectCall(
targetFollowNFT,
abi.encodeCall(followNFT.unfollow, (testUnfollowerProfileId, testUnfollowerProfileOwner)),
1
);
_unfollow({
pk: testUnfollowerProfileOwnerPk,
unfollowerProfileId: testUnfollowerProfileId,
idsOfProfilesToUnfollow: _toUint256Array(targetProfileId)
});
assertFalse(hub.isFollowing(testUnfollowerProfileId, targetProfileId));
}
function testUnfollowAsUnfollowerApprovedDelegatedExecutor(uint256 approvedDelegatedExecutorPk) public {
approvedDelegatedExecutorPk = _boundPk(approvedDelegatedExecutorPk);
address approvedDelegatedExecutor = vm.addr(approvedDelegatedExecutorPk);
vm.assume(approvedDelegatedExecutor != address(0));
vm.assume(approvedDelegatedExecutor != testUnfollowerProfileOwner);
vm.prank(testUnfollowerProfileOwner);
hub.changeDelegatedExecutorsConfig({
delegatorProfileId: testUnfollowerProfileId,
delegatedExecutors: _toAddressArray(approvedDelegatedExecutor),
approvals: _toBoolArray(true)
});
vm.expectEmit(true, false, false, true, address(hub));
emit Events.Unfollowed(testUnfollowerProfileId, targetProfileId, block.timestamp);
vm.expectCall(
targetFollowNFT,
abi.encodeCall(followNFT.unfollow, (testUnfollowerProfileId, approvedDelegatedExecutor)),
1
);
_unfollow({
pk: approvedDelegatedExecutorPk,
unfollowerProfileId: testUnfollowerProfileId,
idsOfProfilesToUnfollow: _toUint256Array(targetProfileId)
});
assertFalse(hub.isFollowing(testUnfollowerProfileId, targetProfileId));
}
function _unfollow(
uint256 pk,
uint256 unfollowerProfileId,
uint256[] memory idsOfProfilesToUnfollow
) internal virtual {
vm.prank(vm.addr(pk));
hub.unfollow(unfollowerProfileId, idsOfProfilesToUnfollow);
}
}
contract UnfollowMetaTxTest is UnfollowTest, MetaTxNegatives {
mapping(address => uint256) cachedNonceByAddress;
function testUnfollowMetaTxTest() public {
// Prevents being counted in Foundry Coverage
}
function setUp() public override(UnfollowTest, MetaTxNegatives) {
UnfollowTest.setUp();
MetaTxNegatives.setUp();
cachedNonceByAddress[nonFollowingProfileOwner] = hub.nonces(nonFollowingProfileOwner);
cachedNonceByAddress[testUnfollowerProfileOwner] = hub.nonces(testUnfollowerProfileOwner);
}
function _unfollow(
uint256 pk,
uint256 unfollowerProfileId,
uint256[] memory idsOfProfilesToUnfollow
) internal virtual override {
address signer = vm.addr(pk);
uint256 nonce = cachedNonceByAddress[signer];
hub.unfollowWithSig({
unfollowerProfileId: unfollowerProfileId,
idsOfProfilesToUnfollow: idsOfProfilesToUnfollow,
signature: _getSigStruct({
pKey: pk,
digest: _calculateUnfollowWithSigDigest(
unfollowerProfileId,
idsOfProfilesToUnfollow,
nonce,
type(uint256).max
),
deadline: type(uint256).max
})
});
}
function _executeMetaTx(uint256 signerPk, uint256 nonce, uint256 deadline) internal virtual override {
hub.unfollowWithSig({
unfollowerProfileId: testUnfollowerProfileId,
idsOfProfilesToUnfollow: _toUint256Array(targetProfileId),
signature: _getSigStruct({
signer: vm.addr(_getDefaultMetaTxSignerPk()),
pKey: signerPk,
digest: _calculateUnfollowWithSigDigest(
testUnfollowerProfileId,
_toUint256Array(targetProfileId),
nonce,
deadline
),
deadline: deadline
})
});
}
function _getDefaultMetaTxSignerPk() internal virtual override returns (uint256) {
return testUnfollowerProfileOwnerPk;
}
function _calculateUnfollowWithSigDigest(
uint256 unfollowerProfileId,
uint256[] memory idsOfProfilesToUnfollow,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
return
_calculateDigest(
keccak256(
abi.encode(
Typehash.UNFOLLOW,
unfollowerProfileId,
keccak256(abi.encodePacked(idsOfProfilesToUnfollow)),
nonce,
deadline
)
)
);
}
}