From 9f5212b55c29c5f982e35a0aaac68d372bb4fc4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Garamv=C3=B6lgyi?= Date: Tue, 24 Sep 2024 15:37:35 +0200 Subject: [PATCH] feat: add required extensions --- docs/badges.md | 15 ++++++++++- script/DeployCanvasTestBadgeContracts.sol | 2 +- src/badge/examples/EthereumYearBadge.sol | 18 ++++++++----- .../examples/ScrollBadgePermissionless.sol | 20 +++++++++------ src/badge/examples/ScrollBadgeSimple.sol | 20 ++++++--------- src/badge/examples/ScrollBadgeTokenOwner.sol | 25 +++++++++++++------ src/badge/examples/ScrollBadgeWhale.sol | 4 ++- .../extensions/IScrollBadgeUpgradeable.sol | 18 ++++++------- .../extensions/ScrollBadgeDefaultURI.sol | 6 +++-- 9 files changed, 80 insertions(+), 48 deletions(-) diff --git a/docs/badges.md b/docs/badges.md index ffe8e71..566ceb4 100644 --- a/docs/badges.md +++ b/docs/badges.md @@ -106,6 +106,7 @@ There are three main badge types of badges: Type Description Requirements +Required Extensions Examples @@ -163,6 +164,12 @@ There are three main badge types of badges: + [ScrollBadgeDefaultURI](../src/badge/extensions/ScrollBadgeDefaultURI.sol), [ScrollBadgeEligibilityCheck](../src/badge/extensions/ScrollBadgeEligibilityCheck.sol) + + + + + [`ScrollBadgePermissionless`](../src/badge/examples/ScrollBadgePermissionless.sol), [`ScrollBadgeTokenOwner`](../src/badge/examples/ScrollBadgeTokenOwner.sol), [`ScrollBadgeWhale`](../src/badge/examples/ScrollBadgeWhale.sol). @@ -214,7 +221,11 @@ There are three main badge types of badges: + + [ScrollBadgeDefaultURI](../src/badge/extensions/ScrollBadgeDefaultURI.sol), [ScrollBadgeAccessControl](../src/badge/extensions/ScrollBadgeAccessControl.sol) + + [`EthereumYearBadge`](../src/badge/examples/EthereumYearBadge.sol), [`ScrollBadgeSimple`](../src/badge/examples/ScrollBadgeSimple.sol). @@ -250,7 +261,9 @@ There are three main badge types of badges: - N/A + + + diff --git a/script/DeployCanvasTestBadgeContracts.sol b/script/DeployCanvasTestBadgeContracts.sol index e794d19..eaf39ad 100644 --- a/script/DeployCanvasTestBadgeContracts.sol +++ b/script/DeployCanvasTestBadgeContracts.sol @@ -84,7 +84,7 @@ contract DeployCanvasTestBadgeContracts is Script { tokens[0] = 0xDd7d857F570B0C211abfe05cd914A85BefEC2464; } - ScrollBadgeTokenOwner badge4 = new ScrollBadgeTokenOwner(address(resolver), tokens); + ScrollBadgeTokenOwner badge4 = new ScrollBadgeTokenOwner(address(resolver), "", tokens); // deploy Ethereum year badge EthereumYearBadge badge5 = new EthereumYearBadge(address(resolver), "https://nft.scroll.io/canvas/year/"); diff --git a/src/badge/examples/EthereumYearBadge.sol b/src/badge/examples/EthereumYearBadge.sol index ec04124..35f80c9 100644 --- a/src/badge/examples/EthereumYearBadge.sol +++ b/src/badge/examples/EthereumYearBadge.sol @@ -9,6 +9,7 @@ import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {ScrollBadge} from "../ScrollBadge.sol"; import {ScrollBadgeAccessControl} from "../extensions/ScrollBadgeAccessControl.sol"; import {ScrollBadgeCustomPayload} from "../extensions/ScrollBadgeCustomPayload.sol"; +import {ScrollBadgeDefaultURI} from "../extensions/ScrollBadgeDefaultURI.sol"; import {ScrollBadgeNoExpiry} from "../extensions/ScrollBadgeNoExpiry.sol"; import {ScrollBadgeNonRevocable} from "../extensions/ScrollBadgeNonRevocable.sol"; import {ScrollBadgeSingleton} from "../extensions/ScrollBadgeSingleton.sol"; @@ -24,6 +25,7 @@ function decodePayloadData(bytes memory data) pure returns (uint256) { contract EthereumYearBadge is ScrollBadgeAccessControl, ScrollBadgeCustomPayload, + ScrollBadgeDefaultURI, ScrollBadgeNoExpiry, ScrollBadgeNonRevocable, ScrollBadgeSingleton @@ -31,20 +33,24 @@ contract EthereumYearBadge is /// @notice The base token URI. string public baseTokenURI; - constructor(address resolver_, string memory baseTokenURI_) ScrollBadge(resolver_) { - baseTokenURI = baseTokenURI_; + constructor(address resolver_, string memory baseTokenURI_) + ScrollBadge(resolver_) + ScrollBadgeDefaultURI(baseTokenURI_) + { + // empty } /// @notice Update the base token URI. /// @param baseTokenURI_ The new base token URI. function updateBaseTokenURI(string memory baseTokenURI_) external onlyOwner { - baseTokenURI = baseTokenURI_; + defaultBadgeURI = baseTokenURI_; } /// @inheritdoc ScrollBadge function onIssueBadge(Attestation calldata attestation) internal override ( + ScrollBadge, ScrollBadgeAccessControl, ScrollBadgeCustomPayload, ScrollBadgeNoExpiry, @@ -67,13 +73,13 @@ contract EthereumYearBadge is return super.onRevokeBadge(attestation); } - /// @inheritdoc ScrollBadge - function badgeTokenURI(bytes32 uid) public view override returns (string memory) { + /// @inheritdoc ScrollBadgeDefaultURI + function getBadgeTokenURI(bytes32 uid) internal view override returns (string memory) { Attestation memory attestation = getAndValidateBadge(uid); bytes memory payload = getPayload(attestation); uint256 year = decodePayloadData(payload); - return string(abi.encodePacked(baseTokenURI, Strings.toString(year), ".json")); + return string(abi.encodePacked(defaultBadgeURI, Strings.toString(year), ".json")); } /// @inheritdoc ScrollBadgeCustomPayload diff --git a/src/badge/examples/ScrollBadgePermissionless.sol b/src/badge/examples/ScrollBadgePermissionless.sol index 7fc205c..bc4f1a9 100644 --- a/src/badge/examples/ScrollBadgePermissionless.sol +++ b/src/badge/examples/ScrollBadgePermissionless.sol @@ -5,14 +5,23 @@ pragma solidity 0.8.19; import {Attestation} from "@eas/contracts/IEAS.sol"; import {ScrollBadge} from "../ScrollBadge.sol"; -import {ScrollBadgeSelfAttest} from "../extensions/ScrollBadgeSelfAttest.sol"; +import {ScrollBadgeDefaultURI} from "../extensions/ScrollBadgeDefaultURI.sol"; import {ScrollBadgeEligibilityCheck} from "../extensions/ScrollBadgeEligibilityCheck.sol"; +import {ScrollBadgeSelfAttest} from "../extensions/ScrollBadgeSelfAttest.sol"; import {ScrollBadgeSingleton} from "../extensions/ScrollBadgeSingleton.sol"; /// @title ScrollBadgePermissionless /// @notice A simple badge that anyone can mint in a permissionless manner. -contract ScrollBadgePermissionless is ScrollBadgeSelfAttest, ScrollBadgeEligibilityCheck, ScrollBadgeSingleton { - constructor(address resolver_) ScrollBadge(resolver_) { +contract ScrollBadgePermissionless is + ScrollBadgeDefaultURI, + ScrollBadgeEligibilityCheck, + ScrollBadgeSelfAttest, + ScrollBadgeSingleton +{ + constructor(address resolver_, string memory _defaultBadgeURI) + ScrollBadge(resolver_) + ScrollBadgeDefaultURI(_defaultBadgeURI) + { // empty } @@ -35,9 +44,4 @@ contract ScrollBadgePermissionless is ScrollBadgeSelfAttest, ScrollBadgeEligibil { return super.onRevokeBadge(attestation); } - - /// @inheritdoc ScrollBadge - function badgeTokenURI(bytes32 /*uid*/ ) public pure override returns (string memory) { - return ""; - } } diff --git a/src/badge/examples/ScrollBadgeSimple.sol b/src/badge/examples/ScrollBadgeSimple.sol index fadc86f..5fbffb9 100644 --- a/src/badge/examples/ScrollBadgeSimple.sol +++ b/src/badge/examples/ScrollBadgeSimple.sol @@ -4,23 +4,22 @@ pragma solidity 0.8.19; import {Attestation} from "@eas/contracts/IEAS.sol"; +import {ScrollBadge} from "../ScrollBadge.sol"; import {ScrollBadgeAccessControl} from "../extensions/ScrollBadgeAccessControl.sol"; +import {ScrollBadgeDefaultURI} from "../extensions/ScrollBadgeDefaultURI.sol"; import {ScrollBadgeSingleton} from "../extensions/ScrollBadgeSingleton.sol"; -import {ScrollBadge} from "../ScrollBadge.sol"; /// @title ScrollBadgeSimple /// @notice A simple badge that has the same static metadata for each token. -contract ScrollBadgeSimple is ScrollBadgeAccessControl, ScrollBadgeSingleton { - string public sharedTokenURI; - - constructor(address resolver_, string memory tokenUri_) ScrollBadge(resolver_) { - sharedTokenURI = tokenUri_; +contract ScrollBadgeSimple is ScrollBadgeAccessControl, ScrollBadgeDefaultURI, ScrollBadgeSingleton { + constructor(address resolver_, string memory tokenUri_) ScrollBadge(resolver_) ScrollBadgeDefaultURI(tokenUri_) { + // empty } /// @inheritdoc ScrollBadge function onIssueBadge(Attestation calldata attestation) internal - override (ScrollBadgeAccessControl, ScrollBadgeSingleton) + override (ScrollBadge, ScrollBadgeAccessControl, ScrollBadgeSingleton) returns (bool) { return super.onIssueBadge(attestation); @@ -29,14 +28,9 @@ contract ScrollBadgeSimple is ScrollBadgeAccessControl, ScrollBadgeSingleton { /// @inheritdoc ScrollBadge function onRevokeBadge(Attestation calldata attestation) internal - override (ScrollBadgeAccessControl, ScrollBadgeSingleton) + override (ScrollBadge, ScrollBadgeAccessControl, ScrollBadgeSingleton) returns (bool) { return super.onRevokeBadge(attestation); } - - /// @inheritdoc ScrollBadge - function badgeTokenURI(bytes32 /*uid*/ ) public view override returns (string memory) { - return sharedTokenURI; - } } diff --git a/src/badge/examples/ScrollBadgeTokenOwner.sol b/src/badge/examples/ScrollBadgeTokenOwner.sol index 6bc35ef..b169152 100644 --- a/src/badge/examples/ScrollBadgeTokenOwner.sol +++ b/src/badge/examples/ScrollBadgeTokenOwner.sol @@ -7,10 +7,12 @@ import {Attestation} from "@eas/contracts/IEAS.sol"; import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import {ScrollBadge} from "../ScrollBadge.sol"; import {ScrollBadgeCustomPayload} from "../extensions/ScrollBadgeCustomPayload.sol"; +import {ScrollBadgeDefaultURI} from "../extensions/ScrollBadgeDefaultURI.sol"; +import {ScrollBadgeEligibilityCheck} from "../extensions/ScrollBadgeEligibilityCheck.sol"; import {ScrollBadgeSelfAttest} from "../extensions/ScrollBadgeSelfAttest.sol"; import {ScrollBadgeSingleton} from "../extensions/ScrollBadgeSingleton.sol"; -import {ScrollBadge} from "../ScrollBadge.sol"; import {Unauthorized} from "../../Errors.sol"; string constant SCROLL_BADGE_NFT_OWNER_SCHEMA = "address tokenAddress, uint256 tokenId"; @@ -21,12 +23,21 @@ function decodePayloadData(bytes memory data) pure returns (address, uint256) { /// @title ScrollBadgeTokenOwner /// @notice A simple badge that attests that the user owns a specific NFT. -contract ScrollBadgeTokenOwner is ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton { +contract ScrollBadgeTokenOwner is + ScrollBadgeCustomPayload, + ScrollBadgeDefaultURI, + ScrollBadgeEligibilityCheck, + ScrollBadgeSelfAttest, + ScrollBadgeSingleton +{ error IncorrectBadgeOwner(); mapping(address => bool) public isTokenAllowed; - constructor(address resolver_, address[] memory tokens_) ScrollBadge(resolver_) { + constructor(address resolver_, string memory _defaultBadgeURI, address[] memory tokens_) + ScrollBadge(resolver_) + ScrollBadgeDefaultURI(_defaultBadgeURI) + { for (uint256 i = 0; i < tokens_.length; ++i) { isTokenAllowed[tokens_[i]] = true; } @@ -35,7 +46,7 @@ contract ScrollBadgeTokenOwner is ScrollBadgeCustomPayload, ScrollBadgeSelfAttes /// @inheritdoc ScrollBadge function onIssueBadge(Attestation calldata attestation) internal - override (ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton) + override (ScrollBadge, ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton) returns (bool) { if (!super.onIssueBadge(attestation)) { @@ -60,14 +71,14 @@ contract ScrollBadgeTokenOwner is ScrollBadgeCustomPayload, ScrollBadgeSelfAttes /// @inheritdoc ScrollBadge function onRevokeBadge(Attestation calldata attestation) internal - override (ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton) + override (ScrollBadge, ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton) returns (bool) { return super.onRevokeBadge(attestation); } - /// @inheritdoc ScrollBadge - function badgeTokenURI(bytes32 uid) public view override returns (string memory) { + /// @inheritdoc ScrollBadgeDefaultURI + function getBadgeTokenURI(bytes32 uid) internal view override returns (string memory) { Attestation memory attestation = getAndValidateBadge(uid); bytes memory payload = getPayload(attestation); (address tokenAddress, uint256 tokenId) = decodePayloadData(payload); diff --git a/src/badge/examples/ScrollBadgeWhale.sol b/src/badge/examples/ScrollBadgeWhale.sol index 7c21697..8d4d669 100644 --- a/src/badge/examples/ScrollBadgeWhale.sol +++ b/src/badge/examples/ScrollBadgeWhale.sol @@ -12,7 +12,9 @@ import {Unauthorized} from "../../Errors.sol"; /// @title ScrollBadgeWhale /// @notice A badge that shows that the user had 1000 ETH or more at the time of minting. contract ScrollBadgeWhale is ScrollBadgePermissionless { - constructor(address resolver_) ScrollBadgePermissionless(resolver_) { + constructor(address resolver_, string memory _defaultBadgeURI) + ScrollBadgePermissionless(resolver_, _defaultBadgeURI) + { // empty } diff --git a/src/badge/extensions/IScrollBadgeUpgradeable.sol b/src/badge/extensions/IScrollBadgeUpgradeable.sol index f554073..2c43713 100644 --- a/src/badge/extensions/IScrollBadgeUpgradeable.sol +++ b/src/badge/extensions/IScrollBadgeUpgradeable.sol @@ -5,14 +5,14 @@ pragma solidity 0.8.19; /// @title IScrollBadgeUpgradeable /// @notice This interface defines functions to facilitate badge upgrades. interface IScrollBadgeUpgradeable { - /// @notice Checks if a badge can be upgraded. - /// @param uid The unique identifier of the badge. - /// @return True if the badge can be upgraded, false otherwise. - function canUpgrade(bytes32 uid) external view returns (bool); + /// @notice Checks if a badge can be upgraded. + /// @param uid The unique identifier of the badge. + /// @return True if the badge can be upgraded, false otherwise. + function canUpgrade(bytes32 uid) external view returns (bool); - /// @notice Upgrades a badge. - /// @param uid The unique identifier of the badge. - /// @dev Should revert with CannotUpgrade (from Errors.sol) if the badge cannot be upgraded. - /// @dev Should emit an Upgrade event (custom defined) if the upgrade is successful. - function upgrade(bytes32 uid) external; + /// @notice Upgrades a badge. + /// @param uid The unique identifier of the badge. + /// @dev Should revert with CannotUpgrade (from Errors.sol) if the badge cannot be upgraded. + /// @dev Should emit an Upgrade event (custom defined) if the upgrade is successful. + function upgrade(bytes32 uid) external; } diff --git a/src/badge/extensions/ScrollBadgeDefaultURI.sol b/src/badge/extensions/ScrollBadgeDefaultURI.sol index 636d9c8..c6a2c3b 100644 --- a/src/badge/extensions/ScrollBadgeDefaultURI.sol +++ b/src/badge/extensions/ScrollBadgeDefaultURI.sol @@ -23,7 +23,9 @@ abstract contract ScrollBadgeDefaultURI is ScrollBadge { } /// @notice Returns the token URI corresponding to a certain badge UID. - /// @param uid The badge UID. + /// @param {uid} The badge UID. /// @return The badge token URI (same format as ERC721). - function getBadgeTokenURI(bytes32 uid) internal view virtual returns (string memory); + function getBadgeTokenURI(bytes32) internal view virtual returns (string memory) { + return defaultBadgeURI; + } }