test: Publication tests base architecture added

This commit is contained in:
donosonaumczuk
2023-04-21 18:11:47 +01:00
11 changed files with 480 additions and 687 deletions

View File

@@ -1,196 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import 'test/foundry/base/BaseTest.t.sol';
import 'test/foundry/helpers/SignatureHelpers.sol';
import 'test/foundry/helpers/CollectingHelpers.sol';
import 'test/foundry/MetaTxNegatives.t.sol';
// TODO: We still need these collecting tests to work with Deprecated collect modules in V1 posts
// TODO add check for _initialize() called for fork tests - check name and symbol set
contract CollectingTest is BaseTest, CollectingHelpers, SigSetup {
uint256 constant collectorProfileOwnerPk = 0xC011EEC7012;
address collectorProfileOwner;
uint256 collectorProfileId;
uint256 constant userWithoutProfilePk = 0x105312;
address userWithoutProfile;
function setUp() public virtual override(SigSetup, TestSetup) {
TestSetup.setUp();
SigSetup.setUp();
vm.prank(profileOwner);
hub.post(mockPostParams);
collectorProfileOwner = vm.addr(collectorProfileOwnerPk);
collectorProfileId = _createProfile(collectorProfileOwner);
userWithoutProfile = vm.addr(userWithoutProfilePk);
mockCollectParams.collectorProfileId = collectorProfileId;
}
function _collect(
uint256, /* metaTxSignerPk */
address transactionExecutor,
Types.CollectParams memory collectParams
) internal virtual returns (uint256) {
vm.prank(transactionExecutor);
return hub.collect(collectParams);
}
// NEGATIVES
// Also acts like a test for cannot collect specifying another (non-owned) profile as a parameter
function testCannotCollectIfNotDelegatedExecutor() public {
vm.expectRevert(Errors.ExecutorInvalid.selector);
_collect(collectorProfileOwnerPk, otherSigner, mockCollectParams);
}
function testCannotCollectIfNonexistantPub() public {
mockCollectParams.publicationCollectedId = 2;
// Check that the publication doesn't exist.
assertEq(
_getPub(mockCollectParams.publicationCollectedProfileId, mockCollectParams.publicationCollectedId)
.pointedProfileId,
0
);
vm.expectRevert(Errors.CollectNotAllowed.selector);
_collect(collectorProfileOwnerPk, collectorProfileOwner, mockCollectParams);
vm.stopPrank();
}
function testCannotCollectIfZeroPub() public {
mockCollectParams.publicationCollectedId = 0;
// Check that the publication doesn't exist.
assertEq(
_getPub(mockCollectParams.publicationCollectedProfileId, mockCollectParams.publicationCollectedId)
.pointedProfileId,
0
);
vm.expectRevert(Errors.CollectNotAllowed.selector);
_collect(collectorProfileOwnerPk, collectorProfileOwner, mockCollectParams);
vm.stopPrank();
}
function testCannotCollect_WithoutProfile() public {
mockCollectParams.collectorProfileId = _getNextProfileId(); // Non-existent profile
vm.expectRevert(Errors.TokenDoesNotExist.selector);
_collect(userWithoutProfilePk, userWithoutProfile, mockCollectParams);
vm.stopPrank();
}
function testCannotCollectIfBlocked() public {
vm.prank(profileOwner);
hub.setBlockStatus(newProfileId, _toUint256Array(collectorProfileId), _toBoolArray(true));
vm.expectRevert(Errors.Blocked.selector);
_collect(collectorProfileOwnerPk, collectorProfileOwner, mockCollectParams);
}
function testCannotCollectMirror() public {
_checkCollectNFTBefore();
// Mirror once
vm.prank(profileOwner);
uint256 mirrorPubId = hub.mirror(mockMirrorParams);
// Collecting the mirror
mockCollectParams.publicationCollectedId = mirrorPubId;
vm.expectRevert(Errors.CollectNotAllowed.selector);
_collect(collectorProfileOwnerPk, collectorProfileOwner, mockCollectParams);
}
// SCENARIOS
function testCollect() public {
uint256 startNftId = _checkCollectNFTBefore();
uint256 nftId = _collect(collectorProfileOwnerPk, collectorProfileOwner, mockCollectParams);
_checkCollectNFTAfter(nftId, startNftId + 1);
}
function testCollectMirror() public {
uint256 startNftId = _checkCollectNFTBefore();
vm.prank(profileOwner);
hub.mirror(mockMirrorParams);
uint256 nftId = _collect(collectorProfileOwnerPk, collectorProfileOwner, mockCollectParams);
_checkCollectNFTAfter(nftId, startNftId + 1);
}
function testDelegatedExecutorCollect() public {
uint256 startNftId = _checkCollectNFTBefore();
// delegate power to executor
_changeDelegatedExecutorsConfig(collectorProfileOwner, collectorProfileId, otherSigner, true);
// collect from executor
uint256 nftId = _collect(otherSignerKey, otherSigner, mockCollectParams);
_checkCollectNFTAfter(nftId, startNftId + 1);
}
function testDelegatedExecutorCollectMirror() public {
uint256 startNftId = _checkCollectNFTBefore();
// mirror, then delegate power to executor
vm.prank(profileOwner);
hub.mirror(mockMirrorParams);
_changeDelegatedExecutorsConfig(collectorProfileOwner, collectorProfileId, otherSigner, true);
// collect from executor
uint256 nftId = _collect(otherSignerKey, otherSigner, mockCollectParams);
_checkCollectNFTAfter(nftId, startNftId + 1);
}
}
contract CollectingTestMetaTx is CollectingTest, MetaTxNegatives {
mapping(address => uint256) cachedNonceByAddress;
function setUp() public override(CollectingTest, MetaTxNegatives) {
CollectingTest.setUp();
MetaTxNegatives.setUp();
cachedNonceByAddress[collectorProfileOwner] = _getSigNonce(collectorProfileOwner);
}
function _collect(
uint256 metaTxSignerPk,
address transactionExecutor,
Types.CollectParams memory collectParams
) internal override returns (uint256) {
address signer = vm.addr(metaTxSignerPk);
uint256 deadline = type(uint256).max;
bytes32 digest = _getCollectTypedDataHash(collectParams, cachedNonceByAddress[signer], deadline);
return hub.collectWithSig(collectParams, _getSigStruct(transactionExecutor, metaTxSignerPk, digest, deadline));
}
function _executeMetaTx(
uint256 signerPk,
uint256 nonce,
uint256 deadline
) internal override {
_collectWithSig(
mockCollectParams,
_getSigStruct(
vm.addr(_getDefaultMetaTxSignerPk()),
signerPk,
_getCollectTypedDataHash(mockCollectParams, nonce, deadline),
deadline
)
);
}
function _getDefaultMetaTxSignerPk() internal pure override returns (uint256) {
return collectorProfileOwnerPk;
}
}

