mirror of
https://github.com/lens-protocol/core.git
synced 2026-01-14 08:28:03 -05:00
(WIP) refactor: Refactored to reduce storage pointers passed.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user