Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add required extensions #54

Merged
merged 1 commit into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion docs/badges.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ There are three main badge types of badges:
<th style="text-align: center">Type</th>
<th style="text-align: center">Description</th>
<th style="text-align: center">Requirements</th>
<th style="text-align: center">Required Extensions</th>
<th style="text-align: center">Examples</th>
</tr>

Expand Down Expand Up @@ -163,6 +164,12 @@ There are three main badge types of badges:

<td>

[ScrollBadgeDefaultURI](../src/badge/extensions/ScrollBadgeDefaultURI.sol), [ScrollBadgeEligibilityCheck](../src/badge/extensions/ScrollBadgeEligibilityCheck.sol)

</td>

<td>

[`ScrollBadgePermissionless`](../src/badge/examples/ScrollBadgePermissionless.sol), [`ScrollBadgeTokenOwner`](../src/badge/examples/ScrollBadgeTokenOwner.sol), [`ScrollBadgeWhale`](../src/badge/examples/ScrollBadgeWhale.sol).

</td>
Expand Down Expand Up @@ -214,7 +221,11 @@ There are three main badge types of badges:
</li>
</ul>
</td>
<td>

[ScrollBadgeDefaultURI](../src/badge/extensions/ScrollBadgeDefaultURI.sol), [ScrollBadgeAccessControl](../src/badge/extensions/ScrollBadgeAccessControl.sol)

</td>
<td>

[`EthereumYearBadge`](../src/badge/examples/EthereumYearBadge.sol), [`ScrollBadgeSimple`](../src/badge/examples/ScrollBadgeSimple.sol).
Expand Down Expand Up @@ -250,7 +261,9 @@ There are three main badge types of badges:
</td>

<td>
N/A
</td>

<td>
</td>
</tr>

Expand Down
2 changes: 1 addition & 1 deletion script/DeployCanvasTestBadgeContracts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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/");
Expand Down
18 changes: 12 additions & 6 deletions src/badge/examples/EthereumYearBadge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -24,27 +25,32 @@ function decodePayloadData(bytes memory data) pure returns (uint256) {
contract EthereumYearBadge is
ScrollBadgeAccessControl,
ScrollBadgeCustomPayload,
ScrollBadgeDefaultURI,
ScrollBadgeNoExpiry,
ScrollBadgeNonRevocable,
ScrollBadgeSingleton
{
/// @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,
Expand All @@ -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
Expand Down
20 changes: 12 additions & 8 deletions src/badge/examples/ScrollBadgePermissionless.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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 "";
}
}
20 changes: 7 additions & 13 deletions src/badge/examples/ScrollBadgeSimple.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
}
25 changes: 18 additions & 7 deletions src/badge/examples/ScrollBadgeTokenOwner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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;
}
Expand All @@ -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)) {
Expand All @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion src/badge/examples/ScrollBadgeWhale.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
18 changes: 9 additions & 9 deletions src/badge/extensions/IScrollBadgeUpgradeable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
6 changes: 4 additions & 2 deletions src/badge/extensions/ScrollBadgeDefaultURI.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Loading