(WIP) refactor: Refactored to reduce storage pointers passed.

This commit is contained in:
Peter Michael
2022-06-20 18:46:35 -04:00
parent 61f9fa1688
commit b5d00a99be
6 changed files with 112 additions and 68 deletions

View File

@@ -346,8 +346,7 @@ contract LensHub is
whenNotPaused
returns (uint256[] memory)
{
return
GeneralLib.follow(msg.sender, profileIds, datas, _profileById, _profileIdByHandleHash);
return GeneralLib.follow(msg.sender, profileIds, datas);
}
/// @inheritdoc ILensHub
@@ -357,7 +356,7 @@ contract LensHub is
whenNotPaused
returns (uint256[] memory)
{
return GeneralLib.followWithSig(vars, _profileById, _profileIdByHandleHash);
return GeneralLib.followWithSig(vars);
}
/// @inheritdoc ILensHub

View File

@@ -36,6 +36,7 @@ uint256 constant NAME_SLOT_GT_31 = 0x290decd9548b62a8d60345a988386fc84ba6bc95484
// Profile struct offsets
uint256 constant PROFILE_FOLLOW_MODULE_OFFSET = 1;
uint256 constant PROFILE_FOLLOW_NFT_OFFSET = 2;
uint256 constant PROFILE_HANDLE_OFFSET = 3;
uint256 constant PROFILE_IMAGE_URI_OFFSET = 4;
uint256 constant PROFILE_FOLLOW_NFT_URI_OFFSET = 5;

View File

