Commit e4f5535d authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #6381 from ethereum-optimism/refcell/op-nft-styling

fix(ctb): Port op-nft periphery contracts to triple slash natspec styling
parents 00e2137a 80280e1e
...@@ -3,39 +3,29 @@ pragma solidity 0.8.15; ...@@ -3,39 +3,29 @@ pragma solidity 0.8.15;
import { Semver } from "../../universal/Semver.sol"; import { Semver } from "../../universal/Semver.sol";
/** /// @title AttestationStation
* @title AttestationStation /// @author Optimism Collective
* @author Optimism Collective /// @author Gitcoin
* @author Gitcoin /// @notice Where attestations live.
* @notice Where attestations live.
*/
contract AttestationStation is Semver { contract AttestationStation is Semver {
/** /// @notice Struct representing data that is being attested.
* @notice Struct representing data that is being attested. /// @custom:field about Address for which the attestation is about.
* /// @custom:field key A bytes32 key for the attestation.
* @custom:field about Address for which the attestation is about. /// @custom:field val The attestation as arbitrary bytes.
* @custom:field key A bytes32 key for the attestation.
* @custom:field val The attestation as arbitrary bytes.
*/
struct AttestationData { struct AttestationData {
address about; address about;
bytes32 key; bytes32 key;
bytes val; bytes val;
} }
/** /// @notice Maps addresses to attestations. Creator => About => Key => Value.
* @notice Maps addresses to attestations. Creator => About => Key => Value.
*/
mapping(address => mapping(address => mapping(bytes32 => bytes))) public attestations; mapping(address => mapping(address => mapping(bytes32 => bytes))) public attestations;
/** /// @notice Emitted when Attestation is created.
* @notice Emitted when Attestation is created. /// @param creator Address that made the attestation.
* /// @param about Address attestation is about.
* @param creator Address that made the attestation. /// @param key Key of the attestation.
* @param about Address attestation is about. /// @param val Value of the attestation.
* @param key Key of the attestation.
* @param val Value of the attestation.
*/
event AttestationCreated( event AttestationCreated(
address indexed creator, address indexed creator,
address indexed about, address indexed about,
...@@ -43,18 +33,13 @@ contract AttestationStation is Semver { ...@@ -43,18 +33,13 @@ contract AttestationStation is Semver {
bytes val bytes val
); );
/** /// @custom:semver 1.1.0
* @custom:semver 1.1.0
*/
constructor() Semver(1, 1, 0) {} constructor() Semver(1, 1, 0) {}
/** /// @notice Allows anyone to create an attestation.
* @notice Allows anyone to create an attestation. /// @param _about Address that the attestation is about.
* /// @param _key A key used to namespace the attestation.
* @param _about Address that the attestation is about. /// @param _val An arbitrary value stored as part of the attestation.
* @param _key A key used to namespace the attestation.
* @param _val An arbitrary value stored as part of the attestation.
*/
function attest( function attest(
address _about, address _about,
bytes32 _key, bytes32 _key,
...@@ -65,11 +50,8 @@ contract AttestationStation is Semver { ...@@ -65,11 +50,8 @@ contract AttestationStation is Semver {
emit AttestationCreated(msg.sender, _about, _key, _val); emit AttestationCreated(msg.sender, _about, _key, _val);
} }
/** /// @notice Allows anyone to create attestations.
* @notice Allows anyone to create attestations. /// @param _attestations An array of AttestationData structs.
*
* @param _attestations An array of AttestationData structs.
*/
function attest(AttestationData[] calldata _attestations) external { function attest(AttestationData[] calldata _attestations) external {
uint256 length = _attestations.length; uint256 length = _attestations.length;
for (uint256 i = 0; i < length; ) { for (uint256 i = 0; i < length; ) {
......
...@@ -9,41 +9,29 @@ import { AttestationStation } from "./AttestationStation.sol"; ...@@ -9,41 +9,29 @@ import { AttestationStation } from "./AttestationStation.sol";
import { OptimistAllowlist } from "./OptimistAllowlist.sol"; import { OptimistAllowlist } from "./OptimistAllowlist.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
/** /// @author Optimism Collective
* @author Optimism Collective /// @author Gitcoin
* @author Gitcoin /// @title Optimist
* @title Optimist /// @notice A Soul Bound Token for real humans only(tm).
* @notice A Soul Bound Token for real humans only(tm).
*/
contract Optimist is ERC721BurnableUpgradeable, Semver { contract Optimist is ERC721BurnableUpgradeable, Semver {
/** /// @notice Attestation key used by the attestor to attest the baseURI.
* @notice Attestation key used by the attestor to attest the baseURI.
*/
bytes32 public constant BASE_URI_ATTESTATION_KEY = bytes32("optimist.base-uri"); bytes32 public constant BASE_URI_ATTESTATION_KEY = bytes32("optimist.base-uri");
/** /// @notice Attestor who attests to baseURI.
* @notice Attestor who attests to baseURI.
*/
address public immutable BASE_URI_ATTESTOR; address public immutable BASE_URI_ATTESTOR;
/** /// @notice Address of the AttestationStation contract.
* @notice Address of the AttestationStation contract.
*/
AttestationStation public immutable ATTESTATION_STATION; AttestationStation public immutable ATTESTATION_STATION;
/** /// @notice Address of the OptimistAllowlist contract.
* @notice Address of the OptimistAllowlist contract.
*/
OptimistAllowlist public immutable OPTIMIST_ALLOWLIST; OptimistAllowlist public immutable OPTIMIST_ALLOWLIST;
/** /// @custom:semver 2.0.0
* @custom:semver 2.0.0 /// @param _name Token name.
* @param _name Token name. /// @param _symbol Token symbol.
* @param _symbol Token symbol. /// @param _baseURIAttestor Address of the baseURI attestor.
* @param _baseURIAttestor Address of the baseURI attestor. /// @param _attestationStation Address of the AttestationStation contract.
* @param _attestationStation Address of the AttestationStation contract. /// @param _optimistAllowlist Address of the OptimistAllowlist contract
* @param _optimistAllowlist Address of the OptimistAllowlist contract
*/
constructor( constructor(
string memory _name, string memory _name,
string memory _symbol, string memory _symbol,
...@@ -57,109 +45,81 @@ contract Optimist is ERC721BurnableUpgradeable, Semver { ...@@ -57,109 +45,81 @@ contract Optimist is ERC721BurnableUpgradeable, Semver {
initialize(_name, _symbol); initialize(_name, _symbol);
} }
/** /// @notice Initializes the Optimist contract.
* @notice Initializes the Optimist contract. /// @param _name Token name.
* /// @param _symbol Token symbol.
* @param _name Token name.
* @param _symbol Token symbol.
*/
function initialize(string memory _name, string memory _symbol) public initializer { function initialize(string memory _name, string memory _symbol) public initializer {
__ERC721_init(_name, _symbol); __ERC721_init(_name, _symbol);
__ERC721Burnable_init(); __ERC721Burnable_init();
} }
/** /// @notice Allows an address to mint an Optimist NFT. Token ID is the uint256 representation
* @notice Allows an address to mint an Optimist NFT. Token ID is the uint256 representation /// of the recipient's address. Recipients must be permitted to mint, eventually anyone
* of the recipient's address. Recipients must be permitted to mint, eventually anyone /// will be able to mint. One token per address.
* will be able to mint. One token per address. /// @param _recipient Address of the token recipient.
*
* @param _recipient Address of the token recipient.
*/
function mint(address _recipient) public { function mint(address _recipient) public {
require(isOnAllowList(_recipient), "Optimist: address is not on allowList"); require(isOnAllowList(_recipient), "Optimist: address is not on allowList");
_safeMint(_recipient, tokenIdOfAddress(_recipient)); _safeMint(_recipient, tokenIdOfAddress(_recipient));
} }
/** /// @notice Returns the baseURI for all tokens.
* @notice Returns the baseURI for all tokens. /// @return uri_ BaseURI for all tokens.
* function baseURI() public view returns (string memory uri_) {
* @return BaseURI for all tokens. uri_ = string(
*/ abi.encodePacked(
function baseURI() public view returns (string memory) { ATTESTATION_STATION.attestations(
return BASE_URI_ATTESTOR,
string( address(this),
abi.encodePacked( bytes32("optimist.base-uri")
ATTESTATION_STATION.attestations(
BASE_URI_ATTESTOR,
address(this),
bytes32("optimist.base-uri")
)
) )
); )
);
} }
/** /// @notice Returns the token URI for a given token by ID
* @notice Returns the token URI for a given token by ID /// @param _tokenId Token ID to query.
* /// @return uri_ Token URI for the given token by ID.
* @param _tokenId Token ID to query. function tokenURI(uint256 _tokenId) public view virtual override returns (string memory uri_) {
uri_ = string(
* @return Token URI for the given token by ID. abi.encodePacked(
*/ baseURI(),
function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) { "/",
return // Properly format the token ID as a 20 byte hex string (address).
string( Strings.toHexString(_tokenId, 20),
abi.encodePacked( ".json"
baseURI(), )
"/", );
// Properly format the token ID as a 20 byte hex string (address).
Strings.toHexString(_tokenId, 20),
".json"
)
);
} }
/** /// @notice Checks OptimistAllowlist to determine whether a given address is allowed to mint
* @notice Checks OptimistAllowlist to determine whether a given address is allowed to mint /// the Optimist NFT. Since the Optimist NFT will also be used as part of the
* the Optimist NFT. Since the Optimist NFT will also be used as part of the /// Citizens House, mints are currently restricted. Eventually anyone will be able
* Citizens House, mints are currently restricted. Eventually anyone will be able /// to mint.
* to mint. /// @return allowed_ Whether or not the address is allowed to mint yet.
* function isOnAllowList(address _recipient) public view returns (bool allowed_) {
* @return Whether or not the address is allowed to mint yet. allowed_ = OPTIMIST_ALLOWLIST.isAllowedToMint(_recipient);
*/
function isOnAllowList(address _recipient) public view returns (bool) {
return OPTIMIST_ALLOWLIST.isAllowedToMint(_recipient);
} }
/** /// @notice Returns the token ID for the token owned by a given address. This is the uint256
* @notice Returns the token ID for the token owned by a given address. This is the uint256 /// representation of the given address.
* representation of the given address. /// @return Token ID for the token owned by the given address.
*
* @return Token ID for the token owned by the given address.
*/
function tokenIdOfAddress(address _owner) public pure returns (uint256) { function tokenIdOfAddress(address _owner) public pure returns (uint256) {
return uint256(uint160(_owner)); return uint256(uint160(_owner));
} }
/** /// @notice Disabled for the Optimist NFT (Soul Bound Token).
* @notice Disabled for the Optimist NFT (Soul Bound Token).
*/
function approve(address, uint256) public pure override { function approve(address, uint256) public pure override {
revert("Optimist: soul bound token"); revert("Optimist: soul bound token");
} }
/** /// @notice Disabled for the Optimist NFT (Soul Bound Token).
* @notice Disabled for the Optimist NFT (Soul Bound Token).
*/
function setApprovalForAll(address, bool) public virtual override { function setApprovalForAll(address, bool) public virtual override {
revert("Optimist: soul bound token"); revert("Optimist: soul bound token");
} }
/** /// @notice Prevents transfers of the Optimist NFT (Soul Bound Token).
* @notice Prevents transfers of the Optimist NFT (Soul Bound Token). /// @param _from Address of the token sender.
* /// @param _to Address of the token recipient.
* @param _from Address of the token sender.
* @param _to Address of the token recipient.
*/
function _beforeTokenTransfer( function _beforeTokenTransfer(
address _from, address _from,
address _to, address _to,
......
...@@ -5,54 +5,37 @@ import { Semver } from "../../universal/Semver.sol"; ...@@ -5,54 +5,37 @@ import { Semver } from "../../universal/Semver.sol";
import { AttestationStation } from "./AttestationStation.sol"; import { AttestationStation } from "./AttestationStation.sol";
import { OptimistConstants } from "./libraries/OptimistConstants.sol"; import { OptimistConstants } from "./libraries/OptimistConstants.sol";
/** /// @title OptimistAllowlist
* @title OptimistAllowlist /// @notice Source of truth for whether an address is able to mint an Optimist NFT.
* @notice Source of truth for whether an address is able to mint an Optimist NFT. /// isAllowedToMint function checks various signals to return boolean value
isAllowedToMint function checks various signals to return boolean value for whether an /// for whether an address is eligible or not.
address is eligible or not.
*/
contract OptimistAllowlist is Semver { contract OptimistAllowlist is Semver {
/** /// @notice Attestation key used by the AllowlistAttestor to manually add addresses to the
* @notice Attestation key used by the AllowlistAttestor to manually add addresses to the /// allowlist.
* allowlist.
*/
bytes32 public constant OPTIMIST_CAN_MINT_ATTESTATION_KEY = bytes32("optimist.can-mint"); bytes32 public constant OPTIMIST_CAN_MINT_ATTESTATION_KEY = bytes32("optimist.can-mint");
/** /// @notice Attestation key used by Coinbase to issue attestations for Quest participants.
* @notice Attestation key used by Coinbase to issue attestations for Quest participants.
*/
bytes32 public constant COINBASE_QUEST_ELIGIBLE_ATTESTATION_KEY = bytes32 public constant COINBASE_QUEST_ELIGIBLE_ATTESTATION_KEY =
bytes32("coinbase.quest-eligible"); bytes32("coinbase.quest-eligible");
/** /// @notice Address of the AttestationStation contract.
* @notice Address of the AttestationStation contract.
*/
AttestationStation public immutable ATTESTATION_STATION; AttestationStation public immutable ATTESTATION_STATION;
/** /// @notice Attestor that issues 'optimist.can-mint' attestations.
* @notice Attestor that issues 'optimist.can-mint' attestations.
*/
address public immutable ALLOWLIST_ATTESTOR; address public immutable ALLOWLIST_ATTESTOR;
/** /// @notice Attestor that issues 'coinbase.quest-eligible' attestations.
* @notice Attestor that issues 'coinbase.quest-eligible' attestations.
*/
address public immutable COINBASE_QUEST_ATTESTOR; address public immutable COINBASE_QUEST_ATTESTOR;
/** /// @notice Address of OptimistInviter contract that issues 'optimist.can-mint-from-invite'
* @notice Address of OptimistInviter contract that issues 'optimist.can-mint-from-invite' /// attestations.
* attestations.
*/
address public immutable OPTIMIST_INVITER; address public immutable OPTIMIST_INVITER;
/** /// @custom:semver 1.0.0
* @custom:semver 1.0.0 /// @param _attestationStation Address of the AttestationStation contract.
* /// @param _allowlistAttestor Address of the allowlist attestor.
* @param _attestationStation Address of the AttestationStation contract. /// @param _coinbaseQuestAttestor Address of the Coinbase Quest attestor.
* @param _allowlistAttestor Address of the allowlist attestor. /// @param _optimistInviter Address of the OptimistInviter contract.
* @param _coinbaseQuestAttestor Address of the Coinbase Quest attestor.
* @param _optimistInviter Address of the OptimistInviter contract.
*/
constructor( constructor(
AttestationStation _attestationStation, AttestationStation _attestationStation,
address _allowlistAttestor, address _allowlistAttestor,
...@@ -65,95 +48,83 @@ contract OptimistAllowlist is Semver { ...@@ -65,95 +48,83 @@ contract OptimistAllowlist is Semver {
OPTIMIST_INVITER = _optimistInviter; OPTIMIST_INVITER = _optimistInviter;
} }
/** /// @notice Checks whether a given address is allowed to mint the Optimist NFT yet. Since the
* @notice Checks whether a given address is allowed to mint the Optimist NFT yet. Since the /// Optimist NFT will also be used as part of the Citizens House, mints are currently
* Optimist NFT will also be used as part of the Citizens House, mints are currently /// restricted. Eventually anyone will be able to mint.
* restricted. Eventually anyone will be able to mint. /// Currently, address is allowed to mint if it satisfies any of the following:
* /// 1) Has a valid 'optimist.can-mint' attestation from the allowlist attestor.
* Currently, address is allowed to mint if it satisfies any of the following: /// 2) Has a valid 'coinbase.quest-eligible' attestation from Coinbase Quest attestor
* 1) Has a valid 'optimist.can-mint' attestation from the allowlist attestor. /// 3) Has a valid 'optimist.can-mint-from-invite' attestation from the OptimistInviter
* 2) Has a valid 'coinbase.quest-eligible' attestation from Coinbase Quest attestor /// contract.
* 3) Has a valid 'optimist.can-mint-from-invite' attestation from the OptimistInviter /// @param _claimer Address to check.
* contract. /// @return allowed_ Whether or not the address is allowed to mint yet.
* function isAllowedToMint(address _claimer) public view returns (bool allowed_) {
* @param _claimer Address to check. allowed_ =
*
* @return Whether or not the address is allowed to mint yet.
*/
function isAllowedToMint(address _claimer) public view returns (bool) {
return
_hasAttestationFromAllowlistAttestor(_claimer) || _hasAttestationFromAllowlistAttestor(_claimer) ||
_hasAttestationFromCoinbaseQuestAttestor(_claimer) || _hasAttestationFromCoinbaseQuestAttestor(_claimer) ||
_hasAttestationFromOptimistInviter(_claimer); _hasAttestationFromOptimistInviter(_claimer);
} }
/** /// @notice Checks whether an address has a valid 'optimist.can-mint' attestation from the
* @notice Checks whether an address has a valid 'optimist.can-mint' attestation from the /// allowlist attestor.
* allowlist attestor. /// @param _claimer Address to check.
* /// @return valid_ Whether or not the address has a valid attestation.
* @param _claimer Address to check. function _hasAttestationFromAllowlistAttestor(address _claimer)
* internal
* @return Whether or not the address has a valid attestation. view
*/ returns (bool valid_)
function _hasAttestationFromAllowlistAttestor(address _claimer) internal view returns (bool) { {
// Expected attestation value is bytes32("true") // Expected attestation value is bytes32("true")
return valid_ = _hasValidAttestation(
_hasValidAttestation(ALLOWLIST_ATTESTOR, _claimer, OPTIMIST_CAN_MINT_ATTESTATION_KEY); ALLOWLIST_ATTESTOR,
_claimer,
OPTIMIST_CAN_MINT_ATTESTATION_KEY
);
} }
/** /// @notice Checks whether an address has a valid attestation from the Coinbase attestor.
* @notice Checks whether an address has a valid attestation from the Coinbase attestor. /// @param _claimer Address to check.
* /// @return valid_ Whether or not the address has a valid attestation.
* @param _claimer Address to check.
*
* @return Whether or not the address has a valid attestation.
*/
function _hasAttestationFromCoinbaseQuestAttestor(address _claimer) function _hasAttestationFromCoinbaseQuestAttestor(address _claimer)
internal internal
view view
returns (bool) returns (bool valid_)
{ {
// Expected attestation value is bytes32("true") // Expected attestation value is bytes32("true")
return valid_ = _hasValidAttestation(
_hasValidAttestation( COINBASE_QUEST_ATTESTOR,
COINBASE_QUEST_ATTESTOR, _claimer,
_claimer, COINBASE_QUEST_ELIGIBLE_ATTESTATION_KEY
COINBASE_QUEST_ELIGIBLE_ATTESTATION_KEY );
);
} }
/** /// @notice Checks whether an address has a valid attestation from the OptimistInviter contract.
* @notice Checks whether an address has a valid attestation from the OptimistInviter contract. /// @param _claimer Address to check.
* /// @return valid_ Whether or not the address has a valid attestation.
* @param _claimer Address to check. function _hasAttestationFromOptimistInviter(address _claimer)
* internal
* @return Whether or not the address has a valid attestation. view
*/ returns (bool valid_)
function _hasAttestationFromOptimistInviter(address _claimer) internal view returns (bool) { {
// Expected attestation value is the inviter's address // Expected attestation value is the inviter's address
return valid_ = _hasValidAttestation(
_hasValidAttestation( OPTIMIST_INVITER,
OPTIMIST_INVITER, _claimer,
_claimer, OptimistConstants.OPTIMIST_CAN_MINT_FROM_INVITE_ATTESTATION_KEY
OptimistConstants.OPTIMIST_CAN_MINT_FROM_INVITE_ATTESTATION_KEY );
);
} }
/** /// @notice Checks whether an address has a valid truthy attestation.
* @notice Checks whether an address has a valid truthy attestation. /// Any attestation val other than bytes32("") is considered truthy.
* Any attestation val other than bytes32("") is considered truthy. /// @param _creator Address that made the attestation.
* /// @param _about Address attestation is about.
* @param _creator Address that made the attestation. /// @param _key Key of the attestation.
* @param _about Address attestation is about. /// @return valid_ Whether or not the address has a valid truthy attestation.
* @param _key Key of the attestation.
*
* @return Whether or not the address has a valid truthy attestation.
*/
function _hasValidAttestation( function _hasValidAttestation(
address _creator, address _creator,
address _about, address _about,
bytes32 _key bytes32 _key
) internal view returns (bool) { ) internal view returns (bool valid_) {
return ATTESTATION_STATION.attestations(_creator, _about, _key).length > 0; valid_ = ATTESTATION_STATION.attestations(_creator, _about, _key).length > 0;
} }
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
/** /// @title OptimistConstants
* @title OptimistConstants /// @notice Library for storing Optimist related constants that are shared in multiple contracts.
* @notice Library for storing Optimist related constants that are shared in multiple contracts.
*/
library OptimistConstants { library OptimistConstants {
/** /// @notice Attestation key issued by OptimistInviter allowing the attested account to mint.
* @notice Attestation key issued by OptimistInviter allowing the attested account to mint.
*/
bytes32 internal constant OPTIMIST_CAN_MINT_FROM_INVITE_ATTESTATION_KEY = bytes32 internal constant OPTIMIST_CAN_MINT_FROM_INVITE_ATTESTATION_KEY =
bytes32("optimist.can-mint-from-invite"); bytes32("optimist.can-mint-from-invite");
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment