Skip to content

Commit 09ee6b6

Browse files
authored
feat: add required extensions (#54)
1 parent 9cc1a8b commit 09ee6b6

9 files changed

+80
-48
lines changed

docs/badges.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ There are three main badge types of badges:
106106
<th style="text-align: center">Type</th>
107107
<th style="text-align: center">Description</th>
108108
<th style="text-align: center">Requirements</th>
109+
<th style="text-align: center">Required Extensions</th>
109110
<th style="text-align: center">Examples</th>
110111
</tr>
111112

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

164165
<td>
165166

167+
[ScrollBadgeDefaultURI](../src/badge/extensions/ScrollBadgeDefaultURI.sol), [ScrollBadgeEligibilityCheck](../src/badge/extensions/ScrollBadgeEligibilityCheck.sol)
168+
169+
</td>
170+
171+
<td>
172+
166173
[`ScrollBadgePermissionless`](../src/badge/examples/ScrollBadgePermissionless.sol), [`ScrollBadgeTokenOwner`](../src/badge/examples/ScrollBadgeTokenOwner.sol), [`ScrollBadgeWhale`](../src/badge/examples/ScrollBadgeWhale.sol).
167174

168175
</td>
@@ -214,7 +221,11 @@ There are three main badge types of badges:
214221
</li>
215222
</ul>
216223
</td>
224+
<td>
217225

226+
[ScrollBadgeDefaultURI](../src/badge/extensions/ScrollBadgeDefaultURI.sol), [ScrollBadgeAccessControl](../src/badge/extensions/ScrollBadgeAccessControl.sol)
227+
228+
</td>
218229
<td>
219230

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

252263
<td>
253-
N/A
264+
</td>
265+
266+
<td>
254267
</td>
255268
</tr>
256269

script/DeployCanvasTestBadgeContracts.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ contract DeployCanvasTestBadgeContracts is Script {
8484
tokens[0] = 0xDd7d857F570B0C211abfe05cd914A85BefEC2464;
8585
}
8686

87-
ScrollBadgeTokenOwner badge4 = new ScrollBadgeTokenOwner(address(resolver), tokens);
87+
ScrollBadgeTokenOwner badge4 = new ScrollBadgeTokenOwner(address(resolver), "", tokens);
8888

8989
// deploy Ethereum year badge
9090
EthereumYearBadge badge5 = new EthereumYearBadge(address(resolver), "https://nft.scroll.io/canvas/year/");

src/badge/examples/EthereumYearBadge.sol

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
99
import {ScrollBadge} from "../ScrollBadge.sol";
1010
import {ScrollBadgeAccessControl} from "../extensions/ScrollBadgeAccessControl.sol";
1111
import {ScrollBadgeCustomPayload} from "../extensions/ScrollBadgeCustomPayload.sol";
12+
import {ScrollBadgeDefaultURI} from "../extensions/ScrollBadgeDefaultURI.sol";
1213
import {ScrollBadgeNoExpiry} from "../extensions/ScrollBadgeNoExpiry.sol";
1314
import {ScrollBadgeNonRevocable} from "../extensions/ScrollBadgeNonRevocable.sol";
1415
import {ScrollBadgeSingleton} from "../extensions/ScrollBadgeSingleton.sol";
@@ -24,27 +25,32 @@ function decodePayloadData(bytes memory data) pure returns (uint256) {
2425
contract EthereumYearBadge is
2526
ScrollBadgeAccessControl,
2627
ScrollBadgeCustomPayload,
28+
ScrollBadgeDefaultURI,
2729
ScrollBadgeNoExpiry,
2830
ScrollBadgeNonRevocable,
2931
ScrollBadgeSingleton
3032
{
3133
/// @notice The base token URI.
3234
string public baseTokenURI;
3335

34-
constructor(address resolver_, string memory baseTokenURI_) ScrollBadge(resolver_) {
35-
baseTokenURI = baseTokenURI_;
36+
constructor(address resolver_, string memory baseTokenURI_)
37+
ScrollBadge(resolver_)
38+
ScrollBadgeDefaultURI(baseTokenURI_)
39+
{
40+
// empty
3641
}
3742

3843
/// @notice Update the base token URI.
3944
/// @param baseTokenURI_ The new base token URI.
4045
function updateBaseTokenURI(string memory baseTokenURI_) external onlyOwner {
41-
baseTokenURI = baseTokenURI_;
46+
defaultBadgeURI = baseTokenURI_;
4247
}
4348

4449
/// @inheritdoc ScrollBadge
4550
function onIssueBadge(Attestation calldata attestation)
4651
internal
4752
override (
53+
ScrollBadge,
4854
ScrollBadgeAccessControl,
4955
ScrollBadgeCustomPayload,
5056
ScrollBadgeNoExpiry,
@@ -67,13 +73,13 @@ contract EthereumYearBadge is
6773
return super.onRevokeBadge(attestation);
6874
}
6975

70-
/// @inheritdoc ScrollBadge
71-
function badgeTokenURI(bytes32 uid) public view override returns (string memory) {
76+
/// @inheritdoc ScrollBadgeDefaultURI
77+
function getBadgeTokenURI(bytes32 uid) internal view override returns (string memory) {
7278
Attestation memory attestation = getAndValidateBadge(uid);
7379
bytes memory payload = getPayload(attestation);
7480
uint256 year = decodePayloadData(payload);
7581

76-
return string(abi.encodePacked(baseTokenURI, Strings.toString(year), ".json"));
82+
return string(abi.encodePacked(defaultBadgeURI, Strings.toString(year), ".json"));
7783
}
7884

7985
/// @inheritdoc ScrollBadgeCustomPayload

src/badge/examples/ScrollBadgePermissionless.sol

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,23 @@ pragma solidity 0.8.19;
55
import {Attestation} from "@eas/contracts/IEAS.sol";
66

77
import {ScrollBadge} from "../ScrollBadge.sol";
8-
import {ScrollBadgeSelfAttest} from "../extensions/ScrollBadgeSelfAttest.sol";
8+
import {ScrollBadgeDefaultURI} from "../extensions/ScrollBadgeDefaultURI.sol";
99
import {ScrollBadgeEligibilityCheck} from "../extensions/ScrollBadgeEligibilityCheck.sol";
10+
import {ScrollBadgeSelfAttest} from "../extensions/ScrollBadgeSelfAttest.sol";
1011
import {ScrollBadgeSingleton} from "../extensions/ScrollBadgeSingleton.sol";
1112

1213
/// @title ScrollBadgePermissionless
1314
/// @notice A simple badge that anyone can mint in a permissionless manner.
14-
contract ScrollBadgePermissionless is ScrollBadgeSelfAttest, ScrollBadgeEligibilityCheck, ScrollBadgeSingleton {
15-
constructor(address resolver_) ScrollBadge(resolver_) {
15+
contract ScrollBadgePermissionless is
16+
ScrollBadgeDefaultURI,
17+
ScrollBadgeEligibilityCheck,
18+
ScrollBadgeSelfAttest,
19+
ScrollBadgeSingleton
20+
{
21+
constructor(address resolver_, string memory _defaultBadgeURI)
22+
ScrollBadge(resolver_)
23+
ScrollBadgeDefaultURI(_defaultBadgeURI)
24+
{
1625
// empty
1726
}
1827

@@ -35,9 +44,4 @@ contract ScrollBadgePermissionless is ScrollBadgeSelfAttest, ScrollBadgeEligibil
3544
{
3645
return super.onRevokeBadge(attestation);
3746
}
38-
39-
/// @inheritdoc ScrollBadge
40-
function badgeTokenURI(bytes32 /*uid*/ ) public pure override returns (string memory) {
41-
return "";
42-
}
4347
}

src/badge/examples/ScrollBadgeSimple.sol

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,22 @@ pragma solidity 0.8.19;
44

55
import {Attestation} from "@eas/contracts/IEAS.sol";
66

7+
import {ScrollBadge} from "../ScrollBadge.sol";
78
import {ScrollBadgeAccessControl} from "../extensions/ScrollBadgeAccessControl.sol";
9+
import {ScrollBadgeDefaultURI} from "../extensions/ScrollBadgeDefaultURI.sol";
810
import {ScrollBadgeSingleton} from "../extensions/ScrollBadgeSingleton.sol";
9-
import {ScrollBadge} from "../ScrollBadge.sol";
1011

1112
/// @title ScrollBadgeSimple
1213
/// @notice A simple badge that has the same static metadata for each token.
13-
contract ScrollBadgeSimple is ScrollBadgeAccessControl, ScrollBadgeSingleton {
14-
string public sharedTokenURI;
15-
16-
constructor(address resolver_, string memory tokenUri_) ScrollBadge(resolver_) {
17-
sharedTokenURI = tokenUri_;
14+
contract ScrollBadgeSimple is ScrollBadgeAccessControl, ScrollBadgeDefaultURI, ScrollBadgeSingleton {
15+
constructor(address resolver_, string memory tokenUri_) ScrollBadge(resolver_) ScrollBadgeDefaultURI(tokenUri_) {
16+
// empty
1817
}
1918

2019
/// @inheritdoc ScrollBadge
2120
function onIssueBadge(Attestation calldata attestation)
2221
internal
23-
override (ScrollBadgeAccessControl, ScrollBadgeSingleton)
22+
override (ScrollBadge, ScrollBadgeAccessControl, ScrollBadgeSingleton)
2423
returns (bool)
2524
{
2625
return super.onIssueBadge(attestation);
@@ -29,14 +28,9 @@ contract ScrollBadgeSimple is ScrollBadgeAccessControl, ScrollBadgeSingleton {
2928
/// @inheritdoc ScrollBadge
3029
function onRevokeBadge(Attestation calldata attestation)
3130
internal
32-
override (ScrollBadgeAccessControl, ScrollBadgeSingleton)
31+
override (ScrollBadge, ScrollBadgeAccessControl, ScrollBadgeSingleton)
3332
returns (bool)
3433
{
3534
return super.onRevokeBadge(attestation);
3635
}
37-
38-
/// @inheritdoc ScrollBadge
39-
function badgeTokenURI(bytes32 /*uid*/ ) public view override returns (string memory) {
40-
return sharedTokenURI;
41-
}
4236
}

src/badge/examples/ScrollBadgeTokenOwner.sol

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import {Attestation} from "@eas/contracts/IEAS.sol";
77
import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
88
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
99

10+
import {ScrollBadge} from "../ScrollBadge.sol";
1011
import {ScrollBadgeCustomPayload} from "../extensions/ScrollBadgeCustomPayload.sol";
12+
import {ScrollBadgeDefaultURI} from "../extensions/ScrollBadgeDefaultURI.sol";
13+
import {ScrollBadgeEligibilityCheck} from "../extensions/ScrollBadgeEligibilityCheck.sol";
1114
import {ScrollBadgeSelfAttest} from "../extensions/ScrollBadgeSelfAttest.sol";
1215
import {ScrollBadgeSingleton} from "../extensions/ScrollBadgeSingleton.sol";
13-
import {ScrollBadge} from "../ScrollBadge.sol";
1416
import {Unauthorized} from "../../Errors.sol";
1517

1618
string constant SCROLL_BADGE_NFT_OWNER_SCHEMA = "address tokenAddress, uint256 tokenId";
@@ -21,12 +23,21 @@ function decodePayloadData(bytes memory data) pure returns (address, uint256) {
2123

2224
/// @title ScrollBadgeTokenOwner
2325
/// @notice A simple badge that attests that the user owns a specific NFT.
24-
contract ScrollBadgeTokenOwner is ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton {
26+
contract ScrollBadgeTokenOwner is
27+
ScrollBadgeCustomPayload,
28+
ScrollBadgeDefaultURI,
29+
ScrollBadgeEligibilityCheck,
30+
ScrollBadgeSelfAttest,
31+
ScrollBadgeSingleton
32+
{
2533
error IncorrectBadgeOwner();
2634

2735
mapping(address => bool) public isTokenAllowed;
2836

29-
constructor(address resolver_, address[] memory tokens_) ScrollBadge(resolver_) {
37+
constructor(address resolver_, string memory _defaultBadgeURI, address[] memory tokens_)
38+
ScrollBadge(resolver_)
39+
ScrollBadgeDefaultURI(_defaultBadgeURI)
40+
{
3041
for (uint256 i = 0; i < tokens_.length; ++i) {
3142
isTokenAllowed[tokens_[i]] = true;
3243
}
@@ -35,7 +46,7 @@ contract ScrollBadgeTokenOwner is ScrollBadgeCustomPayload, ScrollBadgeSelfAttes
3546
/// @inheritdoc ScrollBadge
3647
function onIssueBadge(Attestation calldata attestation)
3748
internal
38-
override (ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton)
49+
override (ScrollBadge, ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton)
3950
returns (bool)
4051
{
4152
if (!super.onIssueBadge(attestation)) {
@@ -60,14 +71,14 @@ contract ScrollBadgeTokenOwner is ScrollBadgeCustomPayload, ScrollBadgeSelfAttes
6071
/// @inheritdoc ScrollBadge
6172
function onRevokeBadge(Attestation calldata attestation)
6273
internal
63-
override (ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton)
74+
override (ScrollBadge, ScrollBadgeCustomPayload, ScrollBadgeSelfAttest, ScrollBadgeSingleton)
6475
returns (bool)
6576
{
6677
return super.onRevokeBadge(attestation);
6778
}
6879

69-
/// @inheritdoc ScrollBadge
70-
function badgeTokenURI(bytes32 uid) public view override returns (string memory) {
80+
/// @inheritdoc ScrollBadgeDefaultURI
81+
function getBadgeTokenURI(bytes32 uid) internal view override returns (string memory) {
7182
Attestation memory attestation = getAndValidateBadge(uid);
7283
bytes memory payload = getPayload(attestation);
7384
(address tokenAddress, uint256 tokenId) = decodePayloadData(payload);

src/badge/examples/ScrollBadgeWhale.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import {Unauthorized} from "../../Errors.sol";
1212
/// @title ScrollBadgeWhale
1313
/// @notice A badge that shows that the user had 1000 ETH or more at the time of minting.
1414
contract ScrollBadgeWhale is ScrollBadgePermissionless {
15-
constructor(address resolver_) ScrollBadgePermissionless(resolver_) {
15+
constructor(address resolver_, string memory _defaultBadgeURI)
16+
ScrollBadgePermissionless(resolver_, _defaultBadgeURI)
17+
{
1618
// empty
1719
}
1820

src/badge/extensions/IScrollBadgeUpgradeable.sol

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ pragma solidity 0.8.19;
55
/// @title IScrollBadgeUpgradeable
66
/// @notice This interface defines functions to facilitate badge upgrades.
77
interface IScrollBadgeUpgradeable {
8-
/// @notice Checks if a badge can be upgraded.
9-
/// @param uid The unique identifier of the badge.
10-
/// @return True if the badge can be upgraded, false otherwise.
11-
function canUpgrade(bytes32 uid) external view returns (bool);
8+
/// @notice Checks if a badge can be upgraded.
9+
/// @param uid The unique identifier of the badge.
10+
/// @return True if the badge can be upgraded, false otherwise.
11+
function canUpgrade(bytes32 uid) external view returns (bool);
1212

13-
/// @notice Upgrades a badge.
14-
/// @param uid The unique identifier of the badge.
15-
/// @dev Should revert with CannotUpgrade (from Errors.sol) if the badge cannot be upgraded.
16-
/// @dev Should emit an Upgrade event (custom defined) if the upgrade is successful.
17-
function upgrade(bytes32 uid) external;
13+
/// @notice Upgrades a badge.
14+
/// @param uid The unique identifier of the badge.
15+
/// @dev Should revert with CannotUpgrade (from Errors.sol) if the badge cannot be upgraded.
16+
/// @dev Should emit an Upgrade event (custom defined) if the upgrade is successful.
17+
function upgrade(bytes32 uid) external;
1818
}

src/badge/extensions/ScrollBadgeDefaultURI.sol

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ abstract contract ScrollBadgeDefaultURI is ScrollBadge {
2323
}
2424

2525
/// @notice Returns the token URI corresponding to a certain badge UID.
26-
/// @param uid The badge UID.
26+
/// @param {uid} The badge UID.
2727
/// @return The badge token URI (same format as ERC721).
28-
function getBadgeTokenURI(bytes32 uid) internal view virtual returns (string memory);
28+
function getBadgeTokenURI(bytes32) internal view virtual returns (string memory) {
29+
return defaultBadgeURI;
30+
}
2931
}

0 commit comments

Comments
 (0)