@@ -173,7 +173,6 @@ library GeneralLib {
let slot := add(keccak256(0, 64), PROFILE_FOLLOW_MODULE_OFFSET)
sstore(slot, followModule)
}
followModuleReturnData = _initFollowModule(
profileId,
vars.followModule,
@@ -333,26 +332,15 @@ library GeneralLib {
* @param follower The address executing the follow.
* @param profileIds The array of profile token IDs to follow.
* @param followModuleDatas The array of follow module data parameters to pass to each profile's follow module.
* @param _profileById A pointer to the storage mapping of profile structs by profile ID.
* @param _profileIdByHandleHash A pointer to the storage mapping of profile IDs by handle hash.
*
* @return uint256[] An array of integers representing the minted follow NFTs token IDs.
*/
function follow(
address follower,
uint256[] calldata profileIds,
bytes[] calldata followModuleDatas,
mapping(uint256 => DataTypes.ProfileStruct) storage _profileById,
mapping(bytes32 => uint256) storage _profileIdByHandleHash
bytes[] calldata followModuleDatas
) external returns (uint256[] memory) {
return
InteractionHelpers.follow(
follower,
profileIds,
followModuleDatas,
_profileById,
_profileIdByHandleHash
);
return InteractionHelpers.follow(follower, profileIds, followModuleDatas);
}
/**
@@ -361,20 +349,12 @@ library GeneralLib {
*
* @param vars the FollowWithSigData struct containing the relevant parameters.
*/
function followWithSig(
DataTypes.FollowWithSigData calldata vars,
mapping(uint256 => DataTypes.ProfileStruct) storage _profileById,
mapping(bytes32 => uint256) storage _profileIdByHandleHash
) external returns (uint256[] memory) {
function followWithSig(DataTypes.FollowWithSigData calldata vars)
external
returns (uint256[] memory)
{
MetaTxHelpers.baseFollowWithSig(vars);
return
InteractionHelpers.follow(
vars.follower,
vars.profileIds,
vars.datas,
_profileById,
_profileIdByHandleHash
);
return InteractionHelpers.follow(vars.follower, vars.profileIds, vars.datas);
}
/**
@@ -545,17 +525,12 @@ library GeneralLib {
address followModule,
bytes calldata followModuleInitData
) private {
address currentFollowModule;
uint256 slot;
assembly {
mstore(0, profileId)
mstore(32, PROFILE_BY_ID_MAPPING_SLOT)
slot := add(keccak256(0, 64), PROFILE_FOLLOW_MODULE_OFFSET)
currentFollowModule := sload(slot)
}
if (followModule != currentFollowModule) {
assembly {
let slot := add(keccak256(0, 64), PROFILE_FOLLOW_MODULE_OFFSET)
let currentFollowModule := sload(slot)
if iszero(eq(followModule, currentFollowModule)) {
sstore(slot, followModule)
}
}

View File

@@ -11,8 +11,7 @@ import './Constants.sol';
* @title Helpers
* @author Lens Protocol
*
* @notice This is a library that only contains a single function that is used in the hub contract as well as in
* both the publishing logic and interaction logic libraries.
* @notice This is a library that contains helper internal functions used by both the Hub and the GeneralLib.
*/
library Helpers {
/**
@@ -22,16 +21,13 @@ library Helpers {
* @param profileId The token ID of the profile that published the given publication.
* @param pubId The publication ID of the given publication.
*
* @return tuple First, the pointed publication's publishing profile ID, and second, the pointed publication's ID.
* @return tuple First, the pointed publication's publishing profile ID, and second, the pointed publication's ID.
* If the passed publication is not a mirror, this returns the given publication.
*/
function getPointedIfMirror(uint256 profileId, uint256 pubId)
internal
view
returns (
uint256,
uint256
)
returns (uint256, uint256)
{
uint256 slot;
address collectModule;

View File

@@ -30,24 +30,37 @@ library InteractionHelpers {
function follow(
address follower,
uint256[] calldata profileIds,
bytes[] calldata followModuleDatas,
mapping(uint256 => DataTypes.ProfileStruct) storage _profileById,
mapping(bytes32 => uint256) storage _profileIdByHandleHash
) internal returns (uint256[] memory) {
bytes[] calldata followModuleDatas //,
)
internal
returns (
uint256[] memory
)
{
if (profileIds.length != followModuleDatas.length) revert Errors.ArrayMismatch();
uint256[] memory tokenIds = new uint256[](profileIds.length);
for (uint256 i = 0; i < profileIds.length; ) {
string memory handle = _profileById[profileIds[i]].handle;
if (_profileIdByHandleHash[keccak256(bytes(handle))] != profileIds[i])
revert Errors.TokenDoesNotExist();
address followModule = _profileById[profileIds[i]].followModule;
address followNFT = _profileById[profileIds[i]].followNFT;
uint256 profileId = profileIds[i];
_validateProfileExistsViaHandle(profileId);
uint256 followNFTSlot;
address followModule;
address followNFT;
assembly {
mstore(0, profileId)
mstore(32, PROFILE_BY_ID_MAPPING_SLOT)
// The follow NFT offset is 2, the follow module offset is 1,
// so we just need to subtract 1 instead of recalculating the slot.
followNFTSlot := add(keccak256(0, 64), PROFILE_FOLLOW_NFT_OFFSET)
followModule := sload(sub(followNFTSlot,1))
followNFT := sload(followNFTSlot)
}
if (followNFT == address(0)) {
followNFT = _deployFollowNFT(profileIds[i]);
_profileById[profileIds[i]].followNFT = followNFT;
followNFT = _deployFollowNFT(profileId);
assembly {
sstore(followNFTSlot, followNFT)
}
}
tokenIds[i] = IFollowNFT(followNFT).mint(follower);
@@ -55,7 +68,7 @@ library InteractionHelpers {
if (followModule != address(0)) {
IFollowModule(followModule).processFollow(
follower,
profileIds[i],
profileId,
followModuleDatas[i]
);
}
@@ -79,7 +92,7 @@ library InteractionHelpers {
) internal returns (uint256) {
(uint256 rootProfileId, uint256 rootPubId, address rootCollectModule) = Helpers
.getPointedIfMirrorWithCollectModule(profileId, pubId);
uint256 tokenId;
// Avoids stack too deep
{
@@ -196,4 +209,67 @@ library InteractionHelpers {
block.timestamp
);
}
function _validateProfileExistsViaHandle(uint256 profileId) private view {
bool shouldRevert;
assembly {
// Load the free memory pointer, where we'll return the value
let ptr := mload(64)
// Load the slot, which either contains the name + 2*length if length < 32 or
// 2*length+1 if length >= 32, and the actual string starts at slot keccak256(slot)
mstore(0, profileId)
mstore(32, PROFILE_BY_ID_MAPPING_SLOT)
let slot := add(keccak256(0, 64), PROFILE_HANDLE_OFFSET)
let slotLoad := sload(slot)
let size
// Determine if the length > 32 by checking the lowest order bit, meaning the string
// itself is stored at keccak256(slot)
switch and(slotLoad, 1)
case 0 {
// The name is in the same slot
// Determine the size by dividing the last byte's value by 2
size := shr(1, and(slotLoad, 255))
// Store the size in the first slot
mstore(ptr, size)
// Store the actual string in the second slot (without the size)
mstore(add(ptr, 32), and(slotLoad, not(255)))
}
case 1 {
// The handle is not in the same slot
// Determine the size by dividing the value in the whole slot minus 1 by 2
size := shr(1, sub(slotLoad, 1))
// Store the size in the first slot
mstore(ptr, size)
// Compute the total memory slots we need, this is (size + 31) / 32
let totalMemorySlots := shr(5, add(size, 31))
mstore(0, slot)
let handleSlot := keccak256(0, 32)
// Iterate through the words in memory and store the string word by word
// prettier-ignore
for { let i := 0 } lt(i, totalMemorySlots) { i := add(i, 1) } {
mstore(add(add(ptr, 32), mul(32, i)), sload(add(handleSlot, i)))
}
}
let handleHash := keccak256(add(ptr, 32), size)
mstore(0, handleHash)
mstore(32, PROFILE_ID_BY_HANDLE_HASH_MAPPING_SLOT)
let handleHashSlot := keccak256(0, 64)
let resolvedProfileId := sload(handleHashSlot)
if iszero(eq(resolvedProfileId, profileId)) {
shouldRevert := true
}
// Store the new memory pointer in the free memory pointer slot
mstore(64, add(add(ptr, 32), size))
}
if (shouldRevert) revert Errors.TokenDoesNotExist();
}
}

View File

@@ -381,27 +381,25 @@ library MetaTxHelpers {
// 2*length+1 if length >= 32, and the actual string starts at slot keccak256(NAME_SLOT)
let slotLoad := sload(NAME_SLOT)
let size
// Determine if the length > 32 by checking the lowest order bit, meaning the string
// itself is stored at keccak256(NAME_SLOT)
switch and(slotLoad, 1)
case 0 {
// The name is in the same slot
// Determine the size by dividing the last byte's value by 2
let size := shr(1, and(slotLoad, 255))
size := shr(1, and(slotLoad, 255))
// Store the size in the first slot
mstore(ptr, size)
// Store the actual string in the second slot (without the size)
mstore(add(ptr, 32), and(slotLoad, not(255)))
// Store the new memory pointer in the free memory pointer slot
mstore(64, add(add(ptr, 32), size))
}
case 1 {
// The name is not in the same slot
// Determine the size by dividing the value in the whole slot minus 1 by 2
let size := shr(1, sub(slotLoad, 1))
size := shr(1, sub(slotLoad, 1))
// Store the size in the first slot
mstore(ptr, size)
@@ -414,10 +412,9 @@ library MetaTxHelpers {
for { let i := 0 } lt(i, totalMemorySlots) { i := add(i, 1) } {
mstore(add(add(ptr, 32), mul(32, i)), sload(add(NAME_SLOT_GT_31, i)))
}
// Store the new memory pointer in the free memory pointer slot
mstore(64, add(add(ptr, 32), size))
}
// Store the new memory pointer in the free memory pointer slot
mstore(64, add(add(ptr, 32), size))
}
// Return a memory pointer to the name (which always starts with the size at the first slot)
return ptr;