View File

@@ -236,28 +236,34 @@ contract EventTest is BaseTest {
}
function testPostingEmitsExpectedEvents() public {
vm.prank(profileOwner);
uint256 expectedPostId = hub.getPubCount(mockPostParams.profileId) + 1;
vm.expectEmit(true, true, false, true, address(hub));
emit Events.PostCreated(mockPostParams, 1, _toBytesArray(abi.encode(true)), '', block.timestamp);
emit Events.PostCreated(mockPostParams, expectedPostId, _toBytesArray(abi.encode(true)), '', block.timestamp);
vm.prank(profileOwner);
hub.post(mockPostParams);
}
function testCommentingEmitsExpectedEvents() public {
vm.startPrank(profileOwner);
hub.post(mockPostParams);
uint256 expectedCommentId = hub.getPubCount(mockPostParams.profileId) + 1;
vm.expectEmit(true, true, false, true, address(hub));
emit Events.CommentCreated(mockCommentParams, 2, '', _toBytesArray(abi.encode(true)), '', block.timestamp);
emit Events.CommentCreated(
mockCommentParams,
expectedCommentId,
'',
_toBytesArray(abi.encode(true)),
'',
block.timestamp
);
vm.prank(profileOwner);
hub.comment(mockCommentParams);
vm.stopPrank();
}
function testMirroringEmitsExpectedEvents() public {
vm.startPrank(profileOwner);
hub.post(mockPostParams);
uint256 expectedMirrorId = hub.getPubCount(mockPostParams.profileId) + 1;
vm.expectEmit(true, true, false, true, address(hub));
emit Events.MirrorCreated(mockMirrorParams, 2, '', block.timestamp);
emit Events.MirrorCreated(mockMirrorParams, expectedMirrorId, '', block.timestamp);
vm.prank(profileOwner);
hub.mirror(mockMirrorParams);
vm.stopPrank();
}
// TODO: Proper tests for Act

View File

