Files
core/test/base/BaseTest.t.sol

480 lines
18 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import 'test/base/TestSetup.t.sol';
import 'contracts/libraries/constants/Types.sol';
import {Typehash} from 'contracts/libraries/constants/Typehash.sol';
import {Typehash as NamespacesTypehash} from 'contracts/namespaces/constants/Typehash.sol';
import {Strings} from '@openzeppelin/contracts/utils/Strings.sol';
import {Address} from '@openzeppelin/contracts/utils/Address.sol';
contract BaseTest is TestSetup {
using Strings for string;
using Address for address;
function testBaseTest() public {
// Prevents being counted in Foundry Coverage
}
// Empty setUp for easier overriding in other tests, otherwise you need to override from TestSetup and is confusing.
function setUp() public virtual override {
super.setUp();
}
function _effectivelyDisableProfileGuardian(address wallet) internal {
_effectivelyDisableGuardian(address(hub), wallet);
}
function _effectivelyDisableGuardian(address nft, address wallet) internal {
if (_isProfileGuardianEnabled(wallet)) {
vm.prank(wallet);
// TODO: Fix this if we move disableTokenGuardian to its own interface
LensHub(nft).DANGER__disableTokenGuardian();
vm.warp(LensHub(nft).getTokenGuardianDisablingTimestamp(wallet));
}
}
function _isProfileGuardianEnabled(address wallet) internal view returns (bool) {
return
!wallet.isContract() &&
(hub.getTokenGuardianDisablingTimestamp(wallet) == 0 ||
block.timestamp < hub.getTokenGuardianDisablingTimestamp(wallet));
}
function _boundPk(uint256 fuzzedUint256) internal view returns (uint256 fuzzedPk) {
return bound(fuzzedUint256, 1, ISSECP256K1_CURVE_ORDER - 1);
}
function _isLensHubProxyAdmin(address proxyAdminCandidate) internal view returns (bool) {
address proxyAdmin = address(uint160(uint256(vm.load(address(hub), ADMIN_SLOT))));
return proxyAdminCandidate == proxyAdmin;
}
function _getSetProfileMetadataURITypedDataHash(
uint256 profileId,
string memory metadataURI,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
bytes32 structHash = keccak256(
abi.encode(
Typehash.SET_PROFILE_METADATA_URI,
profileId,
_encodeUsingEip712Rules(metadataURI),
nonce,
deadline
)
);
return _calculateDigest(structHash);
}
function _getSetFollowModuleTypedDataHash(
uint256 profileId,
address followModule,
bytes memory followModuleInitData,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
bytes32 structHash = keccak256(
abi.encode(
Typehash.SET_FOLLOW_MODULE,
profileId,
followModule,
_encodeUsingEip712Rules(followModuleInitData),
nonce,
deadline
)
);
return _calculateDigest(structHash);
}
function _getChangeDelegatedExecutorsConfigTypedDataHash(
uint256 delegatorProfileId,
uint64 configNumber,
address[] memory delegatedExecutors,
bool[] memory approvals,
bool switchToGivenConfig,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
bytes32 structHash = keccak256(
abi.encode(
Typehash.CHANGE_DELEGATED_EXECUTORS_CONFIG,
delegatorProfileId,
_encodeUsingEip712Rules(delegatedExecutors),
_encodeUsingEip712Rules(approvals),
configNumber,
switchToGivenConfig,
nonce,
deadline
)
);
return _calculateDigest(structHash);
}
function _getPostTypedDataHash(
uint256 profileId,
string memory contentURI,
address[] memory actionModules,
bytes[] memory actionModulesInitDatas,
address referenceModule,
bytes memory referenceModuleInitData,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
bytes32 structHash = keccak256(
abi.encode(
Typehash.POST,
profileId,
_encodeUsingEip712Rules(contentURI),
_encodeUsingEip712Rules(actionModules),
_encodeUsingEip712Rules(actionModulesInitDatas),
referenceModule,
_encodeUsingEip712Rules(referenceModuleInitData),
nonce,
deadline
)
);
return _calculateDigest(structHash);
}
function _getPostTypedDataHash(
Types.PostParams memory postParams,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
return
_getPostTypedDataHash({
profileId: postParams.profileId,
contentURI: postParams.contentURI,
actionModules: postParams.actionModules,
actionModulesInitDatas: postParams.actionModulesInitDatas,
referenceModule: postParams.referenceModule,
referenceModuleInitData: postParams.referenceModuleInitData,
nonce: nonce,
deadline: deadline
});
}
// We need this to deal with stack too deep:
struct ReferenceParamsForAbiEncode {
bytes32 typehash;
uint256 profileId;
bytes32 contentURIHash;
uint256 pointedProfileId;
uint256 pointedPubId;
bytes32 referrerProfileIds;
bytes32 referrerPubIds;
bytes32 referenceModuleDataHash;
bytes32 actionModules;
bytes32 actionModulesInitDataHash;
address referenceModule;
bytes32 referenceModuleInitDataHash;
uint256 nonce;
uint256 deadline;
}
function _abiEncode(
ReferenceParamsForAbiEncode memory referenceParamsForAbiEncode
) private pure returns (bytes memory) {
return abi.encode(referenceParamsForAbiEncode);
}
function _getCommentTypedDataHash(
Types.CommentParams memory commentParams,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
bytes32 structHash = keccak256(
_abiEncode(
ReferenceParamsForAbiEncode(
Typehash.COMMENT,
commentParams.profileId,
_encodeUsingEip712Rules(commentParams.contentURI),
commentParams.pointedProfileId,
commentParams.pointedPubId,
_encodeUsingEip712Rules(commentParams.referrerProfileIds),
_encodeUsingEip712Rules(commentParams.referrerPubIds),
_encodeUsingEip712Rules(commentParams.referenceModuleData),
_encodeUsingEip712Rules(commentParams.actionModules),
_encodeUsingEip712Rules(commentParams.actionModulesInitDatas),
commentParams.referenceModule,
_encodeUsingEip712Rules(commentParams.referenceModuleInitData),
nonce,
deadline
)
)
);
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,
_encodeUsingEip712Rules(quoteParams.contentURI),
quoteParams.pointedProfileId,
quoteParams.pointedPubId,
_encodeUsingEip712Rules(quoteParams.referrerProfileIds),
_encodeUsingEip712Rules(quoteParams.referrerPubIds),
_encodeUsingEip712Rules(quoteParams.referenceModuleData),
_encodeUsingEip712Rules(quoteParams.actionModules),
_encodeUsingEip712Rules(quoteParams.actionModulesInitDatas),
quoteParams.referenceModule,
_encodeUsingEip712Rules(quoteParams.referenceModuleInitData),
nonce,
deadline
)
)
);
return _calculateDigest(structHash);
}
function _getMirrorTypedDataHash(
Types.MirrorParams memory mirrorParams,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
bytes32 structHash = keccak256(
abi.encode(
Typehash.MIRROR,
mirrorParams.profileId,
_encodeUsingEip712Rules(mirrorParams.metadataURI),
mirrorParams.pointedProfileId,
mirrorParams.pointedPubId,
_encodeUsingEip712Rules(mirrorParams.referrerProfileIds),
_encodeUsingEip712Rules(mirrorParams.referrerPubIds),
_encodeUsingEip712Rules(mirrorParams.referenceModuleData),
nonce,
deadline
)
);
return _calculateDigest(structHash);
}
function _getFollowTypedDataHash(
uint256 followerProfileId,
uint256[] memory idsOfProfilesToFollow,
uint256[] memory followTokenIds,
bytes[] memory datas,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
bytes32 structHash = keccak256(
abi.encode(
Typehash.FOLLOW,
followerProfileId,
_encodeUsingEip712Rules(idsOfProfilesToFollow),
_encodeUsingEip712Rules(followTokenIds),
_encodeUsingEip712Rules(datas),
nonce,
deadline
)
);
return _calculateDigest(structHash);
}
function _getActTypedDataHash(
Types.PublicationActionParams memory publicationActionParams,
uint256 nonce,
uint256 deadline
) internal view returns (bytes32) {
bytes32 structHash = keccak256(
abi.encode(
Typehash.ACT,
publicationActionParams.publicationActedProfileId,
publicationActionParams.publicationActedId,
publicationActionParams.actorProfileId,
_encodeUsingEip712Rules(publicationActionParams.referrerProfileIds),
_encodeUsingEip712Rules(publicationActionParams.referrerPubIds),
publicationActionParams.actionModuleAddress,
_encodeUsingEip712Rules(publicationActionParams.actionModuleData),
nonce,
deadline
)
);
return _calculateDigest(structHash);
}
function _calculateDigest(bytes32 structHash) internal view returns (bytes32) {
return keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash));
}
function _getSigStruct(
uint256 pKey,
bytes32 digest,
uint256 deadline
) internal pure returns (Types.EIP712Signature memory) {
return _getSigStruct(vm.addr(pKey), pKey, digest, deadline);
}
function _getSigStruct(
address signer,
uint256 pKey,
bytes32 digest,
uint256 deadline
) internal pure returns (Types.EIP712Signature memory) {
(uint8 v, bytes32 r, bytes32 s) = vm.sign(pKey, digest);
return Types.EIP712Signature(signer, v, r, s, deadline);
}
function _toLegacyV1Pub(uint256 profileId, uint256 pubId, address referenceModule, address collectModule) internal {
uint256 PUBLICATIONS_MAPPING_SLOT = 20;
uint256 publicationSlot;
{
// NOTE: Quotes are converted into V1 comments.
Types.PublicationType pubType = hub.getPublicationType(profileId, pubId);
if (pubType == Types.PublicationType.Nonexistent) {
revert('Cannot convert unexistent or already V1 publications.');
} else if (pubType == Types.PublicationType.Mirror && collectModule != address(0)) {
revert('Legacy V1 mirrors cannot have collect module.');
} else if (pubType != Types.PublicationType.Mirror && collectModule == address(0)) {
revert('Legacy V1 non-mirror publications requires a non-zero collect module.');
}
assembly {
mstore(0, profileId)
mstore(32, PUBLICATIONS_MAPPING_SLOT)
mstore(32, keccak256(0, 64))
mstore(0, pubId)
publicationSlot := keccak256(0, 64)
}
uint256 REFERENCE_MODULE_OFFSET = 3;
uint256 referenceModuleSlot = publicationSlot + REFERENCE_MODULE_OFFSET;
vm.store({
target: address(hub),
slot: bytes32(referenceModuleSlot),
value: bytes32(uint256(uint160(referenceModule)))
});
uint256 COLLECT_MODULE_OFFSET = 4;
uint256 collectModuleSlot = publicationSlot + COLLECT_MODULE_OFFSET;
vm.store({
target: address(hub),
slot: bytes32(collectModuleSlot),
value: bytes32(uint256(uint160(collectModule)))
});
uint256 firstSlotOffsetToWipe = 5;
uint256 lastSlotOffsetToWipe = 8;
for (uint256 offset = firstSlotOffsetToWipe; offset <= lastSlotOffsetToWipe; offset++) {
vm.store({target: address(hub), slot: bytes32(publicationSlot + offset), value: 0});
}
}
{
uint256 ACTION_MODULES_OFFSET = 8;
uint256 ACTION_MODULES_MAPPING_SLOT = publicationSlot + ACTION_MODULES_OFFSET;
_setActionModuleInPublicationStorage(
ACTION_MODULES_MAPPING_SLOT,
_getDefaultPostParams().actionModules[0],
false
);
_setActionModuleInPublicationStorage(
ACTION_MODULES_MAPPING_SLOT,
_getDefaultCommentParams().actionModules[0],
false
);
_setActionModuleInPublicationStorage(
ACTION_MODULES_MAPPING_SLOT,
_getDefaultQuoteParams().actionModules[0],
false
);
}
}
function _setCollectModuleAsIfItWasWhitelistedInLensV1(address collectModule) internal {
_setCollectModuleWhitelistedInLensV1Storage(collectModule, true);
}
function _setCollectModuleWhitelistedInLensV1Storage(address collectModule, bool whitelisted) internal {
uint256 COLLECT_MODULE_WHITELISTED_MAPPING_SLOT = 15;
uint256 collectModuleWhitelistSlot;
assembly {
mstore(0, collectModule)
mstore(32, COLLECT_MODULE_WHITELISTED_MAPPING_SLOT)
collectModuleWhitelistSlot := keccak256(0, 64)
}
bytes32 whitelistedAsBytes32 = bytes32(uint256(whitelisted ? 1 : 0));
vm.store({target: address(hub), slot: bytes32(collectModuleWhitelistSlot), value: whitelistedAsBytes32});
}
function _setActionModuleInPublicationStorage(
uint256 actionModuleMappingSlot,
address module,
bool isEnabled
) internal {
bytes32 slot;
assembly {
mstore(0, module)
mstore(32, actionModuleMappingSlot)
slot := keccak256(0, 64)
}
vm.store({target: address(hub), slot: slot, value: bytes32(uint256(isEnabled ? 1 : 0))});
}
function _isV1LegacyPub(Types.PublicationMemory memory pub) internal pure returns (bool) {
return uint8(pub.pubType) == 0;
}
function _encodeUsingEip712Rules(bytes[] memory bytesArray) internal pure returns (bytes32) {
bytes32[] memory bytesArrayEncodedElements = new bytes32[](bytesArray.length);
uint256 i;
while (i < bytesArray.length) {
// A `bytes` type is encoded as its keccak256 hash.
bytesArrayEncodedElements[i] = keccak256(bytesArray[i]);
unchecked {
++i;
}
}
// An array is encoded as the keccak256 hash of the concatenation of their encoded elements.
return _encodeUsingEip712Rules(bytesArrayEncodedElements);
}
function _encodeUsingEip712Rules(bool[] memory boolArray) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(boolArray));
}
function _encodeUsingEip712Rules(address[] memory addressArray) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(addressArray));
}
function _encodeUsingEip712Rules(uint256[] memory uint256Array) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(uint256Array));
}
function _encodeUsingEip712Rules(bytes32[] memory bytes32Array) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(bytes32Array));
}
function _encodeUsingEip712Rules(string memory stringValue) internal pure returns (bytes32) {
return keccak256(bytes(stringValue));
}
function _encodeUsingEip712Rules(bytes memory bytesValue) internal pure returns (bytes32) {
return keccak256(bytesValue);
}
function _transferHandle(address to, uint256 handleId) internal {
address initialHandleHolder = lensHandles.ownerOf(handleId);
vm.prank(initialHandleHolder);
lensHandles.transferFrom(initialHandleHolder, to, handleId);
}
function _transferProfile(address to, uint256 profileId) internal {
address initialProfileHolder = hub.ownerOf(profileId);
_effectivelyDisableProfileGuardian(initialProfileHolder);
vm.prank(initialProfileHolder);
hub.transferFrom(initialProfileHolder, to, profileId);
}
}