From ec185c2eae3d5febbd7d464e44fcc9b07c11189f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Garamv=C3=B6lgyi?= Date: Wed, 15 Jan 2025 11:08:06 +0100 Subject: [PATCH] feat: remove ProfileRegistry mint --- src/interfaces/IProfileRegistry.sol | 6 -- src/profile/ProfileRegistry.sol | 101 ++++++++++++++++------------ test/Profile.t.sol | 8 +-- test/ProfileRegistry.t.sol | 8 +-- test/SCRHoldingBadge.t.sol | 8 +-- 5 files changed, 69 insertions(+), 62 deletions(-) diff --git a/src/interfaces/IProfileRegistry.sol b/src/interfaces/IProfileRegistry.sol index 4de0674..02fc42d 100644 --- a/src/interfaces/IProfileRegistry.sol +++ b/src/interfaces/IProfileRegistry.sol @@ -72,12 +72,6 @@ interface IProfileRegistry { * */ - /// @notice Mint a profile for caller with given username. - /// @param username The username of the profile. - /// @param referral The referral data. - /// @return The address of minted profile. - function mint(string calldata username, bytes calldata referral) external payable returns (address); - /// @notice Register an username. /// @param username The username to register. function registerUsername(string memory username) external; diff --git a/src/profile/ProfileRegistry.sol b/src/profile/ProfileRegistry.sol index 7c3c08f..1e94bc4 100644 --- a/src/profile/ProfileRegistry.sol +++ b/src/profile/ProfileRegistry.sol @@ -45,9 +45,6 @@ contract ProfileRegistry is OwnableUpgradeable, EIP712Upgradeable, IBeacon, IPro /// @notice The codehash for `ClonableBeaconProxy` contract. bytes32 public constant cloneableProxyHash = keccak256(type(ClonableBeaconProxy).creationCode); - // solhint-disable-next-line var-name-mixedcase - bytes32 private constant _REFERRAL_TYPEHASH = keccak256("Referral(address referrer,address owner,uint256 deadline)"); - /** * * Structs * @@ -151,46 +148,6 @@ contract ProfileRegistry is OwnableUpgradeable, EIP712Upgradeable, IBeacon, IPro * */ - /// @inheritdoc IProfileRegistry - function mint(string calldata username, bytes memory referral) external payable override returns (address) { - address receiver = treasury; - address referrer; - uint256 mintFee = MINT_FEE; - if (referral.length > 0) { - uint256 deadline; - bytes memory signature; - (receiver, deadline, signature) = abi.decode(referral, (address, uint256, bytes)); - if (deadline < block.timestamp) revert ExpiredSignature(); - if (!isProfileMinted[getProfile(receiver)]) { - revert InvalidReferrer(); - } - - bytes32 structHash = keccak256(abi.encode(_REFERRAL_TYPEHASH, receiver, _msgSender(), deadline)); - bytes32 hash = _hashTypedDataV4(structHash); - address recovered = ECDSAUpgradeable.recover(hash, signature); - if (signer != recovered) revert InvalidSignature(); - - // half mint fee and fee goes to referral - mintFee = MINT_FEE / 2; - referrer = receiver; - } - if (msg.value != mintFee) revert MsgValueMismatchWithMintFee(); - Address.sendValue(payable(receiver), mintFee); - - if (isProfileMinted[getProfile(_msgSender())]) { - revert ProfileAlreadyMinted(); - } - - if (referrer != address(0)) { - ReferrerData memory cached = referrerData[referrer]; - cached.referred += 1; - cached.earned += uint128(mintFee); - referrerData[referrer] = cached; - } - - return _mintProfile(_msgSender(), username, referrer); - } - /// @inheritdoc IProfileRegistry function registerUsername(string memory username) external override onlyProfile { _validateUsername(username); @@ -260,7 +217,7 @@ contract ProfileRegistry is OwnableUpgradeable, EIP712Upgradeable, IBeacon, IPro /// @dev Internal function to mint a profile with given account address and username. /// @param account The address of user to mint profile. /// @param username The username of the profile. - function _mintProfile(address account, string calldata username, address referrer) private returns (address) { + function _mintProfile(address account, string calldata username, address referrer) internal returns (address) { // deployment will fail and this function will revert if contract `salt` is not unique bytes32 salt = keccak256(abi.encode(account)); address profile = address(new ClonableBeaconProxy{salt: salt}()); @@ -322,3 +279,59 @@ contract ProfileRegistry is OwnableUpgradeable, EIP712Upgradeable, IBeacon, IPro } } } + +contract ProfileRegistryMintable is ProfileRegistry { + /** + * + * Constants * + * + */ + + // solhint-disable-next-line var-name-mixedcase + bytes32 private constant _REFERRAL_TYPEHASH = keccak256("Referral(address referrer,address owner,uint256 deadline)"); + + /** + * + * Public Mutating Functions * + * + */ + + function mint(string calldata username, bytes memory referral) external payable returns (address) { + address receiver = treasury; + address referrer; + uint256 mintFee = MINT_FEE; + if (referral.length > 0) { + uint256 deadline; + bytes memory signature; + (receiver, deadline, signature) = abi.decode(referral, (address, uint256, bytes)); + if (deadline < block.timestamp) revert ExpiredSignature(); + if (!isProfileMinted[getProfile(receiver)]) { + revert InvalidReferrer(); + } + + bytes32 structHash = keccak256(abi.encode(_REFERRAL_TYPEHASH, receiver, _msgSender(), deadline)); + bytes32 hash = _hashTypedDataV4(structHash); + address recovered = ECDSAUpgradeable.recover(hash, signature); + if (signer != recovered) revert InvalidSignature(); + + // half mint fee and fee goes to referral + mintFee = MINT_FEE / 2; + referrer = receiver; + } + if (msg.value != mintFee) revert MsgValueMismatchWithMintFee(); + Address.sendValue(payable(receiver), mintFee); + + if (isProfileMinted[getProfile(_msgSender())]) { + revert ProfileAlreadyMinted(); + } + + if (referrer != address(0)) { + ReferrerData memory cached = referrerData[referrer]; + cached.referred += 1; + cached.earned += uint128(mintFee); + referrerData[referrer] = cached; + } + + return _mintProfile(_msgSender(), username, referrer); + } +} diff --git a/test/Profile.t.sol b/test/Profile.t.sol index 21808e5..7f4fad3 100644 --- a/test/Profile.t.sol +++ b/test/Profile.t.sol @@ -25,7 +25,7 @@ import { import {EmptyContract} from "../src/misc/EmptyContract.sol"; import {Profile} from "../src/profile/Profile.sol"; -import {ProfileRegistry} from "../src/profile/ProfileRegistry.sol"; +import {ProfileRegistryMintable} from "../src/profile/ProfileRegistry.sol"; import {ScrollBadge} from "../src/badge/ScrollBadge.sol"; import {ScrollBadgeResolver} from "../src/resolver/ScrollBadgeResolver.sol"; @@ -75,7 +75,7 @@ contract ProfileRegistryTest is Test { ScrollBadge private badge; Profile private profileImpl; - ProfileRegistry private profileRegistry; + ProfileRegistryMintable private profileRegistry; Profile private profile; receive() external payable {} @@ -95,10 +95,10 @@ contract ProfileRegistryTest is Test { resolver.toggleBadge(address(badge), true); profileImpl = new Profile(address(resolver)); - ProfileRegistry profileRegistryImpl = new ProfileRegistry(); + ProfileRegistryMintable profileRegistryImpl = new ProfileRegistryMintable(); vm.prank(PROXY_ADMIN_ADDRESS); ITransparentUpgradeableProxy(profileRegistryProxy).upgradeTo(address(profileRegistryImpl)); - profileRegistry = ProfileRegistry(profileRegistryProxy); + profileRegistry = ProfileRegistryMintable(profileRegistryProxy); profileRegistry.initialize(TREASURY_ADDRESS, TREASURY_ADDRESS, address(profileImpl)); profile = Profile(profileRegistry.mint{value: 0.001 ether}("xxxxx", new bytes(0))); } diff --git a/test/ProfileRegistry.t.sol b/test/ProfileRegistry.t.sol index b59c584..e47c392 100644 --- a/test/ProfileRegistry.t.sol +++ b/test/ProfileRegistry.t.sol @@ -15,7 +15,7 @@ import { import {EmptyContract} from "../src/misc/EmptyContract.sol"; import {Profile} from "../src/profile/Profile.sol"; -import {ProfileRegistry} from "../src/profile/ProfileRegistry.sol"; +import {ProfileRegistryMintable} from "../src/profile/ProfileRegistry.sol"; import {ScrollBadgeResolver} from "../src/resolver/ScrollBadgeResolver.sol"; contract ProfileRegistryTest is Test { @@ -40,7 +40,7 @@ contract ProfileRegistryTest is Test { VmSafe.Wallet private signer; Profile private profileImpl; - ProfileRegistry private profileRegistry; + ProfileRegistryMintable private profileRegistry; receive() external payable {} @@ -58,10 +58,10 @@ contract ProfileRegistryTest is Test { signer = vm.createWallet(10_001); profileImpl = new Profile(address(resolver)); - ProfileRegistry profileRegistryImpl = new ProfileRegistry(); + ProfileRegistryMintable profileRegistryImpl = new ProfileRegistryMintable(); vm.prank(PROXY_ADMIN_ADDRESS); ITransparentUpgradeableProxy(profileRegistryProxy).upgradeTo(address(profileRegistryImpl)); - profileRegistry = ProfileRegistry(profileRegistryProxy); + profileRegistry = ProfileRegistryMintable(profileRegistryProxy); profileRegistry.initialize(TREASURY_ADDRESS, signer.addr, address(profileImpl)); vm.warp(1_000_000); } diff --git a/test/SCRHoldingBadge.t.sol b/test/SCRHoldingBadge.t.sol index 2c31227..ed8e4f6 100644 --- a/test/SCRHoldingBadge.t.sol +++ b/test/SCRHoldingBadge.t.sol @@ -16,7 +16,7 @@ import {ITransparentUpgradeableProxy, TransparentUpgradeableProxy} from "@openze import {EmptyContract} from "../src/misc/EmptyContract.sol"; import {Profile} from "../src/profile/Profile.sol"; -import {ProfileRegistry} from "../src/profile/ProfileRegistry.sol"; +import {ProfileRegistryMintable} from "../src/profile/ProfileRegistry.sol"; import {ScrollBadge} from "../src/badge/ScrollBadge.sol"; import {ScrollBadgeResolver} from "../src/resolver/ScrollBadgeResolver.sol"; import {SCRHoldingBadge} from "../src/badge/examples/SCRHoldingBadge.sol"; @@ -42,7 +42,7 @@ contract SCRHoldingBadgeTest is Test { Token private token; Profile private profileImpl; - ProfileRegistry private profileRegistry; + ProfileRegistryMintable private profileRegistry; Profile private profile; receive() external payable {} @@ -64,10 +64,10 @@ contract SCRHoldingBadgeTest is Test { resolver.updateSelfAttestedBadge(0, address(badge)); profileImpl = new Profile(address(resolver)); - ProfileRegistry profileRegistryImpl = new ProfileRegistry(); + ProfileRegistryMintable profileRegistryImpl = new ProfileRegistryMintable(); vm.prank(PROXY_ADMIN_ADDRESS); ITransparentUpgradeableProxy(profileRegistryProxy).upgradeTo(address(profileRegistryImpl)); - profileRegistry = ProfileRegistry(profileRegistryProxy); + profileRegistry = ProfileRegistryMintable(profileRegistryProxy); profileRegistry.initialize(TREASURY_ADDRESS, TREASURY_ADDRESS, address(profileImpl)); profile = Profile(profileRegistry.mint{value: 0.001 ether}("xxxxx", new bytes(0))); }