@@ -1,453 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import 'test/foundry/base/BaseTest.t.sol';
import 'test/foundry/helpers/SignatureHelpers.sol';
import {PublishingHelpers} from 'test/foundry/helpers/PublishingHelpers.sol';
abstract contract PublishingTest is BaseTest, PublishingHelpers, SigSetup {
function replicateInitData() internal virtual {
// Default implementation does nothing.
}
function _publish() internal virtual returns (uint256);
function _publishWithSig(
address delegatedSigner,
uint256 signerPrivKey,
uint256 digestDeadline,
uint256 sigDeadline
) internal virtual returns (uint256);
function _publishWithSig(address delegatedSigner, uint256 signerPrivKey) internal virtual returns (uint256) {
return _publishWithSig(delegatedSigner, signerPrivKey, deadline, deadline);
}
function _expectedPubFromInitData() internal view virtual returns (Types.Publication memory);
function setUp() public virtual override(SigSetup, TestSetup) {
TestSetup.setUp();
SigSetup.setUp();
}
// negatives
function testCannotPublishIfNotDelegatedExecutor() public {
vm.expectRevert(Errors.ExecutorInvalid.selector);
_publish();
}
// TODO: Proper test
// function testCannotPublishNotWhitelistedCollectModule() public virtual {
// mockPostParams.collectModule = address(0xC0FFEE);
// replicateInitData();
// vm.prank(profileOwner);
// vm.expectRevert(Errors.NotWhitelisted.selector);
// _publish();
// }
function testCannotPublishNotWhitelistedReferenceModule() public virtual {
mockPostParams.referenceModule = address(0xC0FFEE);
replicateInitData();
vm.prank(profileOwner);
vm.expectRevert(Errors.NotWhitelisted.selector);
_publish();
}
// TODO: Proper test
// function testCannotPublishWithSigNotWhitelistedCollectModule() public virtual {
// mockPostParams.collectModule = address(0xC0FFEE);
// replicateInitData();
// vm.expectRevert(Errors.NotWhitelisted.selector);
// _publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
// }
function testCannotPublishWithSigNotWhitelistedReferenceModule() public virtual {
mockPostParams.referenceModule = address(0xC0FFEE);
replicateInitData();
vm.expectRevert(Errors.NotWhitelisted.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
}
function testCannotPublishWithSigInvalidSigner() public {
vm.expectRevert(Errors.SignatureInvalid.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: otherSignerKey});
}
function testCannotPublishWithSigInvalidNonce() public {
nonce = _getSigNonce(otherSigner) + 1;
vm.expectRevert(Errors.SignatureInvalid.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: otherSignerKey});
}
function testCannotPublishWithSigInvalidDeadline() public {
vm.expectRevert(Errors.SignatureInvalid.selector);
_publishWithSig({
delegatedSigner: profileOwner,
signerPrivKey: profileOwnerKey,
digestDeadline: type(uint256).max,
sigDeadline: block.timestamp + 10
});
}
function testCannotPublishIfNonceWasIncrementedWithAnotherAction() public {
assertEq(_getSigNonce(profileOwner), nonce, 'Wrong nonce before posting');
uint256 expectedPubId = _getPubCount(newProfileId) + 1;
uint256 pubId = _publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
assertEq(pubId, expectedPubId, 'Wrong pubId');
assertTrue(_getSigNonce(profileOwner) != nonce, 'Wrong nonce after posting');
vm.expectRevert(Errors.SignatureInvalid.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
}
function testCannotPublishWithSigExpiredDeadline() public {
deadline = 10;
vm.warp(20);
vm.expectRevert(Errors.SignatureExpired.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: otherSignerKey});
}
function testCannotPublishWithSigNotDelegatedExecutor() public {
vm.expectRevert(Errors.ExecutorInvalid.selector);
_publishWithSig({delegatedSigner: otherSigner, signerPrivKey: otherSignerKey});
}
// positives
function testPublish() public {
uint256 expectedPubId = _getPubCount(newProfileId) + 1;
vm.prank(profileOwner);
uint256 pubId = _publish();
assertEq(pubId, expectedPubId);
Types.Publication memory pub = _getPub(newProfileId, pubId);
_verifyPublication(pub, _expectedPubFromInitData());
}
// TODO: Can publish without a collect module
// TODO: Can publish without a reference module
function testPublishWithAWhitelistedReferenceModule() public {
mockPostParams.referenceModule = address(mockReferenceModule);
mockPostParams.referenceModuleInitData = abi.encode(1);
replicateInitData();
uint256 expectedPubId = _getPubCount(newProfileId) + 1;
vm.prank(profileOwner);
uint256 pubId = _publish();
assertEq(pubId, expectedPubId);
Types.Publication memory pub = _getPub(newProfileId, pubId);
_verifyPublication(pub, _expectedPubFromInitData());
}
function testPublishWithSig() public {
uint256 expectedPubId = _getPubCount(newProfileId) + 1;
uint256 pubId = _publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
assertEq(pubId, expectedPubId);
Types.Publication memory pub = _getPub(newProfileId, pubId);
_verifyPublication(pub, _expectedPubFromInitData());
}
function testDelegatedExecutorPublish() public {
_changeDelegatedExecutorsConfig(profileOwner, newProfileId, otherSigner, true);
uint256 expectedPubId = _getPubCount(newProfileId) + 1;
vm.prank(otherSigner);
uint256 pubId = _publish();
assertEq(pubId, expectedPubId);
Types.Publication memory pub = _getPub(newProfileId, pubId);
_verifyPublication(pub, _expectedPubFromInitData());
}
function testDelegatedExecutorPublishWithSig() public {
_changeDelegatedExecutorsConfig(profileOwner, newProfileId, otherSigner, true);
uint256 expectedPubId = _getPubCount(newProfileId) + 1;
uint256 pubId = _publishWithSig({delegatedSigner: otherSigner, signerPrivKey: otherSignerKey});
assertEq(pubId, expectedPubId);
Types.Publication memory pub = _getPub(newProfileId, pubId);
_verifyPublication(pub, _expectedPubFromInitData());
}
}
contract PostTest is PublishingTest {
function testPostTest() public {
// Prevents being counted in Foundry Coverage
}
function _publish() internal virtual override returns (uint256) {
return _post(mockPostParams);
}
function _publishWithSig(
address delegatedSigner,
uint256 signerPrivKey,
uint256 digestDeadline,
uint256 sigDeadline
) internal virtual override returns (uint256) {
bytes32 digest = _getPostTypedDataHash(mockPostParams, nonce, digestDeadline);
return _postWithSig(mockPostParams, _getSigStruct(delegatedSigner, signerPrivKey, digest, sigDeadline));
}
function _expectedPubFromInitData() internal view virtual override returns (Types.Publication memory) {
return _expectedPubFromInitData(mockPostParams);
}
}
contract CommentTest is PublishingTest {
uint256 postId;
function replicateInitData() internal override {
mockCommentParams.profileId = mockPostParams.profileId;
mockCommentParams.contentURI = mockPostParams.contentURI;
mockCommentParams.actionModules = mockPostParams.actionModules;
mockCommentParams.actionModulesInitDatas = mockPostParams.actionModulesInitDatas;
mockCommentParams.referenceModule = mockPostParams.referenceModule;
mockCommentParams.referenceModuleInitData = mockPostParams.referenceModuleInitData;
}
function _publish() internal override returns (uint256) {
return _comment(mockCommentParams);
}
function _publishWithSig(
address delegatedSigner,
uint256 signerPrivKey,
uint256 digestDeadline,
uint256 sigDeadline
) internal override returns (uint256) {
bytes32 digest = _getCommentTypedDataHash(mockCommentParams, nonce, digestDeadline);
return _commentWithSig(mockCommentParams, _getSigStruct(delegatedSigner, signerPrivKey, digest, sigDeadline));
}
function _expectedPubFromInitData() internal view override returns (Types.Publication memory) {
return _expectedPubFromInitData(mockCommentParams);
}
function setUp() public override {
PublishingTest.setUp();
vm.prank(profileOwner);
postId = _post(mockPostParams);
}
// negatives
function testCannotCommentOnNonExistentPublication() public {
uint256 nonExistentPubId = _getPubCount(newProfileId) + 10;
replicateInitData();
mockCommentParams.pointedPubId = nonExistentPubId;
vm.prank(profileOwner);
vm.expectRevert(Errors.InvalidPointedPub.selector);
_publish();
}
function testCannotCommentWithSigOnNonExistentPublication() public {
uint256 nonExistentPubId = _getPubCount(newProfileId) + 10;
replicateInitData();
mockCommentParams.pointedPubId = nonExistentPubId;
vm.expectRevert(Errors.InvalidPointedPub.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
}
function testCannotCommentOnTheSamePublicationBeingCreated() public {
uint256 nextPubId = _getPubCount(newProfileId) + 1;
replicateInitData();
mockCommentParams.pointedPubId = nextPubId;
vm.prank(profileOwner);
vm.expectRevert(Errors.InvalidPointedPub.selector);
_publish();
}
function testCannotCommentWithSigOnTheSamePublicationBeingCreated() public {
uint256 nextPubId = _getPubCount(newProfileId) + 1;
replicateInitData();
mockCommentParams.pointedPubId = nextPubId;
vm.expectRevert(Errors.InvalidPointedPub.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
}
function testCannotCommentIfBlocked() public {
uint256 commenterProfileId = _createProfile(profileOwner);
mockCommentParams.profileId = commenterProfileId;
vm.prank(profileOwner);
hub.setBlockStatus(mockPostParams.profileId, _toUint256Array(commenterProfileId), _toBoolArray(true));
vm.expectRevert(Errors.Blocked.selector);
vm.prank(profileOwner);
_publish();
}
function testCannotCommentWithSigIfBlocked() public {
uint256 commenterProfileId = _createProfile(profileOwner);
mockCommentParams.profileId = commenterProfileId;
vm.prank(profileOwner);
hub.setBlockStatus(mockPostParams.profileId, _toUint256Array(commenterProfileId), _toBoolArray(true));
vm.expectRevert(Errors.Blocked.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
}
// scenarios
function testPostWithReferenceModuleAndComment() public {
mockPostParams.referenceModule = address(mockReferenceModule);
mockPostParams.referenceModuleInitData = abi.encode(1);
vm.prank(profileOwner);
postId = _post(mockPostParams);
mockCommentParams.pointedPubId = postId;
vm.prank(profileOwner);
uint256 commentPubId = _publish();
Types.Publication memory pub = _getPub(newProfileId, commentPubId);
_verifyPublication(pub, _expectedPubFromInitData());
}
function testCannotCommentOnMirror() public {
mockMirrorParams.pointedPubId = postId;
vm.prank(profileOwner);
uint256 mirrorId = _mirror(mockMirrorParams);
mockCommentParams.pointedPubId = mirrorId;
vm.expectRevert(Errors.InvalidPointedPub.selector);
vm.prank(profileOwner);
_publish();
}
function testCannotCommentOnMirrorWithSig() public {
mockMirrorParams.pointedPubId = postId;
vm.prank(profileOwner);
uint256 mirrorId = _mirror(mockMirrorParams);
mockCommentParams.pointedPubId = mirrorId;
vm.expectRevert(Errors.InvalidPointedPub.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
}
}
contract MirrorTest is PublishingTest {
uint256 postId;
function replicateInitData() internal override {
mockMirrorParams.profileId = mockPostParams.profileId;
}
function _publish() internal override returns (uint256) {
return _mirror(mockMirrorParams);
}
function _publishWithSig(
address delegatedSigner,
uint256 signerPrivKey,
uint256 digestDeadline,
uint256 sigDeadline
) internal override returns (uint256) {
bytes32 digest = _getMirrorTypedDataHash(mockMirrorParams, nonce, digestDeadline);
return _mirrorWithSig(mockMirrorParams, _getSigStruct(delegatedSigner, signerPrivKey, digest, sigDeadline));
}
function _expectedPubFromInitData() internal view override returns (Types.Publication memory) {
return _expectedPubFromInitData(mockMirrorParams);
}
function setUp() public override {
PublishingTest.setUp();
vm.prank(profileOwner);
postId = _post(mockPostParams);
}
// ignored - these tests don't apply to mirrors
// TODO: Proper tests
// function testCannotPublishNotWhitelistedCollectModule() public override {}
// function testCannotPublishWithSigNotWhitelistedCollectModule() public override {}
function testCannotPublishNotWhitelistedReferenceModule() public override {}
function testCannotPublishWithSigNotWhitelistedReferenceModule() public override {}
// negatives
function testCannotMirrorNonExistentPublication() public {
uint256 nonExistentPubId = _getPubCount(newProfileId) + 10;
replicateInitData();
mockMirrorParams.pointedPubId = nonExistentPubId;
vm.prank(profileOwner);
vm.expectRevert(Errors.InvalidPointedPub.selector);
_publish();
}
function testCannotMirrorWithSigNonExistentPublication() public {
uint256 nonExistentPubId = _getPubCount(newProfileId) + 10;
replicateInitData();
mockMirrorParams.pointedPubId = nonExistentPubId;
vm.expectRevert(Errors.InvalidPointedPub.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
}
function testCannotMirrorIfBlocked() public {
uint256 mirrorerProfileId = _createProfile(profileOwner);
mockMirrorParams.profileId = mirrorerProfileId;
vm.prank(profileOwner);
hub.setBlockStatus(mockPostParams.profileId, _toUint256Array(mirrorerProfileId), _toBoolArray(true));
vm.expectRevert(Errors.Blocked.selector);
vm.prank(profileOwner);
_publish();
}
function testCannotMirrorWithSigIfBlocked() public {
uint256 mirrorerProfileId = _createProfile(profileOwner);
mockMirrorParams.profileId = mirrorerProfileId;
vm.prank(profileOwner);
hub.setBlockStatus(mockPostParams.profileId, _toUint256Array(mirrorerProfileId), _toBoolArray(true));
vm.expectRevert(Errors.Blocked.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
}
// scenarios
function testCannotMirrorAMirror() public {
mockMirrorParams.pointedPubId = postId;
vm.prank(profileOwner);
uint256 firstMirrorId = _publish();
mockMirrorParams.pointedPubId = firstMirrorId;
vm.prank(profileOwner);
vm.expectRevert(Errors.InvalidPointedPub.selector);
_publish();
}
function testCannotMirrorAMirrorWithSig() public {
mockMirrorParams.pointedPubId = postId;
vm.prank(profileOwner);
uint256 firstMirrorId = _publish();
mockMirrorParams.pointedPubId = firstMirrorId;
vm.expectRevert(Errors.InvalidPointedPub.selector);
_publishWithSig({delegatedSigner: profileOwner, signerPrivKey: profileOwnerKey});
}
}

View File

@@ -220,6 +220,34 @@ contract BaseTest is TestSetup {
return _calculateDigest(structHash);
}
function _getQuoteTypedDataHash(
Types.QuoteParams memory quoteParams,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
bytes32 structHash = keccak256(
_abiEncode(
ReferenceParamsForAbiEncode(
Typehash.QUOTE,
quoteParams.profileId,
keccak256(bytes(quoteParams.contentURI)),
quoteParams.pointedProfileId,
quoteParams.pointedPubId,
quoteParams.referrerProfileIds,
quoteParams.referrerPubIds,
keccak256(quoteParams.referenceModuleData),
quoteParams.actionModules,
_hashActionModulesInitDatas(quoteParams.actionModulesInitDatas),
quoteParams.referenceModule,
keccak256(quoteParams.referenceModuleInitData),
nonce,
deadline
)
)
);
return _calculateDigest(structHash);
}
function _getMirrorTypedDataHash(
uint256 profileId,
uint256 pointedProfileId,

View File

@@ -32,6 +32,7 @@ contract TestSetup is Test, ForkManagement, ArrayHelpers {
}
uint256 newProfileId; // TODO: We should get rid of this everywhere, and create dedicated profiles instead (see Follow tests)
uint256 mockPostId;
address deployer;
address governance;
@@ -66,6 +67,7 @@ contract TestSetup is Test, ForkManagement, ArrayHelpers {
Types.PostParams mockPostParams;
Types.CommentParams mockCommentParams;
Types.QuoteParams mockQuoteParams;
Types.MirrorParams mockMirrorParams;
Types.CollectParams mockCollectParams;
Types.PublicationActionParams mockActParams;
@@ -111,9 +113,6 @@ contract TestSetup is Test, ForkManagement, ArrayHelpers {
hubAsProxy = TransparentUpgradeableProxy(payable(address(hub)));
moduleGlobals = ModuleGlobals(json.readAddress(string(abi.encodePacked('.', targetEnv, '.ModuleGlobals'))));
newProfileId = _getNextProfileId();
console.log('newProfileId:', newProfileId);
deployer = address(1);
governance = hub.getGovernance();
@@ -123,7 +122,6 @@ contract TestSetup is Test, ForkManagement, ArrayHelpers {
}
function deployBaseContracts() internal {
newProfileId = FIRST_PROFILE_ID;
deployer = address(1);
governance = address(2);
treasury = address(3);
@@ -208,6 +206,8 @@ contract TestSetup is Test, ForkManagement, ArrayHelpers {
followNFTURI: MOCK_URI
});
newProfileId = hub.createProfile(mockCreateProfileParams);
// Precompute basic post data.
mockPostParams = Types.PostParams({
profileId: newProfileId,
@@ -218,12 +218,30 @@ contract TestSetup is Test, ForkManagement, ArrayHelpers {
referenceModuleInitData: ''
});
vm.prank(profileOwner);
mockPostId = hub.post(mockPostParams);
// Precompute basic comment data.
mockCommentParams = Types.CommentParams({
profileId: newProfileId,
contentURI: MOCK_URI,
pointedProfileId: newProfileId,
pointedPubId: FIRST_PUB_ID,
pointedPubId: mockPostId,
referrerProfileIds: _emptyUint256Array(),
referrerPubIds: _emptyUint256Array(),
referenceModuleData: '',
actionModules: _toAddressArray(address(mockActionModule)),
actionModulesInitDatas: _toBytesArray(abi.encode(1)),
referenceModule: address(0),
referenceModuleInitData: ''
});
// Precompute basic quote data.
mockQuoteParams = Types.QuoteParams({
profileId: newProfileId,
contentURI: MOCK_URI,
pointedProfileId: newProfileId,
pointedPubId: mockPostId,
referrerProfileIds: _emptyUint256Array(),
referrerPubIds: _emptyUint256Array(),
referenceModuleData: '',
@@ -237,7 +255,7 @@ contract TestSetup is Test, ForkManagement, ArrayHelpers {
mockMirrorParams = Types.MirrorParams({
profileId: newProfileId,
pointedProfileId: newProfileId,
pointedPubId: FIRST_PUB_ID,
pointedPubId: mockPostId,
referrerProfileIds: _emptyUint256Array(),
referrerPubIds: _emptyUint256Array(),
referenceModuleData: ''
@@ -252,18 +270,6 @@ contract TestSetup is Test, ForkManagement, ArrayHelpers {
actionModuleAddress: address(mockActionModule),
actionModuleData: abi.encode(true)
});
// // Precompute basic collect data.
// mockCollectParams = Types.CollectParams({
// publicationCollectedProfileId: newProfileId,
// publicationCollectedId: FIRST_PUB_ID,
// collectorProfileId: newProfileId,
// referrerProfileIds: _emptyUint256Array(),
// referrerPubIds: _emptyUint256Array(),
// collectModuleData: ''
// });
hub.createProfile(mockCreateProfileParams);
}
// TODO: Find a better place for such helpers that have access to Hub without rekting inheritance

View File

@@ -13,16 +13,6 @@ contract ArrayHelpers {
return ret;
}
function _emptyAddressArray() internal pure returns (address[] memory) {
address[] memory ret = new address[](0);
return ret;
}
function _emptyBytesArray() internal pure returns (bytes[] memory) {
bytes[] memory ret = new bytes[](0);
return ret;
}
function _emptyPubTypesArray() internal pure returns (Types.PublicationType[] memory) {
Types.PublicationType[] memory ret = new Types.PublicationType[](0);
return ret;

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {Types} from 'contracts/libraries/constants/Types.sol';
import {PublicationTest} from 'test/foundry/publications/PublicationTest.t.sol';
import {MetaTxNegatives} from 'test/foundry/MetaTxNegatives.t.sol';
contract CommentTest is PublicationTest {
function testCommentTest() public {
// Prevents being counted in Foundry Coverage
}
function setUp() public virtual override {
super.setUp();
mockCommentParams.profileId = publisherProfileId;
}
function _publish(uint256 signerPk, uint256 publisherProfileId) internal virtual override returns (uint256) {
mockCommentParams.profileId = publisherProfileId;
vm.prank(vm.addr(signerPk));
return hub.comment(mockCommentParams);
}
function _pubType() internal virtual override returns (Types.PublicationType) {
return Types.PublicationType.Comment;
}
}
contract CommentMetaTxTest is CommentTest, MetaTxNegatives {
mapping(address => uint256) cachedNonceByAddress;
function testCommentMetaTxTest() public {
// Prevents being counted in Foundry Coverage
}
function setUp() public virtual override(CommentTest, MetaTxNegatives) {
CommentTest.setUp();
MetaTxNegatives.setUp();
cachedNonceByAddress[profileOwner] = _getSigNonce(profileOwner);
}
function _publish(uint256 signerPk, uint256 publisherProfileId) internal virtual override returns (uint256) {
mockCommentParams.profileId = publisherProfileId;
address signer = vm.addr(signerPk);
return
hub.commentWithSig(
mockCommentParams,
_getSigStruct({
signer: signer,
pKey: signerPk,
digest: _getCommentTypedDataHash({
commentParams: mockCommentParams,
nonce: cachedNonceByAddress[signer],
deadline: type(uint256).max
}),
deadline: type(uint256).max
})
);
}
function _executeMetaTx(uint256 signerPk, uint256 nonce, uint256 deadline) internal virtual override {
hub.commentWithSig(
mockCommentParams,
_getSigStruct({
signer: vm.addr(_getDefaultMetaTxSignerPk()),
pKey: signerPk,
digest: _getCommentTypedDataHash(mockCommentParams, nonce, deadline),
deadline: deadline
})
);
}
function _getDefaultMetaTxSignerPk() internal virtual override returns (uint256) {
return publisherOwnerPk;
}
}

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {Types} from 'contracts/libraries/constants/Types.sol';
import {PublicationTest} from 'test/foundry/publications/PublicationTest.t.sol';
import {MetaTxNegatives} from 'test/foundry/MetaTxNegatives.t.sol';
contract MirrorTest is PublicationTest {
function testMirrorTest() public {
// Prevents being counted in Foundry Coverage
}
function setUp() public virtual override {
super.setUp();
mockMirrorParams.profileId = publisherProfileId;
}
function _publish(uint256 signerPk, uint256 publisherProfileId) internal virtual override returns (uint256) {
mockMirrorParams.profileId = publisherProfileId;
vm.prank(vm.addr(signerPk));
return hub.mirror(mockMirrorParams);
}
function _pubType() internal virtual override returns (Types.PublicationType) {
return Types.PublicationType.Mirror;
}
}
contract MirrorMetaTxTest is MirrorTest, MetaTxNegatives {
mapping(address => uint256) cachedNonceByAddress;
function testMirrorMetaTxTest() public {
// Prevents being counted in Foundry Coverage
}
function setUp() public virtual override(MirrorTest, MetaTxNegatives) {
MirrorTest.setUp();
MetaTxNegatives.setUp();
cachedNonceByAddress[profileOwner] = _getSigNonce(profileOwner);
}
function _publish(uint256 signerPk, uint256 publisherProfileId) internal virtual override returns (uint256) {
mockMirrorParams.profileId = publisherProfileId;
address signer = vm.addr(signerPk);
return
hub.mirrorWithSig(
mockMirrorParams,
_getSigStruct({
signer: signer,
pKey: signerPk,
digest: _getMirrorTypedDataHash({
mirrorParams: mockMirrorParams,
nonce: cachedNonceByAddress[signer],
deadline: type(uint256).max
}),
deadline: type(uint256).max
})
);
}
function _executeMetaTx(uint256 signerPk, uint256 nonce, uint256 deadline) internal virtual override {
hub.mirrorWithSig(
mockMirrorParams,
_getSigStruct({
signer: vm.addr(_getDefaultMetaTxSignerPk()),
pKey: signerPk,
digest: _getMirrorTypedDataHash(mockMirrorParams, nonce, deadline),
deadline: deadline
})
);
}
function _getDefaultMetaTxSignerPk() internal virtual override returns (uint256) {
return publisherOwnerPk;
}
}

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {Types} from 'contracts/libraries/constants/Types.sol';
import {PublicationTest} from 'test/foundry/publications/PublicationTest.t.sol';
import {MetaTxNegatives} from 'test/foundry/MetaTxNegatives.t.sol';
contract PostTest is PublicationTest {
function testPostTest() public {
// Prevents being counted in Foundry Coverage
}
function setUp() public virtual override {
super.setUp();
mockPostParams.profileId = publisherProfileId;
}
function _publish(uint256 signerPk, uint256 publisherProfileId) internal virtual override returns (uint256) {
mockPostParams.profileId = publisherProfileId;
vm.prank(vm.addr(signerPk));
return hub.post(mockPostParams);
}
function _pubType() internal virtual override returns (Types.PublicationType) {
return Types.PublicationType.Post;
}
}
contract PostMetaTxTest is PostTest, MetaTxNegatives {
mapping(address => uint256) cachedNonceByAddress;
function testPostMetaTxTest() public {
// Prevents being counted in Foundry Coverage
}
function setUp() public virtual override(PostTest, MetaTxNegatives) {
PostTest.setUp();
MetaTxNegatives.setUp();
cachedNonceByAddress[profileOwner] = _getSigNonce(profileOwner);
}
function _publish(uint256 signerPk, uint256 publisherProfileId) internal virtual override returns (uint256) {
mockPostParams.profileId = publisherProfileId;
address signer = vm.addr(signerPk);
return
hub.postWithSig(
mockPostParams,
_getSigStruct({
signer: signer,
pKey: signerPk,
digest: _getPostTypedDataHash({
postParams: mockPostParams,
nonce: cachedNonceByAddress[signer],
deadline: type(uint256).max
}),
deadline: type(uint256).max
})
);
}
function _executeMetaTx(uint256 signerPk, uint256 nonce, uint256 deadline) internal virtual override {
hub.postWithSig(
mockPostParams,
_getSigStruct({
signer: vm.addr(_getDefaultMetaTxSignerPk()),
pKey: signerPk,
digest: _getPostTypedDataHash(mockPostParams, nonce, deadline),
deadline: deadline
})
);
}
function _getDefaultMetaTxSignerPk() internal virtual override returns (uint256) {
return publisherOwnerPk;
}
}

View File

@@ -0,0 +1,108 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import 'test/foundry/base/BaseTest.t.sol';
/**
* Tests shared among all type of publications. Posts, Comments, Quotes, and Mirrors.
*/
abstract contract PublicationTest is BaseTest {
uint256 publisherOwnerPk;
address publisherOwner;
uint256 publisherProfileId;
function _publish(uint256 signerPk, uint256 publisherProfileId) internal virtual returns (uint256);
function _pubType() internal virtual returns (Types.PublicationType);
function setUp() public virtual override {
super.setUp();
(publisherOwnerPk, publisherOwner, publisherProfileId) = _loadAccountAs('Publisher');
}
// Negatives
function testCannotPublish_IfProtocolStateIs_Paused() public {
vm.prank(governance);
hub.setState(Types.ProtocolState.Paused);
vm.expectRevert(Errors.PublishingPaused.selector);
_publish({signerPk: publisherOwnerPk, publisherProfileId: publisherProfileId});
}
function testCannotPublish_IfProtocolStateIs_PublishingPaused() public {
vm.prank(governance);
hub.setState(Types.ProtocolState.PublishingPaused);
vm.expectRevert(Errors.PublishingPaused.selector);
_publish({signerPk: publisherOwnerPk, publisherProfileId: publisherProfileId});
}
function testCannotPublish_IfExecutorIsNot_PublisherProfileOwnerOrDelegatedExecutor(
uint256 nonOwnerNorDelegatedExecutorPk
) public {
nonOwnerNorDelegatedExecutorPk = _boundPk(nonOwnerNorDelegatedExecutorPk);
vm.assume(nonOwnerNorDelegatedExecutorPk != publisherOwnerPk);
address nonOwnerNorDelegatedExecutor = vm.addr(nonOwnerNorDelegatedExecutorPk);
vm.assume(!hub.isDelegatedExecutorApproved(publisherProfileId, nonOwnerNorDelegatedExecutor));
vm.expectRevert(Errors.ExecutorInvalid.selector);
_publish({signerPk: nonOwnerNorDelegatedExecutorPk, publisherProfileId: publisherProfileId});
}
// Scenarios
function testPublisherPubCountIs_IncrementedByOne_AfterPublishing() public {
uint256 pubCountBeforePublishing = hub.getPubCount(publisherProfileId);
_publish({signerPk: publisherOwnerPk, publisherProfileId: publisherProfileId});
uint256 pubCountAfterPublishing = hub.getPubCount(publisherProfileId);
assertEq(pubCountAfterPublishing, pubCountBeforePublishing + 1);
}
function testPubIdAssignedIs_EqualsToPubCount_AfterPublishing() public {
uint256 pubIdAssigned = _publish({signerPk: publisherOwnerPk, publisherProfileId: publisherProfileId});
uint256 pubCountAfterPublishing = hub.getPubCount(publisherProfileId);
assertEq(pubIdAssigned, pubCountAfterPublishing);
}
function testCanPublishIf_ExecutorIs_PublisherProfileApprovedDelegatedExecutor(uint256 delegatedExecutorPk) public {
delegatedExecutorPk = _boundPk(delegatedExecutorPk);
vm.assume(delegatedExecutorPk != publisherOwnerPk);
address delegatedExecutor = vm.addr(delegatedExecutorPk);
vm.prank(publisherOwner);
hub.changeDelegatedExecutorsConfig({
delegatorProfileId: publisherProfileId,
delegatedExecutors: _toAddressArray(delegatedExecutor),
approvals: _toBoolArray(true)
});
_publish({signerPk: delegatedExecutorPk, publisherProfileId: publisherProfileId});
}
function testCanPublishIf_ExecutorIs_PublisherProfileOwner() public {
_publish({signerPk: publisherOwnerPk, publisherProfileId: publisherProfileId});
}
function testPublicationTypeIsCorrect() public {
uint256 publicationIdAssigned = _publish({signerPk: publisherOwnerPk, publisherProfileId: publisherProfileId});
Types.PublicationType assignedPubType = hub.getPublicationType(publisherProfileId, publicationIdAssigned);
Types.PublicationType expectedPubType = _pubType();
assertTrue(assignedPubType == expectedPubType, 'Assigned publication type is different than the expected one');
}
}
/**
* Tests for publications that can handle actions. Posts, Comments, and Quotes, but not Mirrors.
*/
abstract contract ActionablePublicationTest is PublicationTest {
function _setActionModules(address[] memory actionModules, bytes[] memory actionModulesInitDatas) internal virtual;
}
/**
* Tests for publications that points to another publication. Comments, Quotes, and Mirrors, but not Posts.
*/
abstract contract ReferencePublicationTest is PublicationTest {
function _setReferrers(uint256[] memory referrerProfileIds, uint256[] memory referrerPubIds) internal virtual;
function _setReferenceModuleData(bytes memory referenceModuleData) internal virtual;
}

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {Types} from 'contracts/libraries/constants/Types.sol';
import {PublicationTest} from 'test/foundry/publications/PublicationTest.t.sol';
import {MetaTxNegatives} from 'test/foundry/MetaTxNegatives.t.sol';
contract QuoteTest is PublicationTest {
function testQuoteTest() public {
// Prevents being counted in Foundry Coverage
}
function setUp() public virtual override {
super.setUp();
mockQuoteParams.profileId = publisherProfileId;
}
function _publish(uint256 signerPk, uint256 publisherProfileId) internal virtual override returns (uint256) {
mockQuoteParams.profileId = publisherProfileId;
vm.prank(vm.addr(signerPk));
return hub.quote(mockQuoteParams);
}
function _pubType() internal virtual override returns (Types.PublicationType) {
return Types.PublicationType.Quote;
}
}
contract QuoteMetaTxTest is QuoteTest, MetaTxNegatives {
mapping(address => uint256) cachedNonceByAddress;
function testQuoteMetaTxTest() public {
// Prevents being counted in Foundry Coverage
}
function setUp() public virtual override(QuoteTest, MetaTxNegatives) {
QuoteTest.setUp();
MetaTxNegatives.setUp();
cachedNonceByAddress[profileOwner] = _getSigNonce(profileOwner);
}
function _publish(uint256 signerPk, uint256 publisherProfileId) internal virtual override returns (uint256) {
mockQuoteParams.profileId = publisherProfileId;
address signer = vm.addr(signerPk);
return
hub.quoteWithSig(
mockQuoteParams,
_getSigStruct({
signer: signer,
pKey: signerPk,
digest: _getQuoteTypedDataHash({
quoteParams: mockQuoteParams,
nonce: cachedNonceByAddress[signer],
deadline: type(uint256).max
}),
deadline: type(uint256).max
})
);
}
function _executeMetaTx(uint256 signerPk, uint256 nonce, uint256 deadline) internal virtual override {
hub.quoteWithSig(
mockQuoteParams,
_getSigStruct({
signer: vm.addr(_getDefaultMetaTxSignerPk()),
pKey: signerPk,
digest: _getQuoteTypedDataHash(mockQuoteParams, nonce, deadline),
deadline: deadline
})
);
}
function _getDefaultMetaTxSignerPk() internal virtual override returns (uint256) {
return publisherOwnerPk;
}
}