Merge pull request #143 from lens-protocol/test/token-handle-registry

test: Improve test coverage of TokenHandleRegistry
This commit is contained in:
Alan
2023-10-26 00:05:49 +01:00
committed by GitHub
2 changed files with 321 additions and 1 deletions

View File

@@ -4,6 +4,7 @@ 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';
@@ -444,4 +445,18 @@ contract BaseTest is TestSetup {
function _encodeUsingEip712Rules(bytes memory bytesValue) internal pure returns (bytes32) {
return keccak256(bytesValue);
}
function _transferHandle(address to, uint256 handleId) internal {
address initialHandleHolder = lensHandles.ownerOf(handleId);
_effectivelyDisableGuardian(address(lensHandles), initialHandleHolder);
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);
}
}

View File

@@ -2,6 +2,8 @@
pragma solidity ^0.8.13;
import 'test/base/BaseTest.t.sol';
import {ERC1271WalletMock} from '@openzeppelin/contracts/mocks/ERC1271WalletMock.sol';
import {MetaTxNegatives} from 'test/MetaTxNegatives.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';
@@ -13,7 +15,7 @@ contract TokenHandleRegistryTest is BaseTest {
address initialProfileHolder = makeAddr('INITIAL_PROFILE_HOLDER');
address initialHandleHolder = makeAddr('INITIAL_HANDLE_HOLDER');
function setUp() public override {
function setUp() public virtual override {
super.setUp();
profileId = _createProfile(initialProfileHolder);
@@ -64,6 +66,24 @@ contract TokenHandleRegistryTest is BaseTest {
tokenHandleRegistry.link(handleId, profileId);
}
function testCannot_Link_IfNotOwnerOrDelegatedExecutor(address otherAddress) public {
address holder = makeAddr('holder');
vm.assume(otherAddress != holder);
vm.assume(otherAddress != address(0));
vm.assume(!_isLensHubProxyAdmin(otherAddress));
_transferHandle(holder, handleId);
_transferProfile(holder, profileId);
_effectivelyDisableProfileGuardian(holder);
vm.expectRevert(RegistryErrors.DoesNotHavePermissions.selector);
vm.prank(otherAddress);
tokenHandleRegistry.link(handleId, profileId);
}
function testCannot_Link_IfHandleDoesNotExist(uint256 nonexistingHandleId) public {
vm.assume(!lensHandles.exists(nonexistingHandleId));
@@ -792,3 +812,288 @@ contract TokenHandleRegistryTest is BaseTest {
tokenHandleRegistry.getDefaultHandle(profileId);
}
}
abstract contract TokenHandleRegistryMetaTxBaseTest is BaseTest, MetaTxNegatives {
uint256 internal constant NO_DEADLINE = type(uint256).max;
uint256 profileId;
uint256 handleId;
uint256 constant holderPk = 0x401DE8;
address holder;
function setUp() public override (BaseTest, MetaTxNegatives) {
BaseTest.setUp();
MetaTxNegatives.setUp();
holder = vm.addr(holderPk);
profileId = _createProfile(holder);
vm.prank(governance);
handleId = lensHandles.mintHandle(holder, 'handle');
domainSeparator = keccak256(
abi.encode(
Typehash.EIP712_DOMAIN,
keccak256('TokenHandleRegistry'),
keccak256(bytes('1')),
block.chainid,
address(tokenHandleRegistry)
)
);
}
function _incrementNonce(uint8 increment) internal override {
vm.prank(vm.addr(_getDefaultMetaTxSignerPk()));
tokenHandleRegistry.incrementNonce(increment);
}
function _getDefaultMetaTxSignerPk() internal override returns (uint256) {
return holderPk;
}
function _getMetaTxNonce(address signer) internal override returns (uint256) {
return tokenHandleRegistry.nonces(signer);
}
function _getDomainName() internal override returns (bytes memory) {
return bytes('TokenHandleRegistry');
}
function _getRevisionNumber() internal override returns (bytes memory) {
return bytes('1');
}
function _getVerifyingContract() internal override returns (address) {
return address(tokenHandleRegistry);
}
}
contract TokenHandleRegistryLinkMetaTxTest is TokenHandleRegistryMetaTxBaseTest {
function testFreshLinkWithSig(address relayer) public {
vm.assume(relayer != holder);
vm.assume(relayer != address(0));
vm.assume(!_isLensHubProxyAdmin(relayer));
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
Types.EIP712Signature memory sig = _getLinkSigStruct(holder, holderPk, _getMetaTxNonce(holder), NO_DEADLINE);
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
emit RegistryEvents.HandleLinked(handle, token, holder, block.timestamp);
vm.prank(relayer);
tokenHandleRegistry.linkWithSig(handleId, profileId, sig);
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
}
function testFreshLinkWithSig_WithERC1271Wallet() public {
uint256 walletOwnerPk = 0x77a1137077438;
address walletOwner = vm.addr(walletOwnerPk);
address relayer = makeAddr('relayer');
address wallet = address(new ERC1271WalletMock(walletOwner));
_transferHandle(wallet, handleId);
_transferProfile(wallet, profileId);
RegistryTypes.Handle memory handle = RegistryTypes.Handle({collection: address(lensHandles), id: handleId});
RegistryTypes.Token memory token = RegistryTypes.Token({collection: address(hub), id: profileId});
Types.EIP712Signature memory sig = _getLinkSigStruct(wallet, walletOwnerPk, _getMetaTxNonce(wallet), NO_DEADLINE);
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
emit RegistryEvents.HandleLinked(handle, token, wallet, block.timestamp);
vm.prank(address(relayer));
tokenHandleRegistry.linkWithSig(handleId, profileId, sig);
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
}
function testCannot_LinkWithSig_IfWalletValidationFails() public {
uint256 otherPk = 0x07438;
address walletOwner = makeAddr('walletOwner');
address relayer = makeAddr('relayer');
address wallet = address(new ERC1271WalletMock(walletOwner));
_transferHandle(wallet, handleId);
_transferProfile(wallet, profileId);
Types.EIP712Signature memory sig = _getLinkSigStruct(wallet, otherPk, _getMetaTxNonce(wallet), NO_DEADLINE);
vm.expectRevert(Errors.SignatureInvalid.selector);
vm.prank(relayer);
tokenHandleRegistry.linkWithSig(handleId, profileId, sig);
}
function _executeMetaTx(uint256 pKey, uint256 nonce, uint256 deadline) internal override {
tokenHandleRegistry.linkWithSig({
handleId: handleId,
profileId: profileId,
signature: _getLinkSigStruct({
signer: vm.addr(_getDefaultMetaTxSignerPk()),
pKey: pKey,
nonce: nonce,
deadline: deadline
})
});
}
function _getLinkSigStruct(
address signer,
uint256 pKey,
uint256 nonce,
uint256 deadline
) internal view returns (Types.EIP712Signature memory) {
return _getSigStruct({
signer: signer,
pKey: pKey,
deadline: deadline,
digest: _calculateDigest(
keccak256(
abi.encode(
NamespacesTypehash.LINK,
handleId,
profileId,
signer,
nonce,
deadline
)
)
)
});
}
}
contract TokenHandleRegistryUnlinkMetaTxTest is TokenHandleRegistryMetaTxBaseTest {
function testUnlinkWithSig(address relayer) public {
vm.assume(relayer != holder);
vm.assume(relayer != address(0));
vm.assume(!_isLensHubProxyAdmin(relayer));
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});
Types.EIP712Signature memory sig = _getUnlinkSigStruct(holder, holderPk, _getMetaTxNonce(holder), NO_DEADLINE);
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
emit RegistryEvents.HandleUnlinked(handle, token, holder, block.timestamp);
vm.prank(relayer);
tokenHandleRegistry.unlinkWithSig(handleId, profileId, sig);
assertEq(tokenHandleRegistry.resolve(handleId), 0);
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
}
function testUnlinkWithSig_WithERC1271Wallet() public {
uint256 walletOwnerPk = 0x77a1137077438;
address walletOwner = vm.addr(walletOwnerPk);
address relayer = makeAddr('relayer');
address wallet = address(new ERC1271WalletMock(walletOwner));
_transferHandle(wallet, handleId);
_transferProfile(wallet, profileId);
vm.prank(wallet);
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});
Types.EIP712Signature memory sig = _getUnlinkSigStruct(wallet, walletOwnerPk, _getMetaTxNonce(wallet), NO_DEADLINE);
vm.expectEmit(true, true, true, true, address(tokenHandleRegistry));
emit RegistryEvents.HandleUnlinked(handle, token, wallet, block.timestamp);
vm.prank(relayer);
tokenHandleRegistry.unlinkWithSig(handleId, profileId, sig);
assertEq(tokenHandleRegistry.resolve(handleId), 0);
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), 0);
}
function testCannot_UnlinkWithSig_IfWalletValidationFails() public {
uint256 otherPk = 0x07438;
address walletOwner = makeAddr('walletOwner');
address relayer = makeAddr('relayer');
address wallet = address(new ERC1271WalletMock(walletOwner));
_transferHandle(wallet, handleId);
_transferProfile(wallet, profileId);
vm.prank(wallet);
tokenHandleRegistry.link(handleId, profileId);
assertEq(tokenHandleRegistry.resolve(handleId), profileId);
assertEq(tokenHandleRegistry.getDefaultHandle(profileId), handleId);
Types.EIP712Signature memory sig = _getUnlinkSigStruct(wallet, otherPk, _getMetaTxNonce(wallet), NO_DEADLINE);
vm.expectRevert(Errors.SignatureInvalid.selector);
vm.prank(relayer);
tokenHandleRegistry.unlinkWithSig(handleId, profileId, sig);
}
function _executeMetaTx(uint256 signerPk, uint256 nonce, uint256 deadline) internal override {
tokenHandleRegistry.unlinkWithSig({
handleId: handleId,
profileId: profileId,
signature: _getUnlinkSigStruct({
signer: vm.addr(_getDefaultMetaTxSignerPk()),
pKey: signerPk,
nonce: nonce,
deadline: deadline
})
});
}
function _getUnlinkSigStruct(
address signer,
uint256 pKey,
uint256 nonce,
uint256 deadline
) internal view returns (Types.EIP712Signature memory) {
return _getSigStruct({
signer: signer,
pKey: pKey,
deadline: deadline,
digest: _calculateDigest(
keccak256(
abi.encode(
NamespacesTypehash.UNLINK,
handleId,
profileId,
signer,
nonce,
deadline
)
)
)
});
}
}