diff --git a/TestsList.md b/TestsList.md index 0ee1d7a..bb146ff 100644 --- a/TestsList.md +++ b/TestsList.md @@ -50,10 +50,10 @@ Scenarios Governance Functions Negatives -[ ] User should not be able to call governance functions +[X] User should not be able to call governance functions Scenarios -[ ] Governance should successfully whitelist and unwhitelist modules -[ ] Governance should successfully change the governance address +[X] Governance should successfully whitelist and unwhitelist modules +[X] Governance should successfully change the governance address Multi-State Hub Common @@ -75,41 +75,41 @@ Scenarios // Replaced dispatcher with DelegatedExecutor for the following two tests: [X] Governance should pause the hub, setting dispatcher should fail, then governance unpauses the hub and setting dispatcher should work [X] Governance should pause the hub, setting dispatcher with sig should fail, then governance unpauses the hub and setting dispatcher with sig should work -[ ] Governance should pause the hub, setting profile URI should fail, then governance unpauses the hub and setting profile URI should work -[ ] Governance should pause the hub, setting profile URI with sig should fail, then governance unpauses the hub and setting profile URI should work -[ ] Governance should pause the hub, setting follow NFT URI should fail, then governance unpauses the hub and setting follow NFT URI should work -[ ] Governance should pause the hub, setting follow NFT URI with sig should fail, then governance unpauses the hub and setting follow NFT URI should work -[ ] Governance should pause the hub, posting should fail, then governance unpauses the hub and posting should work -[ ] Governance should pause the hub, posting with sig should fail, then governance unpauses the hub and posting with sig should work -[ ] Governance should pause the hub, commenting should fail, then governance unpauses the hub and commenting should work -[ ] Governance should pause the hub, commenting with sig should fail, then governance unpauses the hub and commenting with sig should work -[ ] Governance should pause the hub, mirroring should fail, then governance unpauses the hub and mirroring should work -[ ] Governance should pause the hub, mirroring with sig should fail, then governance unpauses the hub and mirroring with sig should work -[ ] Governance should pause the hub, burning should fail, then governance unpauses the hub and burning should work -[ ] Governance should pause the hub, following should fail, then governance unpauses the hub and following should work -[ ] Governance should pause the hub, following with sig should fail, then governance unpauses the hub and following with sig should work -[ ] Governance should pause the hub, collecting should fail, then governance unpauses the hub and collecting should work -[ ] Governance should pause the hub, collecting with sig should fail, then governance unpauses the hub and collecting with sig should work +[X] Governance should pause the hub, setting profile URI should fail, then governance unpauses the hub and setting profile URI should work +[X] Governance should pause the hub, setting profile URI with sig should fail, then governance unpauses the hub and setting profile URI should work +[X] Governance should pause the hub, setting follow NFT URI should fail, then governance unpauses the hub and setting follow NFT URI should work +[X] Governance should pause the hub, setting follow NFT URI with sig should fail, then governance unpauses the hub and setting follow NFT URI should work +[X] Governance should pause the hub, posting should fail, then governance unpauses the hub and posting should work +[X] Governance should pause the hub, posting with sig should fail, then governance unpauses the hub and posting with sig should work +[X] Governance should pause the hub, commenting should fail, then governance unpauses the hub and commenting should work +[X] Governance should pause the hub, commenting with sig should fail, then governance unpauses the hub and commenting with sig should work +[X] Governance should pause the hub, mirroring should fail, then governance unpauses the hub and mirroring should work +[X] Governance should pause the hub, mirroring with sig should fail, then governance unpauses the hub and mirroring with sig should work +[X] Governance should pause the hub, burning should fail, then governance unpauses the hub and burning should work +[X] Governance should pause the hub, following should fail, then governance unpauses the hub and following should work +[X] Governance should pause the hub, following with sig should fail, then governance unpauses the hub and following with sig should work +[X] Governance should pause the hub, collecting should fail, then governance unpauses the hub and collecting should work +[X] Governance should pause the hub, collecting with sig should fail, then governance unpauses the hub and collecting with sig should work PublishingPaused State Scenarios -[ ] Governance should pause publishing, profile creation should work -[ ] Governance should pause publishing, setting follow module should work -[ ] Governance should pause publishing, setting follow module with sig should work -[ ] Governance should pause publishing, setting dispatcher should work -[ ] Governance should pause publishing, setting dispatcher with sig should work -[ ] Governance should pause publishing, setting profile URI should work -[ ] Governance should pause publishing, setting profile URI with sig should work -[ ] Governance should pause publishing, posting should fail, then governance unpauses the hub and posting should work -[ ] Governance should pause publishing, posting with sig should fail, then governance unpauses the hub and posting with sig should work -[ ] Governance should pause publishing, commenting should fail, then governance unpauses the hub and commenting should work -[ ] Governance should pause publishing, commenting with sig should fail, then governance unpauses the hub and commenting with sig should work -[ ] Governance should pause publishing, mirroring should fail, then governance unpauses the hub and mirroring should work -[ ] Governance should pause publishing, mirroring with sig should fail, then governance unpauses the hub and mirroring with sig should work -[ ] Governance should pause publishing, burning should work -[ ] Governance should pause publishing, following should work -[ ] Governance should pause publishing, following with sig should work -[ ] Governance should pause publishing, collecting should work -[ ] Governance should pause publishing, collecting with sig should work +[X] Governance should pause publishing, profile creation should work +[X] Governance should pause publishing, setting follow module should work +[X] Governance should pause publishing, setting follow module with sig should work +[X] Governance should pause publishing, setting dispatcher should work +[X] Governance should pause publishing, setting dispatcher with sig should work +[X] Governance should pause publishing, setting profile URI should work +[X] Governance should pause publishing, setting profile URI with sig should work +[X] Governance should pause publishing, posting should fail, then governance unpauses the hub and posting should work +[X] Governance should pause publishing, posting with sig should fail, then governance unpauses the hub and posting with sig should work +[X] Governance should pause publishing, commenting should fail, then governance unpauses the hub and commenting should work +[X] Governance should pause publishing, commenting with sig should fail, then governance unpauses the hub and commenting with sig should work +[X] Governance should pause publishing, mirroring should fail, then governance unpauses the hub and mirroring should work +[X] Governance should pause publishing, mirroring with sig should fail, then governance unpauses the hub and mirroring with sig should work +[X] Governance should pause publishing, burning should work +[X] Governance should pause publishing, following should work +[X] Governance should pause publishing, following with sig should work +[X] Governance should pause publishing, collecting should work +[X] Governance should pause publishing, collecting with sig should work Publishing Comments Generic @@ -274,20 +274,20 @@ Scenarios Setting Follow Module Generic Negatives -[ ] UserTwo should fail to set the follow module for the profile owned by User -[ ] User should fail to set a follow module that is not whitelisted -[ ] User should fail to set a follow module with invalid follow module data format +[X] UserTwo should fail to set the follow module for the profile owned by User +[X] User should fail to set a follow module that is not whitelisted +[X] User should fail to set a follow module with invalid follow module data format Scenarios -[ ] User should set a whitelisted follow module, fetching the profile follow module should return the correct address, user then sets it to the zero address and fetching returns the zero address +[X] User should set a whitelisted follow module, fetching the profile follow module should return the correct address, user then sets it to the zero address and fetching returns the zero address Meta-tx Negatives -[ ] TestWallet should fail to set a follow module with sig with signature deadline mismatch -[ ] TestWallet should fail to set a follow module with sig with invalid deadline -[ ] TestWallet should fail to set a follow module with sig with invalid nonce -[ ] TestWallet should fail to set a follow module with sig with an unwhitelisted follow module -[ ] TestWallet should sign attempt to set follow module with sig, then cancel with empty permitForAll, then fail to set follow module with sig +[X] TestWallet should fail to set a follow module with sig with signature deadline mismatch +[X] TestWallet should fail to set a follow module with sig with invalid deadline +[X] TestWallet should fail to set a follow module with sig with invalid nonce +[X] TestWallet should fail to set a follow module with sig with an unwhitelisted follow module +[X] TestWallet should sign attempt to set follow module with sig, then cancel with empty permitForAll, then fail to set follow module with sig Scenarios -[ ] TestWallet should set a whitelisted follow module with sig, fetching the profile follow module should return the correct address +[X] TestWallet should set a whitelisted follow module with sig, fetching the profile follow module should return the correct address Collect NFT Negatives diff --git a/scripts/getProxyAdmin.sh b/scripts/getProxyAdmin.sh new file mode 100644 index 0000000..c20ba89 --- /dev/null +++ b/scripts/getProxyAdmin.sh @@ -0,0 +1,17 @@ +source .env + +if [[ $1 == "" ]] + then + echo "Usage:" + echo " bash getProxyAdmin.sh [address]" + echo " Where [address] is the TransparentUpgradeableProxy address" + exit 1 +fi + +# TransparentUpgradeableProxy implementation slot +adminSlot="0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103" + +rawOldImplAddress=$(cast storage $1 $adminSlot --rpc-url $POLYGON_RPC_URL) + +echo "Admin of $1 TransparentUpgradeableProxy is:" +echo "0x${rawOldImplAddress:26}" diff --git a/test/foundry/CollectTest.t.sol b/test/foundry/CollectTest.t.sol index 3cc2dd6..467b0d1 100644 --- a/test/foundry/CollectTest.t.sol +++ b/test/foundry/CollectTest.t.sol @@ -16,7 +16,7 @@ contract CollectTest is BaseTest { // negatives function testCollectNonexistantPublicationFails() public { vm.expectRevert(Errors.PublicationDoesNotExist.selector); - hub.collect(me, firstProfileId, 2, ''); + hub.collect(me, newProfileId, 2, ''); } function testCollectZeroPublicationFails() public { @@ -27,28 +27,24 @@ contract CollectTest is BaseTest { function testCollectNotExecutorFails() public { vm.prank(otherSigner); vm.expectRevert(Errors.ExecutorInvalid.selector); - hub.collect(me, firstProfileId, 1, ''); + hub.collect(me, newProfileId, 1, ''); } // positives function testCollect() public { - assertEq(hub.getCollectNFT(firstProfileId, 1), address(0)); + assertEq(hub.getCollectNFT(newProfileId, 1), address(0)); - uint256 nftId = hub.collect(me, firstProfileId, 1, ''); - CollectNFT nft = CollectNFT(hub.getCollectNFT(firstProfileId, 1)); + uint256 nftId = hub.collect(me, newProfileId, 1, ''); + CollectNFT nft = CollectNFT(hub.getCollectNFT(newProfileId, 1)); assertEq(nftId, 1); assertEq(nft.ownerOf(1), me); string memory expectedName = string( - abi.encodePacked( - firstProfileId.toString(), - COLLECT_NFT_NAME_INFIX, - uint256(1).toString() - ) + abi.encodePacked(newProfileId.toString(), COLLECT_NFT_NAME_INFIX, uint256(1).toString()) ); string memory expectedSymbol = string( abi.encodePacked( - firstProfileId.toString(), + newProfileId.toString(), COLLECT_NFT_SYMBOL_INFIX, uint256(1).toString() ) @@ -62,9 +58,9 @@ contract CollectTest is BaseTest { hub.setDelegatedExecutorApproval(otherSigner, true); vm.prank(otherSigner); - uint256 nftId = hub.collect(me, firstProfileId, 1, ''); + uint256 nftId = hub.collect(me, newProfileId, 1, ''); - CollectNFT nft = CollectNFT(hub.getCollectNFT(firstProfileId, 1)); + CollectNFT nft = CollectNFT(hub.getCollectNFT(newProfileId, 1)); assertEq(nftId, 1); assertEq(nft.ownerOf(1), me); } @@ -73,13 +69,13 @@ contract CollectTest is BaseTest { vm.prank(profileOwner); hub.mirror(mockMirrorData); - uint256 nftId = hub.collect(me, firstProfileId, 2, ''); + uint256 nftId = hub.collect(me, newProfileId, 2, ''); // Ensure the mirror doesn't have an associated collect NFT. - assertEq(hub.getCollectNFT(firstProfileId, 2), address(0)); + assertEq(hub.getCollectNFT(newProfileId, 2), address(0)); // Ensure the original publication does have an associated collect NFT. - CollectNFT nft = CollectNFT(hub.getCollectNFT(firstProfileId, 1)); + CollectNFT nft = CollectNFT(hub.getCollectNFT(newProfileId, 1)); assertEq(nftId, 1); assertEq(nft.ownerOf(1), me); } @@ -91,13 +87,13 @@ contract CollectTest is BaseTest { hub.setDelegatedExecutorApproval(otherSigner, true); vm.prank(otherSigner); - uint256 nftId = hub.collect(me, firstProfileId, 2, ''); + uint256 nftId = hub.collect(me, newProfileId, 2, ''); // Ensure the mirror doesn't have an associated collect NFT. - assertEq(hub.getCollectNFT(firstProfileId, 2), address(0)); + assertEq(hub.getCollectNFT(newProfileId, 2), address(0)); // Ensure the original publication does have an associated collect NFT. - CollectNFT nft = CollectNFT(hub.getCollectNFT(firstProfileId, 1)); + CollectNFT nft = CollectNFT(hub.getCollectNFT(newProfileId, 1)); assertEq(nftId, 1); assertEq(nft.ownerOf(1), me); } @@ -107,13 +103,13 @@ contract CollectTest is BaseTest { function testCollectWithSigInvalidSignerFails() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getCollectTypedDataHash(firstProfileId, 1, '', nonce, deadline); + bytes32 digest = _getCollectTypedDataHash(newProfileId, 1, '', nonce, deadline); vm.expectRevert(Errors.SignatureInvalid.selector); hub.collectWithSig( _buildCollectWithSigData({ delegatedSigner: address(0), collector: profileOwner, - profileId: firstProfileId, + profileId: newProfileId, pubId: 1, data: '', sig: _getSigStruct(otherSignerKey, digest, deadline) @@ -124,13 +120,13 @@ contract CollectTest is BaseTest { function testCollectWithSigNotExecutorFails() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getCollectTypedDataHash(firstProfileId, 1, '', nonce, deadline); + bytes32 digest = _getCollectTypedDataHash(newProfileId, 1, '', nonce, deadline); vm.expectRevert(Errors.ExecutorInvalid.selector); hub.collectWithSig( _buildCollectWithSigData({ delegatedSigner: otherSigner, collector: profileOwner, - profileId: firstProfileId, + profileId: newProfileId, pubId: 1, data: '', sig: _getSigStruct(otherSignerKey, digest, deadline) @@ -142,30 +138,26 @@ contract CollectTest is BaseTest { function testCollectWithSig() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getCollectTypedDataHash(firstProfileId, 1, '', nonce, deadline); + bytes32 digest = _getCollectTypedDataHash(newProfileId, 1, '', nonce, deadline); uint256 nftId = hub.collectWithSig( _buildCollectWithSigData({ delegatedSigner: address(0), collector: otherSigner, - profileId: firstProfileId, + profileId: newProfileId, pubId: 1, data: '', sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); - CollectNFT nft = CollectNFT(hub.getCollectNFT(firstProfileId, 1)); - + CollectNFT nft = CollectNFT(hub.getCollectNFT(newProfileId, 1)); + string memory expectedName = string( - abi.encodePacked( - firstProfileId.toString(), - COLLECT_NFT_NAME_INFIX, - uint256(1).toString() - ) + abi.encodePacked(newProfileId.toString(), COLLECT_NFT_NAME_INFIX, uint256(1).toString()) ); string memory expectedSymbol = string( abi.encodePacked( - firstProfileId.toString(), + newProfileId.toString(), COLLECT_NFT_SYMBOL_INFIX, uint256(1).toString() ) @@ -180,7 +172,7 @@ contract CollectTest is BaseTest { function testCollectWithSigMirror() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getCollectTypedDataHash(firstProfileId, 2, '', nonce, deadline); + bytes32 digest = _getCollectTypedDataHash(newProfileId, 2, '', nonce, deadline); vm.prank(profileOwner); hub.mirror(mockMirrorData); @@ -189,7 +181,7 @@ contract CollectTest is BaseTest { _buildCollectWithSigData({ delegatedSigner: address(0), collector: otherSigner, - profileId: firstProfileId, + profileId: newProfileId, pubId: 2, data: '', sig: _getSigStruct(otherSignerKey, digest, deadline) @@ -197,7 +189,7 @@ contract CollectTest is BaseTest { ); // Ensure the mirror doesn't have an associated collect NFT. - assertEq(hub.getCollectNFT(firstProfileId, 2), address(0)); + assertEq(hub.getCollectNFT(newProfileId, 2), address(0)); // Ensure the original publication does have an associated collect NFT. CollectNFT nft = CollectNFT(hub.getCollectNFT(1, 1)); @@ -211,19 +203,19 @@ contract CollectTest is BaseTest { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getCollectTypedDataHash(firstProfileId, 1, '', nonce, deadline); + bytes32 digest = _getCollectTypedDataHash(newProfileId, 1, '', nonce, deadline); uint256 nftId = hub.collectWithSig( _buildCollectWithSigData({ delegatedSigner: profileOwner, collector: otherSigner, - profileId: firstProfileId, + profileId: newProfileId, pubId: 1, data: '', sig: _getSigStruct(profileOwnerKey, digest, deadline) }) ); - CollectNFT nft = CollectNFT(hub.getCollectNFT(firstProfileId, 1)); + CollectNFT nft = CollectNFT(hub.getCollectNFT(newProfileId, 1)); assertEq(nftId, 1); assertEq(nft.ownerOf(1), otherSigner); } @@ -234,7 +226,7 @@ contract CollectTest is BaseTest { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getCollectTypedDataHash(firstProfileId, 2, '', nonce, deadline); + bytes32 digest = _getCollectTypedDataHash(newProfileId, 2, '', nonce, deadline); vm.prank(profileOwner); hub.mirror(mockMirrorData); @@ -243,7 +235,7 @@ contract CollectTest is BaseTest { _buildCollectWithSigData({ delegatedSigner: profileOwner, collector: otherSigner, - profileId: firstProfileId, + profileId: newProfileId, pubId: 2, data: '', sig: _getSigStruct(profileOwnerKey, digest, deadline) @@ -251,7 +243,7 @@ contract CollectTest is BaseTest { ); // Ensure the mirror doesn't have an associated collect NFT. - assertEq(hub.getCollectNFT(firstProfileId, 2), address(0)); + assertEq(hub.getCollectNFT(newProfileId, 2), address(0)); // Ensure the original publication does have an associated collect NFT. CollectNFT nft = CollectNFT(hub.getCollectNFT(1, 1)); diff --git a/test/foundry/CollectingTest.t.sol b/test/foundry/CollectingTest.t.sol index 2df898a..97a584b 100644 --- a/test/foundry/CollectingTest.t.sol +++ b/test/foundry/CollectingTest.t.sol @@ -5,16 +5,6 @@ import './base/BaseTest.t.sol'; import './helpers/SignatureHelpers.sol'; import './helpers/CollectingHelpers.sol'; -contract SigSetup { - uint256 nonce; - uint256 deadline; - - function setUp() public virtual { - nonce = 0; - deadline = type(uint256).max; - } -} - // TODO add check for _initialize() called for fork tests - check name and symbol set contract CollectingTest_Base is BaseTest, SignatureHelpers, CollectingHelpers, SigSetup { @@ -143,8 +133,7 @@ contract CollectingTest_Generic is CollectingTest_Base { uint256 startNftId = _checkCollectNFTBefore(); // delegate power to executor - vm.prank(profileOwner); - _setDelegatedExecutorApproval(otherSigner, true); + _setDelegatedExecutorApproval(profileOwner, otherSigner, true); // collect from executor vm.startPrank(otherSigner); @@ -158,10 +147,9 @@ contract CollectingTest_Generic is CollectingTest_Base { uint256 startNftId = _checkCollectNFTBefore(); // mirror, then delegate power to executor - vm.startPrank(profileOwner); + vm.prank(profileOwner); hub.mirror(mockMirrorData); - _setDelegatedExecutorApproval(otherSigner, true); - vm.stopPrank(); + _setDelegatedExecutorApproval(profileOwner, otherSigner, true); // collect from executor vm.startPrank(otherSigner); @@ -217,7 +205,7 @@ contract CollectingTest_WithSig is CollectingTest_Base { function testCannotCollectIfNonceWasIncrementedWithAnotherAction() public { assertEq(_getSigNonce(profileOwner), nonce, 'Wrong nonce before posting'); - uint256 expectedCollectId = _getCollectCount(firstProfileId, mockCollectData.pubId) + 1; + uint256 expectedCollectId = _getCollectCount(newProfileId, mockCollectData.pubId) + 1; uint256 nftId = _mockCollectWithSig({ delegatedSigner: address(0), @@ -263,8 +251,7 @@ contract CollectingTest_WithSig is CollectingTest_Base { uint256 startNftId = _checkCollectNFTBefore(); // delegate power to executor - vm.prank(profileOwner); - _setDelegatedExecutorApproval(otherSigner, true); + _setDelegatedExecutorApproval(profileOwner, otherSigner, true); // collect from executor uint256 nftId = _mockCollectWithSig({ @@ -279,10 +266,9 @@ contract CollectingTest_WithSig is CollectingTest_Base { uint256 startNftId = _checkCollectNFTBefore(); // mirror, then delegate power to executor - vm.startPrank(profileOwner); + vm.prank(profileOwner); hub.mirror(mockMirrorData); - _setDelegatedExecutorApproval(otherSigner, true); - vm.stopPrank(); + _setDelegatedExecutorApproval(profileOwner, otherSigner, true); // collect from executor uint256 nftId = _mockCollectWithSig({ diff --git a/test/foundry/Constants.sol b/test/foundry/Constants.sol new file mode 100644 index 0000000..597483b --- /dev/null +++ b/test/foundry/Constants.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +uint256 constant FIRST_PROFILE_ID = 1; +uint256 constant FIRST_PUB_ID = 1; diff --git a/test/foundry/FollowTest.t.sol b/test/foundry/FollowTest.t.sol index e32de52..b316842 100644 --- a/test/foundry/FollowTest.t.sol +++ b/test/foundry/FollowTest.t.sol @@ -3,33 +3,34 @@ pragma solidity ^0.8.13; import './base/BaseTest.t.sol'; import {Strings} from '@openzeppelin/contracts/utils/Strings.sol'; +import './helpers/SignatureHelpers.sol'; -contract FollowTest is BaseTest { +contract FollowTest is BaseTest, SignatureHelpers { using Strings for uint256; // Negatives function testFollowNotExecutorFails() public { - vm.prank(otherSigner); vm.expectRevert(Errors.ExecutorInvalid.selector); - hub.follow(me, _toUint256Array(firstProfileId), _toBytesArray('')); + _follow({msgSender: otherSigner, onBehalfOf: me, profileId: newProfileId, data: ''}); } // Positives function testFollow() public { - assertEq(hub.getFollowNFT(firstProfileId), address(0)); + assertEq(hub.getFollowNFT(newProfileId), address(0)); - uint256[] memory nftIds = hub.follow( - me, - _toUint256Array(firstProfileId), - _toBytesArray('') - ); + uint256[] memory nftIds = _follow({ + msgSender: me, + onBehalfOf: me, + profileId: newProfileId, + data: '' + }); - FollowNFT nft = FollowNFT(hub.getFollowNFT(firstProfileId)); + FollowNFT nft = FollowNFT(hub.getFollowNFT(newProfileId)); string memory expectedName = string( - abi.encodePacked(firstProfileId.toString(), FOLLOW_NFT_NAME_SUFFIX) + abi.encodePacked(newProfileId.toString(), FOLLOW_NFT_NAME_SUFFIX) ); string memory expectedSymbol = string( - abi.encodePacked(firstProfileId.toString(), FOLLOW_NFT_SYMBOL_SUFFIX) + abi.encodePacked(newProfileId.toString(), FOLLOW_NFT_SYMBOL_SUFFIX) ); assertEq(nft.name(), expectedName); assertEq(nft.symbol(), expectedSymbol); @@ -41,14 +42,14 @@ contract FollowTest is BaseTest { function testExecutorFollow() public { hub.setDelegatedExecutorApproval(otherSigner, true); - vm.prank(otherSigner); - uint256[] memory nftIds = hub.follow( - me, - _toUint256Array(firstProfileId), - _toBytesArray('') - ); + uint256[] memory nftIds = _follow({ + msgSender: otherSigner, + onBehalfOf: me, + profileId: newProfileId, + data: '' + }); - FollowNFT nft = FollowNFT(hub.getFollowNFT(firstProfileId)); + FollowNFT nft = FollowNFT(hub.getFollowNFT(newProfileId)); assertEq(nftIds.length, 1); assertEq(nftIds[0], 1); assertEq(nft.ownerOf(1), me); @@ -58,7 +59,7 @@ contract FollowTest is BaseTest { // Negatives function testFollowWithSigInvalidSignerFails() public { uint256[] memory profileIds = new uint256[](1); - profileIds[0] = firstProfileId; + profileIds[0] = newProfileId; bytes[] memory datas = new bytes[](1); datas[0] = ''; uint256 nonce = 0; @@ -66,7 +67,7 @@ contract FollowTest is BaseTest { bytes32 digest = _getFollowTypedDataHash(profileIds, datas, nonce, deadline); vm.expectRevert(Errors.SignatureInvalid.selector); - hub.followWithSig( + _followWithSig( _buildFollowWithSigData({ delegatedSigner: address(0), follower: profileOwner, @@ -79,7 +80,7 @@ contract FollowTest is BaseTest { function testFollowWithSigNotExecutorFails() public { uint256[] memory profileIds = new uint256[](1); - profileIds[0] = firstProfileId; + profileIds[0] = newProfileId; bytes[] memory datas = new bytes[](1); datas[0] = ''; uint256 nonce = 0; @@ -87,7 +88,7 @@ contract FollowTest is BaseTest { bytes32 digest = _getFollowTypedDataHash(profileIds, datas, nonce, deadline); vm.expectRevert(Errors.ExecutorInvalid.selector); - hub.followWithSig( + _followWithSig( _buildFollowWithSigData({ delegatedSigner: otherSigner, follower: profileOwner, @@ -100,17 +101,17 @@ contract FollowTest is BaseTest { // Positives function testFollowWithSig() public { - assertEq(hub.getFollowNFT(firstProfileId), address(0)); + assertEq(hub.getFollowNFT(newProfileId), address(0)); uint256[] memory profileIds = new uint256[](1); - profileIds[0] = firstProfileId; + profileIds[0] = newProfileId; bytes[] memory datas = new bytes[](1); datas[0] = ''; uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getFollowTypedDataHash(profileIds, datas, nonce, deadline); - uint256[] memory nftIds = hub.followWithSig( + uint256[] memory nftIds = _followWithSig( _buildFollowWithSigData({ delegatedSigner: address(0), follower: otherSigner, @@ -120,12 +121,12 @@ contract FollowTest is BaseTest { }) ); - FollowNFT nft = FollowNFT(hub.getFollowNFT(firstProfileId)); + FollowNFT nft = FollowNFT(hub.getFollowNFT(newProfileId)); string memory expectedName = string( - abi.encodePacked(firstProfileId.toString(), FOLLOW_NFT_NAME_SUFFIX) + abi.encodePacked(newProfileId.toString(), FOLLOW_NFT_NAME_SUFFIX) ); string memory expectedSymbol = string( - abi.encodePacked(firstProfileId.toString(), FOLLOW_NFT_SYMBOL_SUFFIX) + abi.encodePacked(newProfileId.toString(), FOLLOW_NFT_SYMBOL_SUFFIX) ); assertEq(nft.name(), expectedName); assertEq(nft.symbol(), expectedSymbol); @@ -139,14 +140,14 @@ contract FollowTest is BaseTest { hub.setDelegatedExecutorApproval(profileOwner, true); uint256[] memory profileIds = new uint256[](1); - profileIds[0] = firstProfileId; + profileIds[0] = newProfileId; bytes[] memory datas = new bytes[](1); datas[0] = ''; uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getFollowTypedDataHash(profileIds, datas, nonce, deadline); - uint256[] memory nftIds = hub.followWithSig( + uint256[] memory nftIds = _followWithSig( _buildFollowWithSigData({ delegatedSigner: profileOwner, follower: otherSigner, @@ -156,20 +157,9 @@ contract FollowTest is BaseTest { }) ); - FollowNFT nft = FollowNFT(hub.getFollowNFT(firstProfileId)); + FollowNFT nft = FollowNFT(hub.getFollowNFT(newProfileId)); assertEq(nftIds.length, 1); assertEq(nftIds[0], 1); assertEq(nft.ownerOf(1), otherSigner); } - - // Private functions - function _buildFollowWithSigData( - address delegatedSigner, - address follower, - uint256[] memory profileIds, - bytes[] memory datas, - DataTypes.EIP712Signature memory sig - ) private pure returns (DataTypes.FollowWithSigData memory) { - return DataTypes.FollowWithSigData(delegatedSigner, follower, profileIds, datas, sig); - } } diff --git a/test/foundry/GovernanceFunctions.t.sol b/test/foundry/GovernanceFunctions.t.sol new file mode 100644 index 0000000..f6bfa97 --- /dev/null +++ b/test/foundry/GovernanceFunctions.t.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import './base/BaseTest.t.sol'; + +contract GovernanceFunctionsTest is BaseTest { + function setUp() public virtual override { + TestSetup.setUp(); + } + + // NEGATIVES + + function testUserCannotCallGovernanceFunctions() public { + vm.startPrank(profileOwner); + + vm.expectRevert(Errors.NotGovernance.selector); + hub.setGovernance(profileOwner); + + vm.expectRevert(Errors.NotGovernance.selector); + hub.whitelistFollowModule(profileOwner, true); + + vm.expectRevert(Errors.NotGovernance.selector); + hub.whitelistReferenceModule(profileOwner, true); + + vm.expectRevert(Errors.NotGovernance.selector); + hub.whitelistCollectModule(profileOwner, true); + + vm.stopPrank(); + } + + // SCENARIOS + + function testGovernanceCanWhitelistAndUnwhitelistModules() public { + vm.startPrank(governance); + + // Whitelist + + assertEq(hub.isFollowModuleWhitelisted(profileOwner), false); + hub.whitelistFollowModule(profileOwner, true); + assertEq(hub.isFollowModuleWhitelisted(profileOwner), true); + + assertEq(hub.isReferenceModuleWhitelisted(profileOwner), false); + hub.whitelistReferenceModule(profileOwner, true); + assertEq(hub.isReferenceModuleWhitelisted(profileOwner), true); + + assertEq(hub.isCollectModuleWhitelisted(profileOwner), false); + hub.whitelistCollectModule(profileOwner, true); + assertEq(hub.isCollectModuleWhitelisted(profileOwner), true); + + // Unwhitelist + + hub.whitelistFollowModule(profileOwner, false); + assertEq(hub.isFollowModuleWhitelisted(profileOwner), false); + + hub.whitelistReferenceModule(profileOwner, false); + assertEq(hub.isReferenceModuleWhitelisted(profileOwner), false); + + hub.whitelistCollectModule(profileOwner, false); + assertEq(hub.isCollectModuleWhitelisted(profileOwner), false); + + vm.stopPrank(); + } + + function testGovernanceCanChangeGovernanceAddress() public { + vm.startPrank(governance); + + assertEq(hub.getGovernance(), governance); + hub.setGovernance(profileOwner); + assertEq(hub.getGovernance(), profileOwner); + + vm.stopPrank(); + } +} diff --git a/test/foundry/Misc.t.sol b/test/foundry/Misc.t.sol index 1c4d24a..23baa7a 100644 --- a/test/foundry/Misc.t.sol +++ b/test/foundry/Misc.t.sol @@ -6,140 +6,75 @@ import '../../contracts/mocks/MockFollowModule.sol'; contract MiscTest is BaseTest { // Negatives - function testSetFollowModuleNotExecutorFails() public { - vm.expectRevert(Errors.ExecutorInvalid.selector); - hub.setFollowModule(firstProfileId, address(0), ''); - } - function testSetDefaultProfileNotExecutorFails() public { vm.expectRevert(Errors.ExecutorInvalid.selector); - hub.setDefaultProfile(profileOwner, firstProfileId); + hub.setDefaultProfile(profileOwner, newProfileId); } function testSetProfileImageURINotExecutorFails() public { vm.expectRevert(Errors.ExecutorInvalid.selector); - hub.setProfileImageURI(firstProfileId, mockURI); + hub.setProfileImageURI(newProfileId, MOCK_URI); } function testSetFollowNFTURINotExecutorFails() public { vm.expectRevert(Errors.ExecutorInvalid.selector); - hub.setFollowNFTURI(firstProfileId, mockURI); + hub.setFollowNFTURI(newProfileId, MOCK_URI); } function testSetProfileMetadataURINotExecutorFails() public { vm.expectRevert(Errors.ExecutorInvalid.selector); - hub.setProfileMetadataURI(firstProfileId, mockURI); + hub.setProfileMetadataURI(newProfileId, MOCK_URI); } // Positives - function testExecutorSetFollowModule() public { - assertEq(hub.getFollowModule(firstProfileId), address(0)); - vm.prank(profileOwner); - hub.setDelegatedExecutorApproval(otherSigner, true); - - address mockFollowModule = address(new MockFollowModule()); - vm.prank(governance); - hub.whitelistFollowModule(mockFollowModule, true); - - vm.prank(otherSigner); - hub.setFollowModule(firstProfileId, mockFollowModule, abi.encode(1)); - assertEq(hub.getFollowModule(firstProfileId), mockFollowModule); - } - function testExecutorSetDefaultProfile() public { assertEq(hub.getDefaultProfile(profileOwner), 0); vm.prank(profileOwner); hub.setDelegatedExecutorApproval(otherSigner, true); vm.prank(otherSigner); - hub.setDefaultProfile(profileOwner, firstProfileId); - assertEq(hub.getDefaultProfile(profileOwner), firstProfileId); + hub.setDefaultProfile(profileOwner, newProfileId); + assertEq(hub.getDefaultProfile(profileOwner), newProfileId); } function testExecutorSetProfileImageURI() public { - assertEq(hub.getProfileImageURI(firstProfileId), mockURI); + assertEq(hub.getProfileImageURI(newProfileId), MOCK_URI); vm.prank(profileOwner); hub.setDelegatedExecutorApproval(otherSigner, true); vm.prank(otherSigner); - hub.setProfileImageURI(firstProfileId, 'test'); - assertEq(hub.getProfileImageURI(firstProfileId), 'test'); + hub.setProfileImageURI(newProfileId, 'test'); + assertEq(hub.getProfileImageURI(newProfileId), 'test'); } function testExecutorSetFollowNFTURI() public { - assertEq(hub.getFollowNFTURI(firstProfileId), mockURI); + assertEq(hub.getFollowNFTURI(newProfileId), MOCK_URI); vm.prank(profileOwner); hub.setDelegatedExecutorApproval(otherSigner, true); vm.prank(otherSigner); - hub.setFollowNFTURI(firstProfileId, 'test'); - assertEq(hub.getFollowNFTURI(firstProfileId), 'test'); + hub.setFollowNFTURI(newProfileId, 'test'); + assertEq(hub.getFollowNFTURI(newProfileId), 'test'); } function testExecutorSetProfileMetadataURI() public { - assertEq(hub.getProfileMetadataURI(firstProfileId), ''); + assertEq(hub.getProfileMetadataURI(newProfileId), ''); vm.prank(profileOwner); hub.setDelegatedExecutorApproval(otherSigner, true); vm.prank(otherSigner); - hub.setProfileMetadataURI(firstProfileId, mockURI); - assertEq(hub.getProfileMetadataURI(firstProfileId), mockURI); + hub.setProfileMetadataURI(newProfileId, MOCK_URI); + assertEq(hub.getProfileMetadataURI(newProfileId), MOCK_URI); } // Meta-tx // Negatives - function testSetFollowModuleWithSigInvalidSignerFails() public { - uint256 nonce = 0; - uint256 deadline = type(uint256).max; - bytes32 digest = _getSetFollowModuleTypedDataHash( - firstProfileId, - address(0), - '', - nonce, - deadline - ); - - vm.expectRevert(Errors.SignatureInvalid.selector); - hub.setFollowModuleWithSig( - DataTypes.SetFollowModuleWithSigData({ - delegatedSigner: address(0), - profileId: firstProfileId, - followModule: address(0), - followModuleInitData: '', - sig: _getSigStruct(otherSignerKey, digest, deadline) - }) - ); - } - - function testSetFollowModuleWithSigNotExecutorFails() public { - uint256 nonce = 0; - uint256 deadline = type(uint256).max; - bytes32 digest = _getSetFollowModuleTypedDataHash( - firstProfileId, - address(0), - '', - nonce, - deadline - ); - - vm.expectRevert(Errors.ExecutorInvalid.selector); - hub.setFollowModuleWithSig( - DataTypes.SetFollowModuleWithSigData({ - delegatedSigner: otherSigner, - profileId: firstProfileId, - followModule: address(0), - followModuleInitData: '', - sig: _getSigStruct(otherSignerKey, digest, deadline) - }) - ); - } - function testSetDefaultProfileWithSigInvalidSignerFails() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getSetDefaultProfileTypedDataHash( profileOwner, - firstProfileId, + newProfileId, nonce, deadline ); @@ -149,7 +84,7 @@ contract MiscTest is BaseTest { DataTypes.SetDefaultProfileWithSigData({ delegatedSigner: address(0), wallet: profileOwner, - profileId: firstProfileId, + profileId: newProfileId, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); @@ -160,7 +95,7 @@ contract MiscTest is BaseTest { uint256 deadline = type(uint256).max; bytes32 digest = _getSetDefaultProfileTypedDataHash( profileOwner, - firstProfileId, + newProfileId, nonce, deadline ); @@ -170,7 +105,7 @@ contract MiscTest is BaseTest { DataTypes.SetDefaultProfileWithSigData({ delegatedSigner: otherSigner, wallet: profileOwner, - profileId: firstProfileId, + profileId: newProfileId, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); @@ -180,8 +115,8 @@ contract MiscTest is BaseTest { uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getSetProfileImageURITypedDataHash( - firstProfileId, - mockURI, + newProfileId, + MOCK_URI, nonce, deadline ); @@ -190,8 +125,8 @@ contract MiscTest is BaseTest { hub.setProfileImageURIWithSig( DataTypes.SetProfileImageURIWithSigData({ delegatedSigner: address(0), - profileId: firstProfileId, - imageURI: mockURI, + profileId: newProfileId, + imageURI: MOCK_URI, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); @@ -201,8 +136,8 @@ contract MiscTest is BaseTest { uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getSetProfileImageURITypedDataHash( - firstProfileId, - mockURI, + newProfileId, + MOCK_URI, nonce, deadline ); @@ -211,8 +146,8 @@ contract MiscTest is BaseTest { hub.setProfileImageURIWithSig( DataTypes.SetProfileImageURIWithSigData({ delegatedSigner: otherSigner, - profileId: firstProfileId, - imageURI: mockURI, + profileId: newProfileId, + imageURI: MOCK_URI, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); @@ -221,14 +156,14 @@ contract MiscTest is BaseTest { function testSetFollowNFTURIWithSigInvalidSignerFails() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getSetFollowNFTURITypedDatahash(firstProfileId, mockURI, nonce, deadline); + bytes32 digest = _getSetFollowNFTURITypedDataHash(newProfileId, MOCK_URI, nonce, deadline); vm.expectRevert(Errors.SignatureInvalid.selector); hub.setFollowNFTURIWithSig( DataTypes.SetFollowNFTURIWithSigData({ delegatedSigner: address(0), - profileId: firstProfileId, - followNFTURI: mockURI, + profileId: newProfileId, + followNFTURI: MOCK_URI, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); @@ -237,14 +172,14 @@ contract MiscTest is BaseTest { function testSetFollowNFTURIWithSigNotExecutorFails() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getSetFollowNFTURITypedDatahash(firstProfileId, mockURI, nonce, deadline); + bytes32 digest = _getSetFollowNFTURITypedDataHash(newProfileId, MOCK_URI, nonce, deadline); vm.expectRevert(Errors.ExecutorInvalid.selector); hub.setFollowNFTURIWithSig( DataTypes.SetFollowNFTURIWithSigData({ delegatedSigner: otherSigner, - profileId: firstProfileId, - followNFTURI: mockURI, + profileId: newProfileId, + followNFTURI: MOCK_URI, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); @@ -254,8 +189,8 @@ contract MiscTest is BaseTest { uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getSetProfileMetadataURITypedDataHash( - firstProfileId, - mockURI, + newProfileId, + MOCK_URI, nonce, deadline ); @@ -264,8 +199,8 @@ contract MiscTest is BaseTest { hub.setProfileMetadataURIWithSig( DataTypes.SetProfileMetadataURIWithSigData({ delegatedSigner: address(0), - profileId: firstProfileId, - metadataURI: mockURI, + profileId: newProfileId, + metadataURI: MOCK_URI, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); @@ -275,8 +210,8 @@ contract MiscTest is BaseTest { uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getSetProfileMetadataURITypedDataHash( - firstProfileId, - mockURI, + newProfileId, + MOCK_URI, nonce, deadline ); @@ -285,80 +220,20 @@ contract MiscTest is BaseTest { hub.setProfileMetadataURIWithSig( DataTypes.SetProfileMetadataURIWithSigData({ delegatedSigner: otherSigner, - profileId: firstProfileId, - metadataURI: mockURI, + profileId: newProfileId, + metadataURI: MOCK_URI, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); } // Postivies - function testSetFollowModuleWithSig() public { - address mockFollowModule = address(new MockFollowModule()); - vm.prank(governance); - hub.whitelistFollowModule(mockFollowModule, true); - - uint256 nonce = 0; - uint256 deadline = type(uint256).max; - - bytes32 digest = _getSetFollowModuleTypedDataHash( - firstProfileId, - mockFollowModule, - abi.encode(1), - nonce, - deadline - ); - - assertEq(hub.getFollowModule(firstProfileId), address(0)); - hub.setFollowModuleWithSig( - DataTypes.SetFollowModuleWithSigData({ - delegatedSigner: address(0), - profileId: firstProfileId, - followModule: mockFollowModule, - followModuleInitData: abi.encode(1), - sig: _getSigStruct(profileOwnerKey, digest, deadline) - }) - ); - assertEq(hub.getFollowModule(firstProfileId), mockFollowModule); - } - - function testExecutorSetFollowModuleWithSig() public { - vm.prank(profileOwner); - hub.setDelegatedExecutorApproval(otherSigner, true); - - address mockFollowModule = address(new MockFollowModule()); - vm.prank(governance); - hub.whitelistFollowModule(mockFollowModule, true); - - uint256 nonce = 0; - uint256 deadline = type(uint256).max; - bytes32 digest = _getSetFollowModuleTypedDataHash( - firstProfileId, - mockFollowModule, - abi.encode(1), - nonce, - deadline - ); - - assertEq(hub.getFollowModule(firstProfileId), address(0)); - hub.setFollowModuleWithSig( - DataTypes.SetFollowModuleWithSigData({ - delegatedSigner: otherSigner, - profileId: firstProfileId, - followModule: mockFollowModule, - followModuleInitData: abi.encode(1), - sig: _getSigStruct(otherSignerKey, digest, deadline) - }) - ); - assertEq(hub.getFollowModule(firstProfileId), mockFollowModule); - } - function testSetDefaultProfileWithSig() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getSetDefaultProfileTypedDataHash( profileOwner, - firstProfileId, + newProfileId, nonce, deadline ); @@ -368,11 +243,11 @@ contract MiscTest is BaseTest { DataTypes.SetDefaultProfileWithSigData({ delegatedSigner: address(0), wallet: profileOwner, - profileId: firstProfileId, + profileId: newProfileId, sig: _getSigStruct(profileOwnerKey, digest, deadline) }) ); - assertEq(hub.getDefaultProfile(profileOwner), firstProfileId); + assertEq(hub.getDefaultProfile(profileOwner), newProfileId); } function testExecutorSetDefaultProfileWithSig() public { @@ -383,7 +258,7 @@ contract MiscTest is BaseTest { uint256 deadline = type(uint256).max; bytes32 digest = _getSetDefaultProfileTypedDataHash( profileOwner, - firstProfileId, + newProfileId, nonce, deadline ); @@ -393,33 +268,28 @@ contract MiscTest is BaseTest { DataTypes.SetDefaultProfileWithSigData({ delegatedSigner: otherSigner, wallet: profileOwner, - profileId: firstProfileId, + profileId: newProfileId, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); - assertEq(hub.getDefaultProfile(profileOwner), firstProfileId); + assertEq(hub.getDefaultProfile(profileOwner), newProfileId); } function testSetProfileImageURIWithSig() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getSetProfileImageURITypedDataHash( - firstProfileId, - 'test', - nonce, - deadline - ); + bytes32 digest = _getSetProfileImageURITypedDataHash(newProfileId, 'test', nonce, deadline); - assertEq(hub.getProfileImageURI(firstProfileId), mockURI); + assertEq(hub.getProfileImageURI(newProfileId), MOCK_URI); hub.setProfileImageURIWithSig( DataTypes.SetProfileImageURIWithSigData({ delegatedSigner: address(0), - profileId: firstProfileId, + profileId: newProfileId, imageURI: 'test', sig: _getSigStruct(profileOwnerKey, digest, deadline) }) ); - assertEq(hub.getProfileImageURI(firstProfileId), 'test'); + assertEq(hub.getProfileImageURI(newProfileId), 'test'); } function testExecutorSetProfileImageURIWithSig() public { @@ -428,40 +298,35 @@ contract MiscTest is BaseTest { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getSetProfileImageURITypedDataHash( - firstProfileId, - 'test', - nonce, - deadline - ); + bytes32 digest = _getSetProfileImageURITypedDataHash(newProfileId, 'test', nonce, deadline); - assertEq(hub.getProfileImageURI(firstProfileId), mockURI); + assertEq(hub.getProfileImageURI(newProfileId), MOCK_URI); hub.setProfileImageURIWithSig( DataTypes.SetProfileImageURIWithSigData({ delegatedSigner: otherSigner, - profileId: firstProfileId, + profileId: newProfileId, imageURI: 'test', sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); - assertEq(hub.getProfileImageURI(firstProfileId), 'test'); + assertEq(hub.getProfileImageURI(newProfileId), 'test'); } function testSetFollowNFTURIWithSig() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getSetFollowNFTURITypedDatahash(firstProfileId, 'test', nonce, deadline); + bytes32 digest = _getSetFollowNFTURITypedDataHash(newProfileId, 'test', nonce, deadline); - assertEq(hub.getFollowNFTURI(firstProfileId), mockURI); + assertEq(hub.getFollowNFTURI(newProfileId), MOCK_URI); hub.setFollowNFTURIWithSig( DataTypes.SetFollowNFTURIWithSigData({ delegatedSigner: address(0), - profileId: firstProfileId, + profileId: newProfileId, followNFTURI: 'test', sig: _getSigStruct(profileOwnerKey, digest, deadline) }) ); - assertEq(hub.getFollowNFTURI(firstProfileId), 'test'); + assertEq(hub.getFollowNFTURI(newProfileId), 'test'); } function testExecutorSetFollowNFTURIWithSig() public { @@ -470,40 +335,40 @@ contract MiscTest is BaseTest { uint256 nonce = 0; uint256 deadline = type(uint256).max; - bytes32 digest = _getSetFollowNFTURITypedDatahash(firstProfileId, 'test', nonce, deadline); + bytes32 digest = _getSetFollowNFTURITypedDataHash(newProfileId, 'test', nonce, deadline); - assertEq(hub.getFollowNFTURI(firstProfileId), mockURI); + assertEq(hub.getFollowNFTURI(newProfileId), MOCK_URI); hub.setFollowNFTURIWithSig( DataTypes.SetFollowNFTURIWithSigData({ delegatedSigner: otherSigner, - profileId: firstProfileId, + profileId: newProfileId, followNFTURI: 'test', sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); - assertEq(hub.getFollowNFTURI(firstProfileId), 'test'); + assertEq(hub.getFollowNFTURI(newProfileId), 'test'); } function testSetProfileMetadataURIWithSig() public { uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getSetProfileMetadataURITypedDataHash( - firstProfileId, - mockURI, + newProfileId, + MOCK_URI, nonce, deadline ); - assertEq(hub.getProfileMetadataURI(firstProfileId), ''); + assertEq(hub.getProfileMetadataURI(newProfileId), ''); hub.setProfileMetadataURIWithSig( DataTypes.SetProfileMetadataURIWithSigData({ delegatedSigner: address(0), - profileId: firstProfileId, - metadataURI: mockURI, + profileId: newProfileId, + metadataURI: MOCK_URI, sig: _getSigStruct(profileOwnerKey, digest, deadline) }) ); - assertEq(hub.getProfileMetadataURI(firstProfileId), mockURI); + assertEq(hub.getProfileMetadataURI(newProfileId), MOCK_URI); } function testExecutorSetProfileMetadataURIWithSig() public { @@ -513,21 +378,21 @@ contract MiscTest is BaseTest { uint256 nonce = 0; uint256 deadline = type(uint256).max; bytes32 digest = _getSetProfileMetadataURITypedDataHash( - firstProfileId, - mockURI, + newProfileId, + MOCK_URI, nonce, deadline ); - assertEq(hub.getProfileMetadataURI(firstProfileId), ''); + assertEq(hub.getProfileMetadataURI(newProfileId), ''); hub.setProfileMetadataURIWithSig( DataTypes.SetProfileMetadataURIWithSigData({ delegatedSigner: otherSigner, - profileId: firstProfileId, - metadataURI: mockURI, + profileId: newProfileId, + metadataURI: MOCK_URI, sig: _getSigStruct(otherSignerKey, digest, deadline) }) ); - assertEq(hub.getProfileMetadataURI(firstProfileId), mockURI); + assertEq(hub.getProfileMetadataURI(newProfileId), MOCK_URI); } } diff --git a/test/foundry/MultiStateHubTest.t.sol b/test/foundry/MultiStateHubTest.t.sol index 6671351..d1ea9b6 100644 --- a/test/foundry/MultiStateHubTest.t.sol +++ b/test/foundry/MultiStateHubTest.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.13; import './base/BaseTest.t.sol'; -import {SigSetup} from './helpers/SignatureHelpers.sol'; +import './helpers/SignatureHelpers.sol'; contract MultiStateHubTest_Common is BaseTest { // Negatives @@ -109,15 +109,21 @@ contract MultiStateHubTest_Common is BaseTest { } contract MultiStateHubTest_PausedState_Direct is BaseTest { + uint256 postId; + function setUp() public virtual override { super.setUp(); + vm.prank(profileOwner); + postId = _post(mockPostData); + vm.prank(governance); _setState(DataTypes.ProtocolState.Paused); } + // TODO: Consider extracting these mock actions functions somewhere because they're used in several places function _mockSetFollowModule() internal virtual { - _setFollowModule(profileOwner, firstProfileId, address(0), ''); + _setFollowModule(profileOwner, newProfileId, address(0), ''); } function _mockSetDelegatedExecutorApproval() internal virtual { @@ -126,18 +132,63 @@ contract MultiStateHubTest_PausedState_Direct is BaseTest { _setDelegatedExecutorApproval(profileOwner, executor, approved); } + function _mockSetProfileImageURI() internal virtual { + _setProfileImageURI(profileOwner, newProfileId, MOCK_URI); + } + + function _mockSetFollowNFTURI() internal virtual { + _setFollowNFTURI(profileOwner, newProfileId, MOCK_URI); + } + + function _mockPost() internal virtual { + vm.prank(profileOwner); + _post(mockPostData); + } + + function _mockComment() internal virtual { + mockCommentData.pubIdPointed = postId; + vm.prank(profileOwner); + _comment(mockCommentData); + } + + function _mockMirror() internal virtual { + mockMirrorData.pubIdPointed = postId; + vm.prank(profileOwner); + _mirror(mockMirrorData); + } + + function _mockBurn() internal virtual { + _burn(profileOwner, newProfileId); + } + + function _mockFollow() internal virtual { + _follow({msgSender: me, onBehalfOf: me, profileId: newProfileId, data: ''}); + } + + // TODO: The following two functions were copy-pasted from CollectingTest.t.sol + // TODO: Consider extracting them somewhere else to be used by both of tests + function _mockCollect() internal virtual { + vm.prank(profileOwner); + _collect( + mockCollectData.collector, + mockCollectData.profileId, + mockCollectData.pubId, + mockCollectData.data + ); + } + // Negatives - function testCantTransferProfileWhilePaused() public virtual { + function testCannotTransferProfileWhilePaused() public virtual { vm.expectRevert(Errors.Paused.selector); _transferProfile({ msgSender: profileOwner, from: profileOwner, to: address(111), - tokenId: firstProfileId + tokenId: newProfileId }); } - function testCantCreateProfileWhilePaused() public virtual { + function testCannotCreateProfileWhilePaused() public virtual { vm.expectRevert(Errors.Paused.selector); _createProfile(address(this)); @@ -147,7 +198,7 @@ contract MultiStateHubTest_PausedState_Direct is BaseTest { _createProfile(address(this)); } - function testCantSetFollowModuleWhilePaused() public { + function testCannotSetFollowModuleWhilePaused() public { vm.expectRevert(Errors.Paused.selector); _mockSetFollowModule(); @@ -155,10 +206,9 @@ contract MultiStateHubTest_PausedState_Direct is BaseTest { _setState(DataTypes.ProtocolState.Unpaused); _mockSetFollowModule(); - // TODO: Consider if we should check if the follow module was set (or its enough to do that in Follow module tests) } - function testCantSetDelegatedExecutorWhilePaused() public { + function testCannotSetDelegatedExecutorWhilePaused() public { vm.expectRevert(Errors.Paused.selector); _mockSetDelegatedExecutorApproval(); @@ -166,12 +216,94 @@ contract MultiStateHubTest_PausedState_Direct is BaseTest { _setState(DataTypes.ProtocolState.Unpaused); _mockSetDelegatedExecutorApproval(); - // TODO: Consider if we should check if the delegated executor was set (or its enough to do that in DE tests) - // assertEq(hub.isDelegatedExecutorApproved(profileOwner, executor), approved); + } + + function testCannotSetProfileImageURIWhilePaused() public { + vm.expectRevert(Errors.Paused.selector); + _mockSetProfileImageURI(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockSetProfileImageURI(); + } + + function testCannotSetFollowNFTURIWhilePaused() public { + vm.expectRevert(Errors.Paused.selector); + _mockSetFollowNFTURI(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockSetFollowNFTURI(); + } + + function testCannotPostWhilePaused() public { + vm.expectRevert(Errors.PublishingPaused.selector); + _mockPost(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockPost(); + } + + function testCannotCommentWhilePaused() public { + vm.expectRevert(Errors.PublishingPaused.selector); + _mockComment(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockComment(); + } + + function testCannotMirrorWhilePaused() public { + vm.expectRevert(Errors.PublishingPaused.selector); + _mockMirror(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockMirror(); + } + + function testCannotBurnWhilePaused() public { + vm.expectRevert(Errors.Paused.selector); + _mockBurn(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockBurn(); + } + + function testCannotFollowWhilePaused() public { + vm.expectRevert(Errors.Paused.selector); + _mockFollow(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockFollow(); + } + + function testCannotCollectWhilePaused() public { + vm.expectRevert(Errors.Paused.selector); + _mockCollect(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockCollect(); } } -contract MultiStateHubTest_PausedState_WithSig is MultiStateHubTest_PausedState_Direct, SigSetup { +contract MultiStateHubTest_PausedState_WithSig is + MultiStateHubTest_PausedState_Direct, + SignatureHelpers, + SigSetup +{ function setUp() public override(MultiStateHubTest_PausedState_Direct, SigSetup) { MultiStateHubTest_PausedState_Direct.setUp(); SigSetup.setUp(); @@ -179,23 +311,22 @@ contract MultiStateHubTest_PausedState_WithSig is MultiStateHubTest_PausedState_ function _mockSetFollowModule() internal override { bytes32 digest = _getSetFollowModuleTypedDataHash( - firstProfileId, + newProfileId, address(0), '', nonce, deadline ); - return - _setFollowModuleWithSig( - DataTypes.SetFollowModuleWithSigData({ - delegatedSigner: address(0), - profileId: firstProfileId, - followModule: address(0), - followModuleInitData: '', - sig: _getSigStruct(profileOwnerKey, digest, deadline) - }) - ); + _setFollowModuleWithSig( + DataTypes.SetFollowModuleWithSigData({ + delegatedSigner: address(0), + profileId: newProfileId, + followModule: address(0), + followModuleInitData: '', + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); } // Positives @@ -220,8 +351,439 @@ contract MultiStateHubTest_PausedState_WithSig is MultiStateHubTest_PausedState_ ); } - // Methods that cannot be called with sig - function testCantTransferProfileWhilePaused() public override {} + function _mockSetProfileImageURI() internal override { + bytes32 digest = _getSetProfileImageURITypedDataHash( + newProfileId, + MOCK_URI, + nonce, + deadline + ); - function testCantCreateProfileWhilePaused() public override {} + _setProfileImageURIWithSig( + DataTypes.SetProfileImageURIWithSigData({ + delegatedSigner: address(0), + profileId: newProfileId, + imageURI: MOCK_URI, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockSetFollowNFTURI() internal override { + bytes32 digest = _getSetFollowNFTURITypedDataHash(newProfileId, MOCK_URI, nonce, deadline); + + _setFollowNFTURIWithSig( + DataTypes.SetFollowNFTURIWithSigData({ + delegatedSigner: address(0), + profileId: newProfileId, + followNFTURI: MOCK_URI, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockPost() internal override { + bytes32 digest = _getPostTypedDataHash(mockPostData, nonce, deadline); + + _postWithSig( + _buildPostWithSigData({ + delegatedSigner: address(0), + postData: mockPostData, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockComment() internal override { + mockCommentData.pubIdPointed = postId; + bytes32 digest = _getCommentTypedDataHash(mockCommentData, nonce, deadline); + + _commentWithSig( + _buildCommentWithSigData({ + delegatedSigner: address(0), + commentData: mockCommentData, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockMirror() internal override { + mockMirrorData.pubIdPointed = postId; + bytes32 digest = _getMirrorTypedDataHash(mockMirrorData, nonce, deadline); + + _mirrorWithSig( + _buildMirrorWithSigData({ + delegatedSigner: address(0), + mirrorData: mockMirrorData, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockBurn() internal override { + bytes32 digest = _getBurnTypedDataHash(newProfileId, nonce, deadline); + + _burnWithSig({ + profileId: newProfileId, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }); + } + + function _mockFollow() internal override { + bytes32 digest = _getFollowTypedDataHash( + _toUint256Array(newProfileId), + _toBytesArray(''), + nonce, + deadline + ); + + uint256[] memory nftIds = _followWithSig( + _buildFollowWithSigData({ + delegatedSigner: address(0), + follower: otherSigner, + profileIds: _toUint256Array(newProfileId), + datas: _toBytesArray(''), + sig: _getSigStruct(otherSignerKey, digest, deadline) + }) + ); + } + + function _mockCollect() internal override { + bytes32 digest = _getCollectTypedDataHash( + mockCollectData.profileId, + mockCollectData.pubId, + mockCollectData.data, + nonce, + deadline + ); + + _collectWithSig( + _buildCollectWithSigData({ + delegatedSigner: address(0), + collectData: mockCollectData, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + // Methods that cannot be called with sig + function testCannotTransferProfileWhilePaused() public override {} + + function testCannotCreateProfileWhilePaused() public override {} +} + +contract MultiStateHubTest_PublishingPausedState_Direct is BaseTest { + uint256 postId; + + function setUp() public virtual override { + super.setUp(); + + vm.prank(profileOwner); + postId = _post(mockPostData); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.PublishingPaused); + } + + // TODO: Consider extracting these mock actions functions somewhere because they're used in several places + function _mockSetFollowModule() internal virtual { + _setFollowModule(profileOwner, newProfileId, address(0), ''); + } + + function _mockSetDelegatedExecutorApproval() internal virtual { + address executor = otherSigner; + bool approved = true; + _setDelegatedExecutorApproval(profileOwner, executor, approved); + } + + function _mockSetProfileImageURI() internal virtual { + _setProfileImageURI(profileOwner, newProfileId, MOCK_URI); + } + + function _mockSetFollowNFTURI() internal virtual { + _setFollowNFTURI(profileOwner, newProfileId, MOCK_URI); + } + + function _mockPost() internal virtual { + vm.prank(profileOwner); + _post(mockPostData); + } + + function _mockComment() internal virtual { + mockCommentData.pubIdPointed = postId; + vm.prank(profileOwner); + _comment(mockCommentData); + } + + function _mockMirror() internal virtual { + mockMirrorData.pubIdPointed = postId; + vm.prank(profileOwner); + _mirror(mockMirrorData); + } + + function _mockBurn() internal virtual { + _burn(profileOwner, newProfileId); + } + + function _mockFollow() internal virtual { + _follow({msgSender: me, onBehalfOf: me, profileId: newProfileId, data: ''}); + } + + // TODO: The following two functions were copy-pasted from CollectingTest.t.sol + // TODO: Consider extracting them somewhere else to be used by both of tests + function _mockCollect() internal virtual { + vm.prank(profileOwner); + _collect( + mockCollectData.collector, + mockCollectData.profileId, + mockCollectData.pubId, + mockCollectData.data + ); + } + + // Negatives + function testCanTransferProfileWhilePublishingPaused() public virtual { + _transferProfile({ + msgSender: profileOwner, + from: profileOwner, + to: address(111), + tokenId: newProfileId + }); + } + + function testCanCreateProfileWhilePublishingPaused() public virtual { + _createProfile(address(this)); + } + + function testCanSetFollowModuleWhilePublishingPaused() public { + _mockSetFollowModule(); + } + + function testCanSetDelegatedExecutorWhilePublishingPaused() public { + _mockSetDelegatedExecutorApproval(); + } + + function testCanSetProfileImageURIWhilePublishingPaused() public { + _mockSetProfileImageURI(); + } + + function testCanSetFollowNFTURIWhilePublishingPaused() public { + _mockSetFollowNFTURI(); + } + + function testCanBurnWhilePublishingPaused() public { + _mockBurn(); + } + + function testCanFollowWhilePublishingPaused() public { + _mockFollow(); + } + + function testCanCollectWhilePublishingPaused() public { + _mockCollect(); + } + + function testCannotPostWhilePublishingPaused() public { + vm.expectRevert(Errors.PublishingPaused.selector); + _mockPost(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockPost(); + } + + function testCannotCommentWhilePublishingPaused() public { + vm.expectRevert(Errors.PublishingPaused.selector); + _mockComment(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockComment(); + } + + function testCannotMirrorWhilePublishingPaused() public { + vm.expectRevert(Errors.PublishingPaused.selector); + _mockMirror(); + + vm.prank(governance); + _setState(DataTypes.ProtocolState.Unpaused); + + _mockMirror(); + } +} + +contract MultiStateHubTest_PublishingPausedState_WithSig is + MultiStateHubTest_PublishingPausedState_Direct, + SignatureHelpers, + SigSetup +{ + // TODO: Consider refactoring this contract somehow cause it's all just pure copy-paste of the PausedState_WithSig + function setUp() public override(MultiStateHubTest_PublishingPausedState_Direct, SigSetup) { + MultiStateHubTest_PublishingPausedState_Direct.setUp(); + SigSetup.setUp(); + } + + function _mockSetFollowModule() internal override { + bytes32 digest = _getSetFollowModuleTypedDataHash( + newProfileId, + address(0), + '', + nonce, + deadline + ); + + _setFollowModuleWithSig( + DataTypes.SetFollowModuleWithSigData({ + delegatedSigner: address(0), + profileId: newProfileId, + followModule: address(0), + followModuleInitData: '', + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + // Positives + function _mockSetDelegatedExecutorApproval() internal override { + address onBehalfOf = profileOwner; + address executor = otherSigner; + + bytes32 digest = _getSetDelegatedExecutorApprovalTypedDataHash({ + onBehalfOf: onBehalfOf, + executor: executor, + approved: true, + nonce: nonce, + deadline: deadline + }); + hub.setDelegatedExecutorApprovalWithSig( + _buildSetDelegatedExecutorApprovalWithSigData({ + onBehalfOf: onBehalfOf, + executor: executor, + approved: true, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockSetProfileImageURI() internal override { + bytes32 digest = _getSetProfileImageURITypedDataHash( + newProfileId, + MOCK_URI, + nonce, + deadline + ); + + _setProfileImageURIWithSig( + DataTypes.SetProfileImageURIWithSigData({ + delegatedSigner: address(0), + profileId: newProfileId, + imageURI: MOCK_URI, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockSetFollowNFTURI() internal override { + bytes32 digest = _getSetFollowNFTURITypedDataHash(newProfileId, MOCK_URI, nonce, deadline); + + _setFollowNFTURIWithSig( + DataTypes.SetFollowNFTURIWithSigData({ + delegatedSigner: address(0), + profileId: newProfileId, + followNFTURI: MOCK_URI, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockPost() internal override { + bytes32 digest = _getPostTypedDataHash(mockPostData, nonce, deadline); + + _postWithSig( + _buildPostWithSigData({ + delegatedSigner: address(0), + postData: mockPostData, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockComment() internal override { + mockCommentData.pubIdPointed = postId; + bytes32 digest = _getCommentTypedDataHash(mockCommentData, nonce, deadline); + + _commentWithSig( + _buildCommentWithSigData({ + delegatedSigner: address(0), + commentData: mockCommentData, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockMirror() internal override { + mockMirrorData.pubIdPointed = postId; + bytes32 digest = _getMirrorTypedDataHash(mockMirrorData, nonce, deadline); + + _mirrorWithSig( + _buildMirrorWithSigData({ + delegatedSigner: address(0), + mirrorData: mockMirrorData, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function _mockBurn() internal override { + bytes32 digest = _getBurnTypedDataHash(newProfileId, nonce, deadline); + + _burnWithSig({ + profileId: newProfileId, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }); + } + + function _mockFollow() internal override { + bytes32 digest = _getFollowTypedDataHash( + _toUint256Array(newProfileId), + _toBytesArray(''), + nonce, + deadline + ); + + uint256[] memory nftIds = _followWithSig( + _buildFollowWithSigData({ + delegatedSigner: address(0), + follower: otherSigner, + profileIds: _toUint256Array(newProfileId), + datas: _toBytesArray(''), + sig: _getSigStruct(otherSignerKey, digest, deadline) + }) + ); + } + + function _mockCollect() internal override { + bytes32 digest = _getCollectTypedDataHash( + mockCollectData.profileId, + mockCollectData.pubId, + mockCollectData.data, + nonce, + deadline + ); + + _collectWithSig( + _buildCollectWithSigData({ + delegatedSigner: address(0), + collectData: mockCollectData, + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + // Methods that cannot be called with sig + function testCanTransferProfileWhilePublishingPaused() public override {} + + function testCanCreateProfileWhilePublishingPaused() public override {} } diff --git a/test/foundry/PublishingTest.t.sol b/test/foundry/PublishingTest.t.sol index b8b7be7..588eb70 100644 --- a/test/foundry/PublishingTest.t.sol +++ b/test/foundry/PublishingTest.t.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.13; import './base/BaseTest.t.sol'; import './helpers/SignatureHelpers.sol'; import {PublishingHelpers} from './helpers/PublishingHelpers.sol'; -import {SigSetup} from './helpers/SignatureHelpers.sol'; contract PublishingTest_Post is BaseTest, SignatureHelpers, PublishingHelpers, SigSetup { function replicateInitData() internal virtual {} @@ -113,7 +112,7 @@ contract PublishingTest_Post is BaseTest, SignatureHelpers, PublishingHelpers, S function testCannotPublishIfNonceWasIncrementedWithAnotherAction() public { assertEq(_getSigNonce(profileOwner), nonce, 'Wrong nonce before posting'); - uint256 expectedPubId = _getPubCount(firstProfileId) + 1; + uint256 expectedPubId = _getPubCount(newProfileId) + 1; uint256 pubId = _publishWithSig({ delegatedSigner: address(0), @@ -142,14 +141,14 @@ contract PublishingTest_Post is BaseTest, SignatureHelpers, PublishingHelpers, S // positives function testPublish() public { - uint256 expectedPubId = _getPubCount(firstProfileId) + 1; + uint256 expectedPubId = _getPubCount(newProfileId) + 1; vm.prank(profileOwner); uint256 pubId = _publish(); assertEq(pubId, expectedPubId); - DataTypes.PublicationStruct memory pub = _getPub(firstProfileId, pubId); + DataTypes.PublicationStruct memory pub = _getPub(newProfileId, pubId); _verifyPublication(pub, _expectedPubFromInitData()); } @@ -158,19 +157,19 @@ contract PublishingTest_Post is BaseTest, SignatureHelpers, PublishingHelpers, S mockPostData.referenceModuleInitData = abi.encode(1); replicateInitData(); - uint256 expectedPubId = _getPubCount(firstProfileId) + 1; + uint256 expectedPubId = _getPubCount(newProfileId) + 1; vm.prank(profileOwner); uint256 pubId = _publish(); assertEq(pubId, expectedPubId); - DataTypes.PublicationStruct memory pub = _getPub(firstProfileId, pubId); + DataTypes.PublicationStruct memory pub = _getPub(newProfileId, pubId); _verifyPublication(pub, _expectedPubFromInitData()); } function testPublishWithSig() public { - uint256 expectedPubId = _getPubCount(firstProfileId) + 1; + uint256 expectedPubId = _getPubCount(newProfileId) + 1; uint256 pubId = _publishWithSig({ delegatedSigner: address(0), @@ -178,36 +177,34 @@ contract PublishingTest_Post is BaseTest, SignatureHelpers, PublishingHelpers, S }); assertEq(pubId, expectedPubId); - DataTypes.PublicationStruct memory pub = _getPub(firstProfileId, pubId); + DataTypes.PublicationStruct memory pub = _getPub(newProfileId, pubId); _verifyPublication(pub, _expectedPubFromInitData()); } function testExecutorPublish() public { - vm.prank(profileOwner); - _setDelegatedExecutorApproval(otherSigner, true); + _setDelegatedExecutorApproval(profileOwner, otherSigner, true); - uint256 expectedPubId = _getPubCount(firstProfileId) + 1; + uint256 expectedPubId = _getPubCount(newProfileId) + 1; vm.prank(otherSigner); uint256 pubId = _publish(); assertEq(pubId, expectedPubId); - DataTypes.PublicationStruct memory pub = _getPub(firstProfileId, pubId); + DataTypes.PublicationStruct memory pub = _getPub(newProfileId, pubId); _verifyPublication(pub, _expectedPubFromInitData()); } function testExecutorPublishWithSig() public { - vm.prank(profileOwner); - _setDelegatedExecutorApproval(otherSigner, true); + _setDelegatedExecutorApproval(profileOwner, otherSigner, true); - uint256 expectedPubId = _getPubCount(firstProfileId) + 1; + uint256 expectedPubId = _getPubCount(newProfileId) + 1; uint256 pubId = _publishWithSig({ delegatedSigner: otherSigner, signerPrivKey: otherSignerKey }); assertEq(pubId, expectedPubId); - DataTypes.PublicationStruct memory pub = _getPub(firstProfileId, pubId); + DataTypes.PublicationStruct memory pub = _getPub(newProfileId, pubId); _verifyPublication(pub, _expectedPubFromInitData()); } } @@ -264,7 +261,7 @@ contract PublishingTest_Comment is PublishingTest_Post { // negatives function testCannotCommentOnNonExistentPublication() public { - uint256 nonExistentPubId = _getPubCount(firstProfileId) + 10; + uint256 nonExistentPubId = _getPubCount(newProfileId) + 10; replicateInitData(); mockCommentData.pubIdPointed = nonExistentPubId; @@ -275,7 +272,7 @@ contract PublishingTest_Comment is PublishingTest_Post { } function testCannotCommentWithSigOnNonExistentPublication() public { - uint256 nonExistentPubId = _getPubCount(firstProfileId) + 10; + uint256 nonExistentPubId = _getPubCount(newProfileId) + 10; replicateInitData(); mockCommentData.pubIdPointed = nonExistentPubId; @@ -285,7 +282,7 @@ contract PublishingTest_Comment is PublishingTest_Post { } function testCannotCommentOnTheSamePublicationBeingCreated() public { - uint256 nextPubId = _getPubCount(firstProfileId) + 1; + uint256 nextPubId = _getPubCount(newProfileId) + 1; replicateInitData(); mockCommentData.pubIdPointed = nextPubId; @@ -296,7 +293,7 @@ contract PublishingTest_Comment is PublishingTest_Post { } function testCannotCommentWithSigOnTheSamePublicationBeingCreated() public { - uint256 nextPubId = _getPubCount(firstProfileId) + 1; + uint256 nextPubId = _getPubCount(newProfileId) + 1; replicateInitData(); mockCommentData.pubIdPointed = nextPubId; @@ -316,7 +313,7 @@ contract PublishingTest_Comment is PublishingTest_Post { vm.prank(profileOwner); uint256 commentPubId = _publish(); - DataTypes.PublicationStruct memory pub = _getPub(firstProfileId, commentPubId); + DataTypes.PublicationStruct memory pub = _getPub(newProfileId, commentPubId); _verifyPublication(pub, _expectedPubFromInitData()); } } @@ -376,7 +373,7 @@ contract PublishingTest_Mirror is PublishingTest_Post { // negatives function testCannotMirrorNonExistentPublication() public { - uint256 nonExistentPubId = _getPubCount(firstProfileId) + 10; + uint256 nonExistentPubId = _getPubCount(newProfileId) + 10; replicateInitData(); mockMirrorData.pubIdPointed = nonExistentPubId; @@ -387,7 +384,7 @@ contract PublishingTest_Mirror is PublishingTest_Post { } function testCannotMirrorWithSigNonExistentPublication() public { - uint256 nonExistentPubId = _getPubCount(firstProfileId) + 10; + uint256 nonExistentPubId = _getPubCount(newProfileId) + 10; replicateInitData(); mockMirrorData.pubIdPointed = nonExistentPubId; @@ -406,7 +403,7 @@ contract PublishingTest_Mirror is PublishingTest_Post { vm.prank(profileOwner); uint256 secondMirrorId = _publish(); - DataTypes.PublicationStruct memory pub = _getPub(firstProfileId, secondMirrorId); + DataTypes.PublicationStruct memory pub = _getPub(newProfileId, secondMirrorId); mockMirrorData.pubIdPointed = postId; // We're expecting a mirror to point at the original post ID _verifyPublication(pub, _expectedPubFromInitData(mockMirrorData)); } @@ -422,7 +419,7 @@ contract PublishingTest_Mirror is PublishingTest_Post { signerPrivKey: profileOwnerKey }); - DataTypes.PublicationStruct memory pub = _getPub(firstProfileId, secondMirrorId); + DataTypes.PublicationStruct memory pub = _getPub(newProfileId, secondMirrorId); mockMirrorData.pubIdPointed = postId; // We're expecting a mirror to point at the original post ID _verifyPublication(pub, _expectedPubFromInitData(mockMirrorData)); } diff --git a/test/foundry/SetFollowModule.t.sol b/test/foundry/SetFollowModule.t.sol new file mode 100644 index 0000000..73ee85f --- /dev/null +++ b/test/foundry/SetFollowModule.t.sol @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import './base/BaseTest.t.sol'; +import '../../contracts/mocks/MockFollowModule.sol'; +import './helpers/SignatureHelpers.sol'; + +// TODO: Refactor out all `hub.` calls (if we decide to go this route) +contract SetFollowModuleTest is BaseTest, SignatureHelpers, SigSetup { + address mockFollowModule; + + function setUp() public virtual override(SigSetup, TestSetup) { + TestSetup.setUp(); + SigSetup.setUp(); + mockFollowModule = address(new MockFollowModule()); + vm.prank(governance); + hub.whitelistFollowModule(mockFollowModule, true); + } + + function _setFollowModulehWithSig(address delegatedSigner, uint256 signerPrivKey) + internal + virtual + { + _setFollowModulehWithSig(delegatedSigner, signerPrivKey, deadline, deadline); + } + + function _setFollowModulehWithSig( + address delegatedSigner, + uint256 signerPrivKey, + uint256 digestDeadline, + uint256 sigDeadline + ) internal virtual { + bytes32 digest = _getSetFollowModuleTypedDataHash( + newProfileId, + mockFollowModule, + abi.encode(1), + nonce, + digestDeadline + ); + + hub.setFollowModuleWithSig( + DataTypes.SetFollowModuleWithSigData({ + delegatedSigner: delegatedSigner, + profileId: newProfileId, + followModule: mockFollowModule, + followModuleInitData: abi.encode(1), + sig: _getSigStruct(signerPrivKey, digest, sigDeadline) + }) + ); + } + + // Negatives + function testCannotSetFollowModuleNotExecutor() public { + vm.expectRevert(Errors.ExecutorInvalid.selector); + hub.setFollowModule(newProfileId, address(0), ''); + } + + function testCannotSetFollowModuleNotWhitelisted() public { + vm.expectRevert(Errors.FollowModuleNotWhitelisted.selector); + vm.prank(profileOwner); + hub.setFollowModule(newProfileId, address(1), ''); + } + + function testCannotSetFollowModuleWithWrongInitData() public { + vm.expectRevert(bytes('')); + vm.prank(profileOwner); + hub.setFollowModule(newProfileId, mockFollowModule, ''); + } + + // Positives + function testSetFollowModule() public { + vm.prank(profileOwner); + hub.setFollowModule(newProfileId, mockFollowModule, abi.encode(1)); + assertEq(hub.getFollowModule(newProfileId), mockFollowModule); + + vm.prank(profileOwner); + hub.setFollowModule(newProfileId, address(0), ''); + assertEq(hub.getFollowModule(newProfileId), address(0)); + } + + function testExecutorSetFollowModule() public { + assertEq(hub.getFollowModule(newProfileId), address(0)); + vm.prank(profileOwner); + hub.setDelegatedExecutorApproval(otherSigner, true); + + address mockFollowModule = address(new MockFollowModule()); + vm.prank(governance); + hub.whitelistFollowModule(mockFollowModule, true); + + vm.prank(otherSigner); + hub.setFollowModule(newProfileId, mockFollowModule, abi.encode(1)); + assertEq(hub.getFollowModule(newProfileId), mockFollowModule); + } + + // Meta-tx + // Negatives + function testCannotSetFollowModuleNotWhitelistedWithSig() public { + vm.expectRevert(Errors.FollowModuleNotWhitelisted.selector); + bytes32 digest = _getSetFollowModuleTypedDataHash( + newProfileId, + address(1), + '', + nonce, + deadline + ); + + hub.setFollowModuleWithSig( + DataTypes.SetFollowModuleWithSigData({ + delegatedSigner: address(0), + profileId: newProfileId, + followModule: address(1), + followModuleInitData: '', + sig: _getSigStruct(profileOwnerKey, digest, deadline) + }) + ); + } + + function testCannotPublishWithSigInvalidSigner() public { + vm.expectRevert(Errors.SignatureInvalid.selector); + _setFollowModulehWithSig({delegatedSigner: address(0), signerPrivKey: otherSignerKey}); + } + + function testCannotPublishWithSigInvalidNonce() public { + nonce = _getSigNonce(otherSigner) + 1; + vm.expectRevert(Errors.SignatureInvalid.selector); + _setFollowModulehWithSig({delegatedSigner: address(0), signerPrivKey: otherSignerKey}); + } + + function testCannotPublishWithSigInvalidDeadline() public { + vm.expectRevert(Errors.SignatureInvalid.selector); + _setFollowModulehWithSig({ + delegatedSigner: address(0), + signerPrivKey: profileOwnerKey, + digestDeadline: type(uint256).max, + sigDeadline: block.timestamp + 10 + }); + } + + function testCannotPublishIfNonceWasIncrementedWithAnotherAction() public { + assertEq(_getSigNonce(profileOwner), nonce, 'Wrong nonce before posting'); + + _setFollowModulehWithSig({delegatedSigner: address(0), signerPrivKey: profileOwnerKey}); + + assertTrue(_getSigNonce(profileOwner) != nonce, 'Wrong nonce after posting'); + + vm.expectRevert(Errors.SignatureInvalid.selector); + _setFollowModulehWithSig({delegatedSigner: address(0), signerPrivKey: profileOwnerKey}); + } + + function testCannotPublishWithSigExpiredDeadline() public { + deadline = 10; + vm.warp(20); + + vm.expectRevert(Errors.SignatureExpired.selector); + _setFollowModulehWithSig({delegatedSigner: address(0), signerPrivKey: otherSignerKey}); + } + + function testCannotPublishWithSigNotExecutor() public { + vm.expectRevert(Errors.ExecutorInvalid.selector); + _setFollowModulehWithSig({delegatedSigner: otherSigner, signerPrivKey: otherSignerKey}); + } + + function testSetFollowModuleWithSigNotExecutorFails() public { + vm.expectRevert(Errors.ExecutorInvalid.selector); + _setFollowModulehWithSig({delegatedSigner: otherSigner, signerPrivKey: otherSignerKey}); + } + + // Postivies + function testPublishWithSig() public { + assertEq(hub.getFollowModule(newProfileId), address(0)); + _setFollowModulehWithSig({delegatedSigner: address(0), signerPrivKey: profileOwnerKey}); + assertEq(hub.getFollowModule(newProfileId), mockFollowModule); + } + + function testExecutorPublishWithSig() public { + _setDelegatedExecutorApproval(profileOwner, otherSigner, true); + + assertEq(hub.getFollowModule(newProfileId), address(0)); + _setFollowModulehWithSig({delegatedSigner: otherSigner, signerPrivKey: otherSignerKey}); + assertEq(hub.getFollowModule(newProfileId), mockFollowModule); + } +} diff --git a/test/foundry/base/BaseTest.t.sol b/test/foundry/base/BaseTest.t.sol index de2d919..1a677c5 100644 --- a/test/foundry/base/BaseTest.t.sol +++ b/test/foundry/base/BaseTest.t.sol @@ -93,7 +93,7 @@ contract BaseTest is TestSetup { return _calculateDigest(structHash); } - function _getSetFollowNFTURITypedDatahash( + function _getSetFollowNFTURITypedDataHash( uint256 profileId, string memory followNFTURI, uint256 nonce, @@ -111,6 +111,17 @@ contract BaseTest is TestSetup { return _calculateDigest(structHash); } + function _getBurnTypedDataHash( + uint256 profileId, + uint256 nonce, + uint256 deadline + ) internal view returns (bytes32) { + bytes32 structHash = keccak256( + abi.encode(BURN_WITH_SIG_TYPEHASH, profileId, nonce, deadline) + ); + return _calculateDigest(structHash); + } + function _getPostTypedDataHash( uint256 profileId, string memory contentURI, @@ -385,24 +396,21 @@ contract BaseTest is TestSetup { return hub.collectWithSig(collectWithSigData); } - function _setDelegatedExecutorApproval(address executor, bool approved) internal { - hub.setDelegatedExecutorApproval(executor, approved); + function _follow( + address msgSender, + address onBehalfOf, + uint256 profileId, + bytes memory data + ) internal returns (uint256[] memory) { + vm.prank(msgSender); + return hub.follow(onBehalfOf, _toUint256Array(profileId), _toBytesArray(data)); } - function _getPub(uint256 profileId, uint256 pubId) + function _followWithSig(DataTypes.FollowWithSigData memory vars) internal - view - returns (DataTypes.PublicationStruct memory) + returns (uint256[] memory) { - return hub.getPub(profileId, pubId); - } - - function _getSigNonce(address signer) internal view returns (uint256) { - return hub.sigNonces(signer); - } - - function _getPubCount(uint256 profileId) internal view returns (uint256) { - return hub.getPubCount(profileId); + return hub.followWithSig(vars); } function _createProfile(address newProfileOwner) internal returns (uint256) { @@ -461,7 +469,60 @@ contract BaseTest is TestSetup { function _setFollowModuleWithSig(DataTypes.SetFollowModuleWithSigData memory vars) internal { hub.setFollowModuleWithSig(vars); } - + + function _setProfileImageURI( + address msgSender, + uint256 profileId, + string memory imageURI + ) internal { + vm.prank(msgSender); + hub.setProfileImageURI(profileId, imageURI); + } + + function _setProfileImageURIWithSig(DataTypes.SetProfileImageURIWithSigData memory vars) + internal + { + hub.setProfileImageURIWithSig(vars); + } + + function _setFollowNFTURI( + address msgSender, + uint256 profileId, + string memory followNFTURI + ) internal { + vm.prank(msgSender); + hub.setFollowNFTURI(profileId, followNFTURI); + } + + function _setFollowNFTURIWithSig(DataTypes.SetFollowNFTURIWithSigData memory vars) internal { + hub.setFollowNFTURIWithSig(vars); + } + + function _burn(address msgSender, uint256 profileId) internal { + vm.prank(msgSender); + hub.burn(profileId); + } + + function _burnWithSig(uint256 profileId, DataTypes.EIP712Signature memory sig) internal { + hub.burnWithSig(profileId, sig); + } + + function _getPub(uint256 profileId, uint256 pubId) + internal + view + returns (DataTypes.PublicationStruct memory) + { + return hub.getPub(profileId, pubId); + } + + function _getSigNonce(address signer) internal view returns (uint256) { + return hub.sigNonces(signer); + } + + function _getPubCount(uint256 profileId) internal view returns (uint256) { + return hub.getPubCount(profileId); + } + function _getCollectCount(uint256 profileId, uint256 pubId) internal view returns (uint256) { address collectNft = hub.getCollectNFT(profileId, pubId); if (collectNft == address(0)) { diff --git a/test/foundry/base/TestSetup.t.sol b/test/foundry/base/TestSetup.t.sol index 084908a..b2df7b3 100644 --- a/test/foundry/base/TestSetup.t.sol +++ b/test/foundry/base/TestSetup.t.sol @@ -4,34 +4,50 @@ pragma solidity ^0.8.13; import 'forge-std/Test.sol'; // Deployments -import '../../../contracts/core/LensHub.sol'; -import '../../../contracts/core/FollowNFT.sol'; -import '../../../contracts/core/CollectNFT.sol'; -import '../../../contracts/upgradeability/TransparentUpgradeableProxy.sol'; -import '../../../contracts/libraries/DataTypes.sol'; -import '../../../contracts/libraries/Constants.sol'; -import '../../../contracts/libraries/Errors.sol'; -import '../../../contracts/libraries/GeneralLib.sol'; -import '../../../contracts/libraries/ProfileTokenURILogic.sol'; -import '../../../contracts/mocks/MockCollectModule.sol'; -import '../../../contracts/mocks/MockReferenceModule.sol'; +import {ILensHub} from 'contracts/interfaces/ILensHub.sol'; +import {LensHub} from 'contracts/core/LensHub.sol'; +import {FollowNFT} from 'contracts/core/FollowNFT.sol'; +import {CollectNFT} from 'contracts/core/CollectNFT.sol'; +import {ModuleGlobals} from 'contracts/core/modules/ModuleGlobals.sol'; +import {TransparentUpgradeableProxy} from 'contracts/upgradeability/TransparentUpgradeableProxy.sol'; +import {DataTypes} from 'contracts/libraries/DataTypes.sol'; +import 'contracts/libraries/Constants.sol'; +import {Errors} from 'contracts/libraries/Errors.sol'; +import {GeneralLib} from 'contracts/libraries/GeneralLib.sol'; +import {ProfileTokenURILogic} from 'contracts/libraries/ProfileTokenURILogic.sol'; +import {MockCollectModule} from 'contracts/mocks/MockCollectModule.sol'; +import {MockReferenceModule} from 'contracts/mocks/MockReferenceModule.sol'; +import '../helpers/ForkManagement.sol'; +import '../constants.sol'; -contract TestSetup is Test { - uint256 constant firstProfileId = 1; - address constant deployer = address(1); - // UserOne is the test address, replaced with "me." - address constant governance = address(2); +contract TestSetup is Test, ForkManagement { + using stdJson for string; + + string forkEnv; + bool fork; + string network; + string json; + uint256 forkBlockNumber; + + uint256 newProfileId; + address deployer; + address governance; + address treasury; + + string constant MOCK_URI = 'ipfs://QmUXfQWe43RKx31VzA2BnbwhSMW8WuaJvszFWChD59m76U'; - string constant mockHandle = 'handle.lens'; - string constant mockURI = 'ipfs://QmUXfQWe43RKx31VzA2BnbwhSMW8WuaJvszFWChD59m76U'; - uint256 constant profileOwnerKey = 0x04546b; uint256 constant otherSignerKey = 0x737562; + uint256 constant profileOwnerKey = 0x04546b; + address immutable profileOwner = vm.addr(profileOwnerKey); + address immutable otherSigner = vm.addr(otherSignerKey); + address immutable me = address(this); - address profileOwner = vm.addr(profileOwnerKey); - address otherSigner = vm.addr(otherSignerKey); - address me = address(this); bytes32 domainSeparator; + uint16 TREASURY_FEE_BPS; + uint16 constant TREASURY_FEE_MAX_BPS = 10000; + + address hubProxyAddr; CollectNFT collectNFT; FollowNFT followNFT; LensHub hubImpl; @@ -39,6 +55,7 @@ contract TestSetup is Test { LensHub hub; MockCollectModule mockCollectModule; MockReferenceModule mockReferenceModule; + ModuleGlobals moduleGlobals; DataTypes.CreateProfileData mockCreateProfileData; @@ -47,14 +64,112 @@ contract TestSetup is Test { DataTypes.MirrorData mockMirrorData; DataTypes.CollectData mockCollectData; - function setUp() public virtual { - // Start deployments. + function isEnvSet(string memory key) internal returns (bool) { + try vm.envString(key) { + return true; + } catch { + return false; + } + } + + constructor() { + // TODO: Replace with envOr when it's released + forkEnv = isEnvSet('TESTING_FORK') ? vm.envString('TESTING_FORK') : ''; + + if (bytes(forkEnv).length > 0) { + fork = true; + console.log('\n\n Testing using %s fork', forkEnv); + json = loadJson(); + + network = getNetwork(json, forkEnv); + + if (isEnvSet('FORK_BLOCK')) { + forkBlockNumber = vm.envUint('FORK_BLOCK'); + vm.createSelectFork(network, forkBlockNumber); + console.log('Fork Block number (FIXED BLOCK):', forkBlockNumber); + } else { + vm.createSelectFork(network); + forkBlockNumber = block.number; + console.log('Fork Block number:', forkBlockNumber); + } + + checkNetworkParams(json, forkEnv); + + loadBaseAddresses(forkEnv); + } else { + deployBaseContracts(); + } + ///////////////////////////////////////// Start governance actions. + vm.startPrank(governance); + + if (hub.getState() != DataTypes.ProtocolState.Unpaused) + hub.setState(DataTypes.ProtocolState.Unpaused); + + // Whitelist the test contract as a profile creator + hub.whitelistProfileCreator(me, true); + + vm.stopPrank(); + ///////////////////////////////////////// End governance actions. + } + + // TODO: Replace with forge-std/StdJson.sol::keyExists(...) when/if this PR is approved: + // https://github.com/foundry-rs/forge-std/pull/226 + function keyExists(string memory key) internal returns (bool) { + return json.parseRaw(key).length > 0; + } + + function loadBaseAddresses(string memory targetEnv) internal virtual { + bytes32 PROXY_IMPLEMENTATION_STORAGE_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + console.log('targetEnv:', targetEnv); + + hubProxyAddr = json.readAddress(string(abi.encodePacked('.', targetEnv, '.LensHubProxy'))); + console.log('hubProxyAddr:', hubProxyAddr); + + hub = LensHub(hubProxyAddr); + + console.log('Hub:', address(hub)); + + address followNFTAddr = hub.getFollowNFTImpl(); + address collectNFTAddr = hub.getCollectNFTImpl(); + + address hubImplAddr = address( + uint160(uint256(vm.load(hubProxyAddr, PROXY_IMPLEMENTATION_STORAGE_SLOT))) + ); + console.log('Found hubImplAddr:', hubImplAddr); + hubImpl = LensHub(hubImplAddr); + followNFT = FollowNFT(followNFTAddr); + collectNFT = CollectNFT(collectNFTAddr); + hubAsProxy = TransparentUpgradeableProxy(payable(address(hub))); + moduleGlobals = ModuleGlobals( + json.readAddress(string(abi.encodePacked('.', targetEnv, '.ModuleGlobals'))) + ); + + newProfileId = uint256(vm.load(hubProxyAddr, bytes32(uint256(22)))) + 1; + console.log('newProfileId:', newProfileId); + + deployer = address(1); + + governance = hub.getGovernance(); + treasury = moduleGlobals.getTreasury(); + + TREASURY_FEE_BPS = moduleGlobals.getTreasuryFee(); + } + + function deployBaseContracts() internal { + newProfileId = FIRST_PROFILE_ID; + deployer = address(1); + governance = address(2); + + TREASURY_FEE_BPS = 50; + + ///////////////////////////////////////// Start deployments. vm.startPrank(deployer); // Precompute needed addresss. address followNFTAddr = computeCreateAddress(deployer, 1); address collectNFTAddr = computeCreateAddress(deployer, 2); - address hubProxyAddr = computeCreateAddress(deployer, 3); + hubProxyAddr = computeCreateAddress(deployer, 3); // Deploy implementation contracts. hubImpl = new LensHub(followNFTAddr, collectNFTAddr); @@ -77,27 +192,23 @@ contract TestSetup is Test { // Deploy the MockReferenceModule. mockReferenceModule = new MockReferenceModule(); - // End deployments. vm.stopPrank(); + ///////////////////////////////////////// End deployments. // Start governance actions. vm.startPrank(governance); - // Set the state to unpaused. - hub.setState(DataTypes.ProtocolState.Unpaused); - // Whitelist the FreeCollectModule. hub.whitelistCollectModule(address(mockCollectModule), true); // Whitelist the MockReferenceModule. hub.whitelistReferenceModule(address(mockReferenceModule), true); - // Whitelist the test contract as a profile creator - hub.whitelistProfileCreator(me, true); - // End governance actions. vm.stopPrank(); + } + function setUp() public virtual { // Compute the domain separator. domainSeparator = keccak256( abi.encode( @@ -112,16 +223,16 @@ contract TestSetup is Test { // precompute basic profile creaton data. mockCreateProfileData = DataTypes.CreateProfileData({ to: profileOwner, - imageURI: mockURI, + imageURI: MOCK_URI, followModule: address(0), followModuleInitData: '', - followNFTURI: mockURI + followNFTURI: MOCK_URI }); // Precompute basic post data. mockPostData = DataTypes.PostData({ - profileId: firstProfileId, - contentURI: mockURI, + profileId: newProfileId, + contentURI: MOCK_URI, collectModule: address(mockCollectModule), collectModuleInitData: abi.encode(1), referenceModule: address(0), @@ -130,10 +241,10 @@ contract TestSetup is Test { // Precompute basic comment data. mockCommentData = DataTypes.CommentData({ - profileId: firstProfileId, - contentURI: mockURI, - profileIdPointed: firstProfileId, - pubIdPointed: 1, + profileId: newProfileId, + contentURI: MOCK_URI, + profileIdPointed: newProfileId, + pubIdPointed: FIRST_PUB_ID, referenceModuleData: '', collectModule: address(mockCollectModule), collectModuleInitData: abi.encode(1), @@ -143,9 +254,9 @@ contract TestSetup is Test { // Precompute basic mirror data. mockMirrorData = DataTypes.MirrorData({ - profileId: firstProfileId, - profileIdPointed: firstProfileId, - pubIdPointed: 1, + profileId: newProfileId, + profileIdPointed: newProfileId, + pubIdPointed: FIRST_PUB_ID, referenceModuleData: '', referenceModule: address(0), referenceModuleInitData: '' @@ -154,8 +265,8 @@ contract TestSetup is Test { // Precompute basic collect data. mockCollectData = DataTypes.CollectData({ collector: profileOwner, - profileId: firstProfileId, - pubId: 1, + profileId: newProfileId, + pubId: FIRST_PUB_ID, data: '' }); diff --git a/test/foundry/fork/UpgradeForkTest.t.sol b/test/foundry/fork/UpgradeForkTest.t.sol index 6ad29d7..31afe18 100644 --- a/test/foundry/fork/UpgradeForkTest.t.sol +++ b/test/foundry/fork/UpgradeForkTest.t.sol @@ -149,10 +149,10 @@ contract UpgradeForkTest is BaseTest { // precompute basic profile creaton data. mockCreateProfileData = DataTypes.CreateProfileData({ to: me, - imageURI: mockURI, + imageURI: MOCK_URI, followModule: address(0), followModuleInitData: abi.encode(1), - followNFTURI: mockURI + followNFTURI: MOCK_URI }); OldCreateProfileData memory oldCreateProfileData = OldCreateProfileData( @@ -374,16 +374,16 @@ contract UpgradeForkTest is BaseTest { // precompute basic profile creaton data. mockCreateProfileData = DataTypes.CreateProfileData({ to: me, - imageURI: mockURI, + imageURI: MOCK_URI, followModule: address(0), followModuleInitData: abi.encode(1), - followNFTURI: mockURI + followNFTURI: MOCK_URI }); // Precompute basic post data. mockPostData = DataTypes.PostData({ profileId: 0, - contentURI: mockURI, + contentURI: MOCK_URI, collectModule: address(0), collectModuleInitData: abi.encode(1), referenceModule: address(0), @@ -393,8 +393,8 @@ contract UpgradeForkTest is BaseTest { // Precompute basic comment data. mockCommentData = DataTypes.CommentData({ profileId: 0, - contentURI: mockURI, - profileIdPointed: firstProfileId, + contentURI: MOCK_URI, + profileIdPointed: newProfileId, pubIdPointed: 1, referenceModuleData: '', collectModule: address(0), @@ -406,7 +406,7 @@ contract UpgradeForkTest is BaseTest { // Precompute basic mirror data. mockMirrorData = DataTypes.MirrorData({ profileId: 0, - profileIdPointed: firstProfileId, + profileIdPointed: newProfileId, pubIdPointed: 1, referenceModuleData: '', referenceModule: address(0), diff --git a/test/foundry/helpers/CollectingHelpers.sol b/test/foundry/helpers/CollectingHelpers.sol index c014ffd..55e22ac 100644 --- a/test/foundry/helpers/CollectingHelpers.sol +++ b/test/foundry/helpers/CollectingHelpers.sol @@ -6,8 +6,6 @@ import 'forge-std/Test.sol'; import 'contracts/libraries/DataTypes.sol'; contract CollectingHelpers is TestSetup { - using Strings for uint256; - CollectNFT _collectNftAfter; function _checkCollectNFTBefore() internal returns (uint256) { @@ -41,24 +39,24 @@ contract CollectingHelpers is TestSetup { assertEq(_collectNftAfter.symbol(), _expectedSymbol()); } - function _expectedName() internal view virtual returns (string memory) { + function _expectedName() internal virtual returns (string memory) { return string( abi.encodePacked( - mockCollectData.profileId.toString(), + vm.toString(mockCollectData.profileId), COLLECT_NFT_NAME_INFIX, - uint256(mockCollectData.pubId).toString() + vm.toString(mockCollectData.pubId) ) ); } - function _expectedSymbol() internal view virtual returns (string memory) { + function _expectedSymbol() internal virtual returns (string memory) { return string( abi.encodePacked( - mockCollectData.profileId.toString(), + vm.toString(mockCollectData.profileId), COLLECT_NFT_SYMBOL_INFIX, - uint256(mockCollectData.pubId).toString() + vm.toString(mockCollectData.pubId) ) ); } diff --git a/test/foundry/helpers/ForkManagement.sol b/test/foundry/helpers/ForkManagement.sol new file mode 100644 index 0000000..0338838 --- /dev/null +++ b/test/foundry/helpers/ForkManagement.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import 'forge-std/Script.sol'; + +contract ForkManagement is Script { + using stdJson for string; + + function loadJson() internal returns (string memory) { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, '/addresses.json'); + string memory json = vm.readFile(path); + return json; + } + + function checkNetworkParams(string memory json, string memory targetEnv) + internal + returns (string memory network, uint256 chainId) + { + network = json.readString(string.concat('.', targetEnv, '.network')); + chainId = json.readUint(string.concat('.', targetEnv, '.chainId')); + + console.log('\nTarget environment:', targetEnv); + console.log('Network:', network); + if (block.chainid != chainId) revert('Wrong chainId'); + console.log('ChainId:', chainId); + } + + function getNetwork(string memory json, string memory targetEnv) + internal + returns (string memory) + { + return json.readString(string.concat('.', targetEnv, '.network')); + } +} diff --git a/test/foundry/helpers/SignatureHelpers.sol b/test/foundry/helpers/SignatureHelpers.sol index 40bd417..c02dc06 100644 --- a/test/foundry/helpers/SignatureHelpers.sol +++ b/test/foundry/helpers/SignatureHelpers.sol @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + import '../../../contracts/libraries/DataTypes.sol'; contract SigSetup { @@ -159,4 +162,14 @@ contract SignatureHelpers { sig: sig }); } + + function _buildFollowWithSigData( + address delegatedSigner, + address follower, + uint256[] memory profileIds, + bytes[] memory datas, + DataTypes.EIP712Signature memory sig + ) internal pure returns (DataTypes.FollowWithSigData memory) { + return DataTypes.FollowWithSigData(delegatedSigner, follower, profileIds, datas, sig); + } }