Skip to content

Commit

Permalink
feat: add required extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
Thegaram committed Sep 24, 2024
1 parent 9cc1a8b commit 9f5212b
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 48 deletions.
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;
}
}

0 comments on commit 9f5212b

Please sign in to comment.