mirror of
https://github.com/lens-protocol/core.git
synced 2026-04-22 03:02:03 -04:00
Merge pull request #90 from lens-protocol/test/token-handle-registry
Test/token handle registry
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -4,3 +4,6 @@
|
||||
[submodule "lib/forge-std"]
|
||||
path = lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
[submodule "lib/solady"]
|
||||
path = lib/solady
|
||||
url = https://github.com/Vectorized/solady
|
||||
|
||||
@@ -89,12 +89,19 @@ contract LensHandles is ERC721, ImmutableOwnable, ILensHandles {
|
||||
return NAMESPACE_HASH;
|
||||
}
|
||||
|
||||
// TODO: Should we revert if it doesn't exist?
|
||||
function getLocalName(uint256 tokenId) public view returns (string memory) {
|
||||
string memory localName = _localNames[tokenId];
|
||||
if (bytes(localName).length == 0) {
|
||||
revert HandlesErrors.DoesNotExist();
|
||||
}
|
||||
return _localNames[tokenId];
|
||||
}
|
||||
|
||||
// TODO: Should we revert if it doesn't exist?
|
||||
function getHandle(uint256 tokenId) public view returns (string memory) {
|
||||
return string.concat(_localNames[tokenId], '.', NAMESPACE);
|
||||
string memory localName = getLocalName(tokenId);
|
||||
return string.concat(localName, '.', NAMESPACE);
|
||||
}
|
||||
|
||||
function getTokenId(string memory localName) public pure returns (uint256) {
|
||||
@@ -106,19 +113,21 @@ contract LensHandles is ERC721, ImmutableOwnable, ILensHandles {
|
||||
//////////////////////////////////////
|
||||
|
||||
function _validateLocalName(string memory localName) internal view {
|
||||
uint256 localNameLength = bytes(localName).length;
|
||||
bytes memory localNameAsBytes = bytes(localName);
|
||||
uint256 localNameLength = localNameAsBytes.length;
|
||||
|
||||
if (localNameLength == 0 || localNameLength + SEPARATOR_LENGTH + NAMESPACE_LENGTH > MAX_HANDLE_LENGTH) {
|
||||
revert HandlesErrors.HandleLengthInvalid();
|
||||
}
|
||||
|
||||
bytes1 firstByte = bytes(localName)[0];
|
||||
bytes1 firstByte = localNameAsBytes[0];
|
||||
if (firstByte == '-' || firstByte == '_') {
|
||||
revert HandlesErrors.HandleFirstCharInvalid();
|
||||
}
|
||||
|
||||
uint256 i;
|
||||
while (i < localNameLength) {
|
||||
if (bytes(localName)[i] == '.') {
|
||||
if (!_isAlphaNumeric(localNameAsBytes[i]) && localNameAsBytes[i] != '-' && localNameAsBytes[i] != '_') {
|
||||
revert HandlesErrors.HandleContainsInvalidCharacters();
|
||||
}
|
||||
unchecked {
|
||||
@@ -126,4 +135,8 @@ contract LensHandles is ERC721, ImmutableOwnable, ILensHandles {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _isAlphaNumeric(bytes1 char) internal pure returns (bool) {
|
||||
return (char >= '0' && char <= '9') || (char >= 'a' && char <= 'z');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,26 +39,14 @@ contract TokenHandleRegistry is ITokenHandleRegistry {
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyHandleOrTokenOwner(
|
||||
uint256 handleId,
|
||||
uint256 tokenId,
|
||||
address transactionExecutor
|
||||
) {
|
||||
if (
|
||||
IERC721(LENS_HANDLES).ownerOf(handleId) != transactionExecutor &&
|
||||
IERC721(LENS_HUB).ownerOf(tokenId) != transactionExecutor
|
||||
) {
|
||||
revert RegistryErrors.NotHandleNorTokenOwner();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(address lensHub, address lensHandles) {
|
||||
LENS_HUB = lensHub;
|
||||
LENS_HANDLES = lensHandles;
|
||||
}
|
||||
|
||||
// Lens V1 to Lens V2 migration function
|
||||
// WARNING: It is able to link the Token and Handle even if they're not in the same wallet.
|
||||
// But it is designed to be only called from LensHub migration function, which assures that they are.
|
||||
function migrationLink(uint256 handleId, uint256 tokenId) external {
|
||||
if (msg.sender != LENS_HUB) {
|
||||
revert RegistryErrors.OnlyLensHub();
|
||||
@@ -81,9 +69,21 @@ contract TokenHandleRegistry is ITokenHandleRegistry {
|
||||
}
|
||||
|
||||
/// @inheritdoc ITokenHandleRegistry
|
||||
function unlink(uint256 handleId, uint256 tokenId) external onlyHandleOrTokenOwner(handleId, tokenId, msg.sender) {
|
||||
function unlink(uint256 handleId, uint256 tokenId) external {
|
||||
// We revert here only in the case if both tokens exists and the caller is not the owner of any of them
|
||||
if (
|
||||
ILensHandles(LENS_HANDLES).exists(handleId) &&
|
||||
ILensHandles(LENS_HANDLES).ownerOf(handleId) != msg.sender &&
|
||||
ILensHub(LENS_HUB).exists(tokenId) &&
|
||||
ILensHub(LENS_HUB).ownerOf(tokenId) != msg.sender
|
||||
) {
|
||||
revert RegistryErrors.NotHandleNorTokenOwner();
|
||||
}
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: LENS_HANDLES, id: handleId});
|
||||
RegistryTypes.Token memory tokenPointedByHandle = handleToToken[_handleHash(handle)];
|
||||
|
||||
// We check if the tokens are (were) linked for the case if some of them doesn't exist
|
||||
if (tokenPointedByHandle.id != tokenId) {
|
||||
revert RegistryErrors.NotLinked();
|
||||
}
|
||||
@@ -115,11 +115,6 @@ contract TokenHandleRegistry is ITokenHandleRegistry {
|
||||
return defaultHandleId;
|
||||
}
|
||||
|
||||
// TODO: Add this to interface and make it prettier
|
||||
function isLinked(uint256 handleId, uint256 tokenId) external view returns (bool) {
|
||||
return this.resolve(handleId) == tokenId && this.getDefaultHandle(tokenId) == handleId;
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
/// INTERNAL FUNCTIONS ///
|
||||
//////////////////////////////////////
|
||||
|
||||
@@ -17,4 +17,5 @@ library HandlesErrors {
|
||||
error HandleFirstCharInvalid();
|
||||
error NotOwnerNorWhitelisted();
|
||||
error NotOwner();
|
||||
error DoesNotExist();
|
||||
}
|
||||
|
||||
1
lib/solady
Submodule
1
lib/solady
Submodule
Submodule lib/solady added at 6675f94f3f
@@ -11,3 +11,5 @@ operator-filter-registry/=lib/seadrop/lib/operator-filter-registry/src/
|
||||
solmate/=lib/seadrop/lib/solmate/src/
|
||||
utility-contracts/=lib/seadrop/lib/utility-contracts/src/
|
||||
create2-scripts/=lib/seadrop/lib/create2-helpers/script/
|
||||
|
||||
solady/=lib/solady/src/
|
||||
|
||||
@@ -156,6 +156,7 @@ contract ProxyAdminTest is BaseTest {
|
||||
|
||||
assertEq(hub.ownerOf(profileId), profileOwner, 'Profile owner mismatch');
|
||||
assertEq(lensHandles.ownerOf(handleId), profileOwner, 'Handle owner mismatch');
|
||||
assertTrue(tokenHandleRegistry.isLinked(handleId, profileId), 'Handle not linked to profile');
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId, 'Handle not linked to profile');
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId, 'Profile not linked to handle');
|
||||
}
|
||||
}
|
||||
|
||||
354
test/namespaces/LensHandlesTest.t.sol
Normal file
354
test/namespaces/LensHandlesTest.t.sol
Normal file
@@ -0,0 +1,354 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.13;
|
||||
|
||||
import 'test/base/BaseTest.t.sol';
|
||||
import {LibString} from 'solady/utils/LibString.sol';
|
||||
import {Base64} from 'solady/utils/Base64.sol';
|
||||
import {HandlesErrors} from 'contracts/namespaces/constants/Errors.sol';
|
||||
import {HandlesEvents} from 'contracts/namespaces/constants/Events.sol';
|
||||
|
||||
contract LensHandlesTest is BaseTest {
|
||||
using stdJson for string;
|
||||
|
||||
uint256 constant MAX_HANDLE_LENGTH = 26;
|
||||
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
// NEGATIVES
|
||||
|
||||
function testCannot_GetTokenURI_IfNotMinted(uint256 tokenId) public {
|
||||
vm.assume(!lensHandles.exists(tokenId));
|
||||
|
||||
vm.expectRevert('ERC721: invalid token ID');
|
||||
lensHandles.tokenURI(tokenId);
|
||||
}
|
||||
|
||||
function testCannot_Burn_IfNotOwnerOf(address owner, address otherAddress) public {
|
||||
vm.assume(owner != otherAddress);
|
||||
vm.assume(owner != address(0));
|
||||
vm.assume(otherAddress != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(lensHandles), ADMIN_SLOT))));
|
||||
vm.assume(otherAddress != proxyAdmin);
|
||||
|
||||
string memory handle = 'handle';
|
||||
|
||||
vm.prank(address(hub));
|
||||
uint256 handleId = lensHandles.mintHandle(owner, handle);
|
||||
|
||||
assertTrue(lensHandles.exists(handleId));
|
||||
assertEq(lensHandles.ownerOf(handleId), owner);
|
||||
|
||||
vm.expectRevert(HandlesErrors.NotOwner.selector);
|
||||
|
||||
vm.prank(otherAddress);
|
||||
lensHandles.burn(handleId);
|
||||
}
|
||||
|
||||
function testCannot_MintHandle_IfNotOwnerOrHubOrWhitelistedProfileCreator(address otherAddress) public {
|
||||
vm.assume(otherAddress != address(0));
|
||||
vm.assume(otherAddress != address(hub));
|
||||
vm.assume(otherAddress != lensHandles.OWNER());
|
||||
vm.assume(!hub.isProfileCreatorWhitelisted(otherAddress));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(lensHandles), ADMIN_SLOT))));
|
||||
vm.assume(otherAddress != proxyAdmin);
|
||||
|
||||
string memory handle = 'handle';
|
||||
|
||||
vm.expectRevert(HandlesErrors.NotOwnerNorWhitelisted.selector);
|
||||
|
||||
vm.prank(otherAddress);
|
||||
lensHandles.mintHandle(otherAddress, handle);
|
||||
}
|
||||
|
||||
function testCannot_MintHandle_WithZeroLength() public {
|
||||
vm.expectRevert(HandlesErrors.HandleLengthInvalid.selector);
|
||||
|
||||
vm.prank(address(hub));
|
||||
lensHandles.mintHandle(address(this), '');
|
||||
}
|
||||
|
||||
function testCannot_MintHandle_WithNonUniqueLocalName() public {
|
||||
vm.prank(address(hub));
|
||||
lensHandles.mintHandle(address(this), 'handle');
|
||||
|
||||
vm.expectRevert('ERC721: token already minted');
|
||||
|
||||
vm.prank(address(hub));
|
||||
lensHandles.mintHandle(makeAddr('ANOTHER_ADDRESS'), 'handle');
|
||||
}
|
||||
|
||||
function testCannot_MintHandle_WithLengthMoreThanMax(uint256 randomFuzz) public {
|
||||
string memory randomHandle = _randomAlphanumericString(MAX_HANDLE_LENGTH + 1, randomFuzz);
|
||||
|
||||
vm.expectRevert(HandlesErrors.HandleLengthInvalid.selector);
|
||||
|
||||
vm.prank(address(hub));
|
||||
lensHandles.mintHandle(address(this), randomHandle);
|
||||
}
|
||||
|
||||
function testCannot_MintHandle_WithInvalidFirstChar(uint256 length, uint256 randomFuzz) public {
|
||||
length = bound(length, 0, MAX_HANDLE_LENGTH - 1); // we will add 1 char at the start, so length is shorter by 1
|
||||
|
||||
string memory randomHandle = _randomAlphanumericString(length, randomFuzz);
|
||||
|
||||
string memory invalidUnderscoreHandle = string.concat('_', randomHandle);
|
||||
|
||||
vm.expectRevert(HandlesErrors.HandleFirstCharInvalid.selector);
|
||||
|
||||
vm.prank(address(hub));
|
||||
lensHandles.mintHandle(address(this), invalidUnderscoreHandle);
|
||||
|
||||
string memory invalidDashHandle = string.concat('-', randomHandle);
|
||||
|
||||
vm.expectRevert(HandlesErrors.HandleFirstCharInvalid.selector);
|
||||
|
||||
vm.prank(address(hub));
|
||||
lensHandles.mintHandle(address(this), invalidDashHandle);
|
||||
}
|
||||
|
||||
function testCannot_MintHandle_WithInvalidChar(
|
||||
uint256 length,
|
||||
uint256 insertionPosition,
|
||||
uint256 randomFuzz,
|
||||
uint256 invalidCharCode
|
||||
) public {
|
||||
length = bound(length, 1, MAX_HANDLE_LENGTH);
|
||||
insertionPosition = bound(insertionPosition, 0, length - 1);
|
||||
invalidCharCode = bound(invalidCharCode, 0x00, 0xFF);
|
||||
vm.assume(
|
||||
(invalidCharCode < 48 || // '0'
|
||||
invalidCharCode > 122 || // 'z'
|
||||
(invalidCharCode > 57 && invalidCharCode < 97)) && // '9' and 'a'
|
||||
invalidCharCode != 45 && // '-'
|
||||
invalidCharCode != 95 // '_'
|
||||
);
|
||||
|
||||
string memory randomHandle = _randomAlphanumericString(length, randomFuzz);
|
||||
|
||||
console.log('randomHandle:', randomHandle);
|
||||
console.log('insert position:', insertionPosition);
|
||||
console.log('invalid char code:', invalidCharCode);
|
||||
|
||||
bytes memory randomHandleBytes = bytes(randomHandle);
|
||||
randomHandleBytes[insertionPosition] = bytes1(uint8(invalidCharCode));
|
||||
|
||||
string memory invalidHandle = string(randomHandleBytes);
|
||||
|
||||
console.log('invalidHandle', invalidHandle);
|
||||
|
||||
vm.expectRevert(HandlesErrors.HandleContainsInvalidCharacters.selector);
|
||||
vm.prank(address(hub));
|
||||
lensHandles.mintHandle(address(this), invalidHandle);
|
||||
}
|
||||
|
||||
// SCENARIOS
|
||||
|
||||
function testName() public {
|
||||
string memory name = lensHandles.name();
|
||||
assertEq(name, '.lens Handles');
|
||||
}
|
||||
|
||||
function testSymbol() public {
|
||||
string memory symbol = lensHandles.symbol();
|
||||
assertEq(symbol, '.lens');
|
||||
}
|
||||
|
||||
function testExists(uint256 number) public {
|
||||
number = bound(number, 1, 10 ** (MAX_HANDLE_LENGTH) - 1);
|
||||
string memory numbersHandle = vm.toString(number);
|
||||
uint256 expectedTokenId = lensHandles.getTokenId(numbersHandle);
|
||||
vm.assume(!lensHandles.exists(expectedTokenId));
|
||||
|
||||
vm.prank(address(hub));
|
||||
uint256 handleId = lensHandles.mintHandle(address(this), numbersHandle);
|
||||
|
||||
assertEq(handleId, expectedTokenId);
|
||||
assertTrue(lensHandles.exists(handleId));
|
||||
|
||||
lensHandles.burn(handleId);
|
||||
assertFalse(lensHandles.exists(handleId));
|
||||
}
|
||||
|
||||
function testGetNamespace() public {
|
||||
string memory namespace = lensHandles.getNamespace();
|
||||
assertEq(namespace, 'lens');
|
||||
}
|
||||
|
||||
function testGetNamespaceHash() public {
|
||||
string memory namespace = lensHandles.getNamespace();
|
||||
bytes32 namespaceHash = lensHandles.getNamespaceHash();
|
||||
assertEq(namespaceHash, keccak256(bytes(namespace)));
|
||||
}
|
||||
|
||||
function testConstructionImmutables(address owner, address hub) public {
|
||||
LensHandles newLensHandles = new LensHandles(owner, hub);
|
||||
assertEq(newLensHandles.OWNER(), owner);
|
||||
assertEq(newLensHandles.LENS_HUB(), hub);
|
||||
}
|
||||
|
||||
// TODO: Should we revert if it doesn't exist?
|
||||
function testGetLocalName(uint256 number) public {
|
||||
number = bound(number, 1, 10 ** (MAX_HANDLE_LENGTH) - 1);
|
||||
string memory numbersHandle = vm.toString(number);
|
||||
uint256 expectedTokenId = lensHandles.getTokenId(numbersHandle);
|
||||
vm.assume(!lensHandles.exists(expectedTokenId));
|
||||
|
||||
vm.expectRevert(HandlesErrors.DoesNotExist.selector);
|
||||
lensHandles.getLocalName(expectedTokenId);
|
||||
|
||||
vm.prank(address(hub));
|
||||
uint256 handleId = lensHandles.mintHandle(address(this), numbersHandle);
|
||||
|
||||
assertEq(handleId, expectedTokenId);
|
||||
|
||||
string memory localName = lensHandles.getLocalName(handleId);
|
||||
assertEq(localName, numbersHandle);
|
||||
|
||||
lensHandles.burn(handleId);
|
||||
|
||||
vm.expectRevert(HandlesErrors.DoesNotExist.selector);
|
||||
lensHandles.getLocalName(expectedTokenId);
|
||||
}
|
||||
|
||||
// TODO: Should we revert if it doesn't exist?
|
||||
function testGetHandle(uint256 number) public {
|
||||
number = bound(number, 1, 10 ** (MAX_HANDLE_LENGTH) - 1);
|
||||
string memory numbersHandle = vm.toString(number);
|
||||
uint256 expectedTokenId = lensHandles.getTokenId(numbersHandle);
|
||||
vm.assume(!lensHandles.exists(expectedTokenId));
|
||||
|
||||
vm.expectRevert(HandlesErrors.DoesNotExist.selector);
|
||||
lensHandles.getHandle(expectedTokenId);
|
||||
|
||||
vm.prank(address(hub));
|
||||
uint256 handleId = lensHandles.mintHandle(address(this), numbersHandle);
|
||||
|
||||
assertEq(handleId, expectedTokenId);
|
||||
|
||||
string memory namespaceSuffix = string.concat('.', lensHandles.getNamespace());
|
||||
string memory handle = lensHandles.getHandle(handleId);
|
||||
assertEq(handle, string.concat(numbersHandle, namespaceSuffix));
|
||||
|
||||
lensHandles.burn(handleId);
|
||||
|
||||
vm.expectRevert(HandlesErrors.DoesNotExist.selector);
|
||||
lensHandles.getHandle(expectedTokenId);
|
||||
}
|
||||
|
||||
function testGetTokenId(uint256 number) public {
|
||||
number = bound(number, 1, 10 ** (MAX_HANDLE_LENGTH) - 1);
|
||||
string memory numbersHandle = vm.toString(number);
|
||||
|
||||
uint256 expectedTokenId = uint256(keccak256(bytes(numbersHandle)));
|
||||
assertEq(lensHandles.getTokenId(numbersHandle), expectedTokenId);
|
||||
}
|
||||
|
||||
function testTokenURI() public {
|
||||
string memory handle = 'handle';
|
||||
|
||||
vm.prank(address(hub));
|
||||
uint256 handleId = lensHandles.mintHandle(address(this), handle);
|
||||
|
||||
string memory tokenURI = lensHandles.tokenURI(handleId);
|
||||
|
||||
string memory base64prefix = 'data:application/json;base64,';
|
||||
|
||||
string memory decodedTokenURI = string(Base64.decode(LibString.slice(tokenURI, bytes(base64prefix).length)));
|
||||
|
||||
assertEq(decodedTokenURI.readString('.name'), string.concat('@', handle));
|
||||
assertEq(decodedTokenURI.readString('.description'), string.concat('Lens Protocol - @', handle));
|
||||
assertEq(decodedTokenURI.readUint('.attributes[0].value'), handleId);
|
||||
assertEq(decodedTokenURI.readString('.attributes[1].value'), lensHandles.symbol());
|
||||
assertEq(decodedTokenURI.readUint('.attributes[2].value'), bytes(handle).length);
|
||||
}
|
||||
|
||||
function testBurn(address owner) public {
|
||||
vm.assume(owner != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(lensHandles), ADMIN_SLOT))));
|
||||
vm.assume(owner != proxyAdmin);
|
||||
|
||||
string memory handle = 'handle';
|
||||
|
||||
vm.prank(address(hub));
|
||||
uint256 handleId = lensHandles.mintHandle(owner, handle);
|
||||
|
||||
assertTrue(lensHandles.exists(handleId));
|
||||
assertEq(lensHandles.ownerOf(handleId), owner);
|
||||
|
||||
vm.prank(owner);
|
||||
lensHandles.burn(handleId);
|
||||
|
||||
assertFalse(lensHandles.exists(handleId));
|
||||
|
||||
vm.expectRevert(HandlesErrors.DoesNotExist.selector);
|
||||
lensHandles.getLocalName(handleId);
|
||||
}
|
||||
|
||||
function testMintHandle_IfOwner(address to, uint256 length, uint256 randomFuzz) public {
|
||||
_mintHandle(lensHandles.OWNER(), to, length, randomFuzz);
|
||||
}
|
||||
|
||||
function testMintHandle_ifHub(address to, uint256 length, uint256 randomFuzz) public {
|
||||
_mintHandle(address(hub), to, length, randomFuzz);
|
||||
}
|
||||
|
||||
function testMintHandle_ifWhitelistedProfileCreator(
|
||||
address whitelistedProfileCreator,
|
||||
address to,
|
||||
uint256 length,
|
||||
uint256 randomFuzz
|
||||
) public {
|
||||
vm.assume(whitelistedProfileCreator != address(0));
|
||||
vm.assume(whitelistedProfileCreator != address(hub));
|
||||
vm.assume(whitelistedProfileCreator != lensHandles.OWNER());
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(lensHandles), ADMIN_SLOT))));
|
||||
vm.assume(whitelistedProfileCreator != proxyAdmin);
|
||||
|
||||
vm.prank(governance);
|
||||
hub.whitelistProfileCreator(whitelistedProfileCreator, true);
|
||||
_mintHandle(whitelistedProfileCreator, to, length, randomFuzz);
|
||||
}
|
||||
|
||||
function _mintHandle(address minter, address to, uint256 length, uint256 randomFuzz) internal {
|
||||
vm.assume(to != address(0));
|
||||
length = bound(length, 1, MAX_HANDLE_LENGTH);
|
||||
|
||||
string memory randomHandle = _randomAlphanumericString(length, randomFuzz);
|
||||
uint256 expectedHandleId = lensHandles.getTokenId(randomHandle);
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(lensHandles));
|
||||
emit HandlesEvents.HandleMinted(
|
||||
randomHandle,
|
||||
lensHandles.getNamespace(),
|
||||
expectedHandleId,
|
||||
to,
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
vm.prank(minter);
|
||||
uint256 handleId = lensHandles.mintHandle(to, randomHandle);
|
||||
assertEq(handleId, expectedHandleId);
|
||||
assertEq(lensHandles.ownerOf(handleId), to);
|
||||
|
||||
string memory localName = lensHandles.getLocalName(handleId);
|
||||
assertEq(localName, randomHandle);
|
||||
}
|
||||
|
||||
function _randomAlphanumericString(uint256 length, uint256 randomFuzz) internal view returns (string memory) {
|
||||
bytes memory allowedChars = '0123456789abcdefghijklmnopqrstuvwxyz_-';
|
||||
|
||||
string memory str = '';
|
||||
for (uint256 i = 0; i < length; i++) {
|
||||
uint8 charCode = uint8((randomFuzz >> (i * 8)) & 0xff);
|
||||
charCode = uint8(bound(charCode, 0, allowedChars.length - 1));
|
||||
if (i == 0 && (allowedChars[charCode] == '_' || allowedChars[charCode] == '-')) {
|
||||
charCode /= 2;
|
||||
}
|
||||
string memory char = string(abi.encodePacked(allowedChars[charCode]));
|
||||
str = string.concat(str, char);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
730
test/namespaces/TokenHandleRegistryTest.t.sol
Normal file
730
test/namespaces/TokenHandleRegistryTest.t.sol
Normal file
@@ -0,0 +1,730 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.13;
|
||||
|
||||
import 'test/base/BaseTest.t.sol';
|
||||
import {RegistryErrors} from 'contracts/namespaces/constants/Errors.sol';
|
||||
import {RegistryEvents} from 'contracts/namespaces/constants/Events.sol';
|
||||
import {RegistryTypes} from 'contracts/namespaces/constants/Types.sol';
|
||||
|
||||
contract TokenHandleRegistryTest is BaseTest {
|
||||
uint256 profileId;
|
||||
uint256 handleId;
|
||||
|
||||
address initialProfileHolder = makeAddr('INITIAL_PROFILE_HOLDER');
|
||||
address initialHandleHolder = makeAddr('INITIAL_HANDLE_HOLDER');
|
||||
|
||||
function setUp() public override {
|
||||
super.setUp();
|
||||
|
||||
profileId = _createProfile(initialProfileHolder);
|
||||
|
||||
vm.prank(governance);
|
||||
handleId = lensHandles.mintHandle(initialHandleHolder, 'handle');
|
||||
}
|
||||
|
||||
function testCannot_MigrationLink_IfNotHub(address otherAddress) public {
|
||||
vm.assume(otherAddress != address(hub));
|
||||
vm.assume(otherAddress != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(otherAddress != proxyAdmin);
|
||||
|
||||
vm.expectRevert(RegistryErrors.OnlyLensHub.selector);
|
||||
|
||||
vm.prank(otherAddress);
|
||||
tokenHandleRegistry.migrationLink(profileId, handleId);
|
||||
}
|
||||
|
||||
function testCannot_Link_IfNotHoldingProfile(address otherAddress) public {
|
||||
vm.assume(otherAddress != hub.ownerOf(profileId));
|
||||
vm.assume(otherAddress != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(otherAddress != proxyAdmin);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, otherAddress, handleId);
|
||||
|
||||
vm.expectRevert(RegistryErrors.NotTokenOwner.selector);
|
||||
|
||||
vm.prank(otherAddress);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
}
|
||||
|
||||
function testCannot_Link_IfNotHoldingHandle(address otherAddress) public {
|
||||
vm.assume(otherAddress != lensHandles.ownerOf(handleId));
|
||||
vm.assume(otherAddress != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(otherAddress != proxyAdmin);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, otherAddress, profileId);
|
||||
|
||||
vm.expectRevert(RegistryErrors.NotHandleOwner.selector);
|
||||
|
||||
vm.prank(otherAddress);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
}
|
||||
|
||||
function testCannot_Link_IfHandleDoesNotExist(uint256 nonexistingHandleId) public {
|
||||
vm.assume(!lensHandles.exists(nonexistingHandleId));
|
||||
|
||||
vm.expectRevert('ERC721: invalid token ID');
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
tokenHandleRegistry.link(nonexistingHandleId, profileId);
|
||||
}
|
||||
|
||||
function testCannot_Link_IfProfileDoesNotExist(uint256 nonexistingProfileId) public {
|
||||
vm.assume(!hub.exists(nonexistingProfileId));
|
||||
|
||||
vm.expectRevert(Errors.TokenDoesNotExist.selector);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
tokenHandleRegistry.link(handleId, nonexistingProfileId);
|
||||
}
|
||||
|
||||
function testCannot_Unlink_IfNotHoldingProfileOrHandle(address otherAddress) public {
|
||||
vm.assume(otherAddress != lensHandles.ownerOf(handleId));
|
||||
vm.assume(otherAddress != hub.ownerOf(profileId));
|
||||
vm.assume(otherAddress != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(otherAddress != proxyAdmin);
|
||||
|
||||
vm.prank(address(hub));
|
||||
tokenHandleRegistry.migrationLink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
vm.expectRevert(RegistryErrors.NotHandleNorTokenOwner.selector);
|
||||
|
||||
vm.prank(otherAddress);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
}
|
||||
|
||||
function testResolve() public {
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
|
||||
vm.prank(address(hub));
|
||||
tokenHandleRegistry.migrationLink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
|
||||
address newProfileHolder = makeAddr('NEW_PROFILE_HOLDER');
|
||||
address newHandleHolder = makeAddr('NEW_HANDLE_HOLDER');
|
||||
|
||||
vm.prank(address(initialProfileHolder));
|
||||
hub.transferFrom(initialProfileHolder, newProfileHolder, profileId);
|
||||
|
||||
vm.prank(address(initialHandleHolder));
|
||||
lensHandles.transferFrom(initialHandleHolder, newHandleHolder, handleId);
|
||||
|
||||
// Still resolves after both tokens were moved to new owners.
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
|
||||
vm.prank(address(newProfileHolder));
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
}
|
||||
|
||||
function testGetDefaultHandle() public {
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
|
||||
vm.prank(address(hub));
|
||||
tokenHandleRegistry.migrationLink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
address newProfileHolder = makeAddr('NEW_PROFILE_HOLDER');
|
||||
address newHandleHolder = makeAddr('NEW_HANDLE_HOLDER');
|
||||
|
||||
vm.prank(address(initialProfileHolder));
|
||||
hub.transferFrom(initialProfileHolder, newProfileHolder, profileId);
|
||||
|
||||
vm.prank(address(initialHandleHolder));
|
||||
lensHandles.transferFrom(initialHandleHolder, newHandleHolder, handleId);
|
||||
|
||||
// Still gets default handle after both tokens were moved to new owners.
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
vm.prank(address(newHandleHolder));
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
}
|
||||
|
||||
function testCannot_Resolve_IfHandleDoesNotExist(uint256 nonexistingHandleId) public {
|
||||
vm.assume(!lensHandles.exists(nonexistingHandleId));
|
||||
|
||||
vm.expectRevert(RegistryErrors.DoesNotExist.selector);
|
||||
tokenHandleRegistry.resolve(nonexistingHandleId);
|
||||
}
|
||||
|
||||
function testCannot_GetDefaultHandle_IfProfileDoesNotExist(uint256 nonexistingProfileId) public {
|
||||
vm.assume(!hub.exists(nonexistingProfileId));
|
||||
|
||||
vm.expectRevert(RegistryErrors.DoesNotExist.selector);
|
||||
tokenHandleRegistry.getDefaultHandle(nonexistingProfileId);
|
||||
}
|
||||
|
||||
function testResolve_IfBurnt() public {
|
||||
vm.prank(address(hub));
|
||||
tokenHandleRegistry.migrationLink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
vm.prank(address(initialProfileHolder));
|
||||
hub.burn(profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
|
||||
vm.expectRevert(RegistryErrors.DoesNotExist.selector);
|
||||
tokenHandleRegistry.getDefaultHandle(profileId);
|
||||
}
|
||||
|
||||
function testGetDefaultHandle_IfBurnt() public {
|
||||
vm.prank(address(hub));
|
||||
tokenHandleRegistry.migrationLink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
vm.prank(address(initialHandleHolder));
|
||||
lensHandles.burn(handleId);
|
||||
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
}
|
||||
|
||||
function testCannot_Unlink_IfNotLinked() public {
|
||||
vm.expectRevert(RegistryErrors.NotLinked.selector);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
}
|
||||
|
||||
function testFreshLink(address holder) public {
|
||||
vm.assume(holder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(holder != proxyAdmin);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, holder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, holder, profileId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleLinked(handle, token, block.timestamp);
|
||||
|
||||
vm.prank(holder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
}
|
||||
|
||||
function testLink_AfterHandleWasMoved(address firstHolder, address newHolder) public {
|
||||
vm.assume(firstHolder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(firstHolder != proxyAdmin);
|
||||
vm.assume(firstHolder != initialProfileHolder);
|
||||
vm.assume(firstHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != address(0));
|
||||
vm.assume(newHolder != proxyAdmin);
|
||||
vm.assume(newHolder != initialProfileHolder);
|
||||
vm.assume(newHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != firstHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, firstHolder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, firstHolder, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
lensHandles.transferFrom(firstHolder, newHolder, handleId);
|
||||
|
||||
uint256 newProfileId = _createProfile(newHolder);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
RegistryTypes.Token memory newToken = RegistryTypes.Token({collection: address(hub), id: newProfileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleLinked(handle, newToken, block.timestamp);
|
||||
|
||||
vm.prank(newHolder);
|
||||
tokenHandleRegistry.link(handleId, newProfileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), newProfileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(newProfileId), handleId);
|
||||
}
|
||||
|
||||
function testLink_AfterProfileWasMoved(address firstHolder, address newHolder) public {
|
||||
vm.assume(firstHolder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(firstHolder != proxyAdmin);
|
||||
vm.assume(firstHolder != initialProfileHolder);
|
||||
vm.assume(firstHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != address(0));
|
||||
vm.assume(newHolder != proxyAdmin);
|
||||
vm.assume(newHolder != initialProfileHolder);
|
||||
vm.assume(newHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != firstHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, firstHolder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, firstHolder, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
hub.transferFrom(firstHolder, newHolder, profileId);
|
||||
|
||||
uint256 newHandleId = lensHandles.mintHandle(newHolder, 'newhandle');
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
RegistryTypes.Handle memory newHandle = RegistryTypes.Handle({
|
||||
collection: address(lensHandles),
|
||||
id: newHandleId
|
||||
});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleLinked(newHandle, token, block.timestamp);
|
||||
|
||||
vm.prank(newHolder);
|
||||
tokenHandleRegistry.link(newHandleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
assertEq(tokenHandleRegistry.resolve(newHandleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), newHandleId);
|
||||
}
|
||||
|
||||
function testLink_AfterBothProfileAndHandleWereMoved(address firstHolder, address newHolder) public {
|
||||
address thirdHolder = makeAddr('THIRD_HOLDER');
|
||||
|
||||
vm.assume(firstHolder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(firstHolder != proxyAdmin);
|
||||
vm.assume(firstHolder != initialProfileHolder);
|
||||
vm.assume(firstHolder != initialHandleHolder);
|
||||
vm.assume(firstHolder != thirdHolder);
|
||||
|
||||
vm.assume(newHolder != address(0));
|
||||
vm.assume(newHolder != proxyAdmin);
|
||||
vm.assume(newHolder != initialProfileHolder);
|
||||
vm.assume(newHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != firstHolder);
|
||||
vm.assume(newHolder != thirdHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, firstHolder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, firstHolder, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
hub.transferFrom(firstHolder, newHolder, profileId);
|
||||
|
||||
uint256 newHandleId = lensHandles.mintHandle(thirdHolder, 'newhandle');
|
||||
uint256 newProfileId = _createProfile(thirdHolder);
|
||||
|
||||
vm.prank(thirdHolder);
|
||||
tokenHandleRegistry.link(newHandleId, newProfileId);
|
||||
|
||||
vm.prank(thirdHolder);
|
||||
lensHandles.transferFrom(thirdHolder, newHolder, newHandleId);
|
||||
|
||||
RegistryTypes.Handle memory oldHandle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory oldToken = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
RegistryTypes.Handle memory newHandle = RegistryTypes.Handle({
|
||||
collection: address(lensHandles),
|
||||
id: newHandleId
|
||||
});
|
||||
RegistryTypes.Token memory newToken = RegistryTypes.Token({collection: address(hub), id: newProfileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(newHandle, newToken, block.timestamp);
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(oldHandle, oldToken, block.timestamp);
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleLinked(newHandle, oldToken, block.timestamp);
|
||||
|
||||
vm.prank(newHolder);
|
||||
tokenHandleRegistry.link(newHandleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(newProfileId), 0);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(newHandleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), newHandleId);
|
||||
}
|
||||
|
||||
function testUnlink(address holder) public {
|
||||
vm.assume(holder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(holder != proxyAdmin);
|
||||
vm.assume(holder != initialProfileHolder);
|
||||
vm.assume(holder != initialHandleHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, holder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, holder, profileId);
|
||||
|
||||
vm.prank(holder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
vm.prank(holder);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
}
|
||||
|
||||
function testUnlink_ByProfileOwner_IfHandleWasMoved(address firstHolder, address newHolder) public {
|
||||
vm.assume(firstHolder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(firstHolder != proxyAdmin);
|
||||
vm.assume(firstHolder != initialProfileHolder);
|
||||
vm.assume(firstHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != address(0));
|
||||
vm.assume(newHolder != proxyAdmin);
|
||||
vm.assume(newHolder != initialProfileHolder);
|
||||
vm.assume(newHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != firstHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, firstHolder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, firstHolder, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
lensHandles.transferFrom(firstHolder, newHolder, handleId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
}
|
||||
|
||||
function testUnlink_ByNewHandleOwner_IfHandleWasMoved(address firstHolder, address newHolder) public {
|
||||
vm.assume(firstHolder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(firstHolder != proxyAdmin);
|
||||
vm.assume(firstHolder != initialProfileHolder);
|
||||
vm.assume(firstHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != address(0));
|
||||
vm.assume(newHolder != proxyAdmin);
|
||||
vm.assume(newHolder != initialProfileHolder);
|
||||
vm.assume(newHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != firstHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, firstHolder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, firstHolder, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
lensHandles.transferFrom(firstHolder, newHolder, handleId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
vm.prank(newHolder);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
}
|
||||
|
||||
function testUnlink_ByHandleOwner_IfProfileWasMoved(address firstHolder, address newHolder) public {
|
||||
vm.assume(firstHolder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(firstHolder != proxyAdmin);
|
||||
vm.assume(firstHolder != initialProfileHolder);
|
||||
vm.assume(firstHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != address(0));
|
||||
vm.assume(newHolder != proxyAdmin);
|
||||
vm.assume(newHolder != initialProfileHolder);
|
||||
vm.assume(newHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != firstHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, firstHolder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, firstHolder, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
hub.transferFrom(firstHolder, newHolder, profileId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
}
|
||||
|
||||
function testUnlink_ByNewProfileOwner_IfProfileWasMoved(address firstHolder, address newHolder) public {
|
||||
vm.assume(firstHolder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(firstHolder != proxyAdmin);
|
||||
vm.assume(firstHolder != initialProfileHolder);
|
||||
vm.assume(firstHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != address(0));
|
||||
vm.assume(newHolder != proxyAdmin);
|
||||
vm.assume(newHolder != initialProfileHolder);
|
||||
vm.assume(newHolder != initialHandleHolder);
|
||||
|
||||
vm.assume(newHolder != firstHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, firstHolder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, firstHolder, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
vm.prank(firstHolder);
|
||||
hub.transferFrom(firstHolder, newHolder, profileId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
vm.prank(newHolder);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
}
|
||||
|
||||
function testUnlink_IfHandleWasBurned(address holder) public {
|
||||
vm.assume(holder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(holder != proxyAdmin);
|
||||
vm.assume(holder != initialProfileHolder);
|
||||
vm.assume(holder != initialHandleHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, holder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, holder, profileId);
|
||||
|
||||
vm.prank(holder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
vm.prank(holder);
|
||||
lensHandles.burn(handleId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
vm.prank(holder);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
vm.expectRevert(RegistryErrors.DoesNotExist.selector);
|
||||
tokenHandleRegistry.resolve(handleId);
|
||||
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
}
|
||||
|
||||
function testUnlink_IfProfileWasBurned(address holder) public {
|
||||
vm.assume(holder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(holder != proxyAdmin);
|
||||
vm.assume(holder != initialProfileHolder);
|
||||
vm.assume(holder != initialHandleHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, holder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, holder, profileId);
|
||||
|
||||
vm.prank(holder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
vm.prank(holder);
|
||||
hub.burn(profileId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
vm.prank(holder);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
|
||||
vm.expectRevert(RegistryErrors.DoesNotExist.selector);
|
||||
tokenHandleRegistry.getDefaultHandle(profileId);
|
||||
}
|
||||
|
||||
function testUnlink_IfHandleWasBurned_CalledByNotOwner(address holder) public {
|
||||
vm.assume(holder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(holder != proxyAdmin);
|
||||
vm.assume(holder != initialProfileHolder);
|
||||
vm.assume(holder != initialHandleHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, holder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, holder, profileId);
|
||||
|
||||
vm.prank(holder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
vm.prank(holder);
|
||||
lensHandles.burn(handleId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
address otherAddress = makeAddr('OTHER_ADDRESS');
|
||||
vm.prank(otherAddress);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
vm.expectRevert(RegistryErrors.DoesNotExist.selector);
|
||||
tokenHandleRegistry.resolve(handleId);
|
||||
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
|
||||
}
|
||||
|
||||
function testUnlink_IfProfileWasBurned_CalledByNotOwner(address holder) public {
|
||||
vm.assume(holder != address(0));
|
||||
address proxyAdmin = address(uint160(uint256(vm.load(address(tokenHandleRegistry), ADMIN_SLOT))));
|
||||
vm.assume(holder != proxyAdmin);
|
||||
vm.assume(holder != initialProfileHolder);
|
||||
vm.assume(holder != initialHandleHolder);
|
||||
|
||||
vm.prank(initialHandleHolder);
|
||||
lensHandles.transferFrom(initialHandleHolder, holder, handleId);
|
||||
|
||||
vm.prank(initialProfileHolder);
|
||||
hub.transferFrom(initialProfileHolder, holder, profileId);
|
||||
|
||||
vm.prank(holder);
|
||||
tokenHandleRegistry.link(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
|
||||
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
|
||||
|
||||
vm.prank(holder);
|
||||
hub.burn(profileId);
|
||||
|
||||
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
|
||||
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
|
||||
emit RegistryEvents.HandleUnlinked(handle, token, block.timestamp);
|
||||
|
||||
address otherAddress = makeAddr('OTHER_ADDRESS');
|
||||
vm.prank(otherAddress);
|
||||
tokenHandleRegistry.unlink(handleId, profileId);
|
||||
|
||||
assertEq(tokenHandleRegistry.resolve(handleId), 0);
|
||||
|
||||
vm.expectRevert(RegistryErrors.DoesNotExist.selector);
|
||||
tokenHandleRegistry.getDefaultHandle(profileId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user