-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathScrollBadgePowerRank.sol
139 lines (115 loc) · 4.57 KB
/
ScrollBadgePowerRank.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {Attestation} from "@eas/contracts/IEAS.sol";
import {Base64} from "@openzeppelin/contracts/utils/Base64.sol";
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 {ScrollBadgeNoExpiry} from "../extensions/ScrollBadgeNoExpiry.sol";
import {ScrollBadgeNonRevocable} from "../extensions/ScrollBadgeNonRevocable.sol";
import {ScrollBadgeSingleton} from "../extensions/ScrollBadgeSingleton.sol";
import {IScrollBadgeUpgradeable} from "../extensions/IScrollBadgeUpgradeable.sol";
import {Unauthorized, CannotUpgrade} from "../../Errors.sol";
string constant SCROLL_BADGE_POWER_RANK_SCHEMA = "uint256 firstTxTimestamp";
function decodePayloadData(bytes memory data) pure returns (uint256) {
return abi.decode(data, (uint256));
}
/// @title ScrollBadgePowerRank
/// @notice A badge that represents the user's power rank.
contract ScrollBadgePowerRank is
ScrollBadgeAccessControl,
ScrollBadgeCustomPayload,
ScrollBadgeNoExpiry,
ScrollBadgeNonRevocable,
ScrollBadgeSingleton,
IScrollBadgeUpgradeable
{
event Upgrade(uint256 oldRank, uint256 newRank);
// badge UID => current rank
mapping(bytes32 => uint256) public badgeRank;
constructor(address resolver_) ScrollBadge(resolver_) {
// empty
}
/// @inheritdoc ScrollBadge
function onIssueBadge(
Attestation calldata attestation
)
internal
override(
ScrollBadgeAccessControl,
ScrollBadgeCustomPayload,
ScrollBadgeNoExpiry,
ScrollBadgeNonRevocable,
ScrollBadgeSingleton
)
returns (bool)
{
if (!super.onIssueBadge(attestation)) {
return false;
}
bytes memory payload = getPayload(attestation);
uint256 firstTxTimestamp = decodePayloadData(payload);
badgeRank[attestation.uid] = timestampToRank(firstTxTimestamp);
return true;
}
/// @inheritdoc ScrollBadge
function onRevokeBadge(
Attestation calldata attestation
)
internal
override(
ScrollBadge,
ScrollBadgeAccessControl,
ScrollBadgeCustomPayload,
ScrollBadgeNoExpiry,
ScrollBadgeSingleton
)
returns (bool)
{
return super.onRevokeBadge(attestation);
}
/// @inheritdoc ScrollBadge
function badgeTokenURI(bytes32 uid) public view override returns (string memory) {
uint256 rank = badgeRank[uid];
string memory name = string(abi.encodePacked("Scroll Power Rank #", Strings.toString(rank)));
string memory description = "Scroll Power Rank Badge";
string memory image = ""; // IPFS, HTTP, or data URL
string memory tokenUriJson = Base64.encode(
abi.encodePacked('{"name":"', name, '", "description":"', description, '", "image": "', image, '"}')
);
return string(abi.encodePacked("data:application/json;base64,", tokenUriJson));
}
/// @inheritdoc ScrollBadgeCustomPayload
function getSchema() public pure override returns (string memory) {
return SCROLL_BADGE_POWER_RANK_SCHEMA;
}
/// @inheritdoc IScrollBadgeUpgradeable
function canUpgrade(bytes32 uid) external view returns (bool) {
Attestation memory badge = getAndValidateBadge(uid);
bytes memory payload = getPayload(badge);
uint256 firstTxTimestamp = decodePayloadData(payload);
uint256 newRank = timestampToRank(firstTxTimestamp);
uint256 oldRank = badgeRank[uid];
return newRank > oldRank;
}
/// @inheritdoc IScrollBadgeUpgradeable
function upgrade(bytes32 uid) external {
Attestation memory badge = getAndValidateBadge(uid);
if (msg.sender != badge.recipient) {
revert Unauthorized();
}
bytes memory payload = getPayload(badge);
uint256 firstTxTimestamp = decodePayloadData(payload);
uint256 newRank = timestampToRank(firstTxTimestamp);
uint256 oldRank = badgeRank[uid];
if (newRank <= oldRank) {
revert CannotUpgrade(uid);
}
badgeRank[uid] = newRank;
emit Upgrade(oldRank, newRank);
}
function timestampToRank(uint256 timestamp) public view returns (uint256) {
return (block.timestamp - timestamp) / 2_592_000 + 1; // level up every 30 days
}
}