diff --git a/README.md b/README.md index 7776f89..192d9e3 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,10 @@ See [badges](./docs/badges.md) for details. This repo contains some useful [extensions](src/badge/extensions): - `ScrollBadgeAccessControl` restricts who can create and revoke this badge. - `ScrollBadgeCustomPayload` adds custom payload support to the badge. +- `ScrollBadgeDefaultURI` sets a default badge token URI. +- `ScrollBadgeEligibilityCheck` adds a standard on-chain eligibility check interface. - `ScrollBadgeNoExpiry` disables expiration for the badge. - `ScrollBadgeNonRevocable` disables revocation for the badge. -- `ScrollBadgeEligibilityCheck` adds a standard on-chain eligibility check interface. - `ScrollBadgeSBT` attaches an SBT token to each badge attestation. - `ScrollBadgeSelfAttest` ensures that only the recipient of the badge can create the badge. - `ScrollBadgeSingleton` ensures that each user can only have at most one of the badge. diff --git a/src/badge/examples/ScrollBadgeLevels.sol b/src/badge/examples/ScrollBadgeLevels.sol index b77e84b..1906c12 100644 --- a/src/badge/examples/ScrollBadgeLevels.sol +++ b/src/badge/examples/ScrollBadgeLevels.sol @@ -9,6 +9,7 @@ import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {ScrollBadgeAccessControl} from "../extensions/ScrollBadgeAccessControl.sol"; import {ScrollBadgeCustomPayload} from "../extensions/ScrollBadgeCustomPayload.sol"; +import {ScrollBadgeDefaultURI} from "../extensions/ScrollBadgeDefaultURI.sol"; import {ScrollBadge} from "../ScrollBadge.sol"; string constant SCROLL_BADGE_LEVELS_SCHEMA = "uint8 scrollLevel"; @@ -19,15 +20,18 @@ function decodePayloadData(bytes memory data) pure returns (uint8) { /// @title ScrollBadgeLevels /// @notice A simple badge that represents the user's level. -contract ScrollBadgeLevels is ScrollBadgeAccessControl, ScrollBadgeCustomPayload { - constructor(address resolver_) ScrollBadge(resolver_) { +contract ScrollBadgeLevels is ScrollBadgeAccessControl, ScrollBadgeCustomPayload, ScrollBadgeDefaultURI { + constructor(address resolver_, string memory _defaultBadgeURI) + ScrollBadge(resolver_) + ScrollBadgeDefaultURI(_defaultBadgeURI) + { // empty } /// @inheritdoc ScrollBadge function onIssueBadge(Attestation calldata attestation) internal - override (ScrollBadgeAccessControl, ScrollBadgeCustomPayload) + override (ScrollBadge, ScrollBadgeAccessControl, ScrollBadgeCustomPayload) returns (bool) { return super.onIssueBadge(attestation); @@ -36,14 +40,14 @@ contract ScrollBadgeLevels is ScrollBadgeAccessControl, ScrollBadgeCustomPayload /// @inheritdoc ScrollBadge function onRevokeBadge(Attestation calldata attestation) internal - override (ScrollBadgeAccessControl, ScrollBadgeCustomPayload) + override (ScrollBadge, ScrollBadgeAccessControl, ScrollBadgeCustomPayload) 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) { uint8 level = getCurrentLevel(uid); string memory name = string(abi.encode("Scroll Level #", Strings.toString(level))); string memory description = "Scroll Level Badge"; diff --git a/src/badge/extensions/ScrollBadgeDefaultURI.sol b/src/badge/extensions/ScrollBadgeDefaultURI.sol new file mode 100644 index 0000000..636d9c8 --- /dev/null +++ b/src/badge/extensions/ScrollBadgeDefaultURI.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.19; + +import {ScrollBadge} from "../ScrollBadge.sol"; + +/// @title ScrollBadgeDefaultURI +/// @notice This contract sets a default badge URI. +abstract contract ScrollBadgeDefaultURI is ScrollBadge { + string public defaultBadgeURI; + + constructor(string memory _defaultBadgeURI) { + defaultBadgeURI = _defaultBadgeURI; + } + + /// @inheritdoc ScrollBadge + function badgeTokenURI(bytes32 uid) public view override returns (string memory) { + if (uid == bytes32(0)) { + return defaultBadgeURI; + } + + return getBadgeTokenURI(uid); + } + + /// @notice Returns the token URI corresponding to a certain 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); +} diff --git a/test/ScrollBadgeDefaultURI.t.sol b/test/ScrollBadgeDefaultURI.t.sol new file mode 100644 index 0000000..83a6233 --- /dev/null +++ b/test/ScrollBadgeDefaultURI.t.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.19; + +import {ScrollBadgeTestBase} from "./ScrollBadgeTestBase.sol"; + +import {ScrollBadge} from "../src/badge/ScrollBadge.sol"; +import {ScrollBadgeDefaultURI} from "../src/badge/extensions/ScrollBadgeDefaultURI.sol"; + +contract TestContract is ScrollBadgeDefaultURI { + constructor(address resolver_) ScrollBadge(resolver_) ScrollBadgeDefaultURI("default") {} + + function getBadgeTokenURI(bytes32 /*uid*/ ) internal pure override returns (string memory) { + return "not-default"; + } +} + +contract ScrollBadgeDefaultURITest is ScrollBadgeTestBase { + TestContract internal badge; + + function setUp() public virtual override { + super.setUp(); + + badge = new TestContract(address(resolver)); + resolver.toggleBadge(address(badge), true); + } + + function testGetBadgeTokenURI() external { + bytes32 uid = _attest(address(badge), "", alice); + + string memory uri = badge.badgeTokenURI(uid); + assertEq(uri, "not-default"); + + uri = badge.badgeTokenURI(bytes32(0)); + assertEq(uri, "default"); + } +}