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;
+ }
}