Skip to content

Commit

Permalink
Merge pull request #7 from citydaoproject/issue1
Browse files Browse the repository at this point in the history
Merge initial issue1 changes into main
  • Loading branch information
Slyracoon23 authored May 6, 2022
2 parents 5a79588 + 8d2df5d commit a54bc2e
Show file tree
Hide file tree
Showing 30 changed files with 1,222 additions and 36 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ jobs:
- name: Build
run: npm run build
- name: Test
run: npm run test -- --ci --maxWorkers=1 --reporters=default
run: npm test
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# CHANGEME
# Parcel Contracts

## Setup

Expand Down
199 changes: 199 additions & 0 deletions contracts/ParcelNFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.9;

import '@gnus.ai/contracts-upgradeable-diamond/access/AccessControlUpgradeable.sol';
import '@gnus.ai/contracts-upgradeable-diamond/proxy/utils/UUPSUpgradeable.sol';
import '@gnus.ai/contracts-upgradeable-diamond/security/PausableUpgradeable.sol';
import '@gnus.ai/contracts-upgradeable-diamond/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol';
import '@gnus.ai/contracts-upgradeable-diamond/token/ERC721/extensions/ERC721RoyaltyUpgradeable.sol';
import './ParcelNFTStorage.sol';
import './common/RoyaltyEventSupport.sol';
import './Roles.sol';

contract ParcelNFT is
UUPSUpgradeable,
ERC721URIStorageUpgradeable,
RoyaltyEventSupport,
ERC721RoyaltyUpgradeable,
AccessControlUpgradeable,
PausableUpgradeable
{
struct InitParams {
string name;
string symbol;
address superAdmin;
}

function initialize(InitParams memory initParams) public initializer {
__ERC721_init(initParams.name, initParams.symbol);
__ERC721URIStorage_init_unchained();
__ERC2981_init_unchained();
__ERC721Royalty_init_unchained();
__AccessControl_init_unchained();
__Pausable_init_unchained();

if (initParams.superAdmin == address(0)) {
initParams.superAdmin = _msgSender();
}
_setupRole(Roles.SUPER_ADMIN, initParams.superAdmin);
}

// todo: temporary until minting is supported
function mint(uint256 tokenId) external onlyRole(Roles.PARCEL_MANAGER) {
_safeMint(_msgSender(), tokenId);
}

function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(AccessControlUpgradeable, ERC721RoyaltyUpgradeable, ERC721Upgradeable, ERC2981Upgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}

/**
* @notice Sets `baseURI` as the base URI for all tokens. Used when explicit tokenURI not set.
*/
function setBaseURI(string calldata baseURI) external onlyRole(Roles.PARCEL_MANAGER) {
ParcelNFTStorage.setBaseURI(baseURI);
}

function _baseURI() internal view virtual override returns (string memory) {
return ParcelNFTStorage.baseURI();
}

/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId)
public
view
virtual
override(ERC721URIStorageUpgradeable, ERC721Upgradeable)
returns (string memory)
{
return super.tokenURI(tokenId);
}

/**
* @notice Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function setTokenURI(uint256 tokenId, string memory _tokenURI) external onlyRole(Roles.PARCEL_MANAGER) {
_setTokenURI(tokenId, _tokenURI);
}

/**
* @notice Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function setDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyRole(Roles.PARCEL_MANAGER) {
_setDefaultRoyalty(receiver, feeNumerator);
}

/**
* @inheritdoc ERC2981Upgradeable
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator)
internal
virtual
override(RoyaltyEventSupport, ERC2981Upgradeable)
{
super._setDefaultRoyalty(receiver, feeNumerator);
}

/**
* @notice Removes default royalty information.
*/
function deleteDefaultRoyalty() external onlyRole(Roles.PARCEL_MANAGER) {
_deleteDefaultRoyalty();
}

/**
* @inheritdoc ERC2981Upgradeable
*/
function _deleteDefaultRoyalty() internal virtual override(RoyaltyEventSupport, ERC2981Upgradeable) {
super._deleteDefaultRoyalty();
}

/**
* @notice Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `tokenId` must be already minted.
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) external onlyRole(Roles.PARCEL_MANAGER) {
_setTokenRoyalty(tokenId, receiver, feeNumerator);
}

/**
* @inheritdoc ERC2981Upgradeable
*/
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual override(RoyaltyEventSupport, ERC2981Upgradeable) {
super._setTokenRoyalty(tokenId, receiver, feeNumerator);
}

/**
* @notice Resets royalty information for the token id back to the global default.
*/
function resetTokenRoyalty(uint256 tokenId) external onlyRole(Roles.PARCEL_MANAGER) {
_resetTokenRoyalty(tokenId);
}

/**
* @inheritdoc ERC2981Upgradeable
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual override(RoyaltyEventSupport, ERC2981Upgradeable) {
super._resetTokenRoyalty(tokenId);
}

/**
* @notice Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function pause() external onlyRole(Roles.PAUSER) {
_pause();
}

/**
* @notice Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function unpause() external onlyRole(Roles.PAUSER) {
_unpause();
}

function _burn(uint256 tokenId) internal virtual override(ERC721URIStorageUpgradeable, ERC721RoyaltyUpgradeable) {
super._burn(tokenId);
}

// solhint-disable-next-line no-empty-blocks
function _authorizeUpgrade(address newImplementation) internal virtual override onlyRole(Roles.UPGRADER) {}
}
29 changes: 29 additions & 0 deletions contracts/ParcelNFTStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.9;

library ParcelNFTStorage {
struct Layout {
// storage for base URI
string baseURI;
}

bytes32 internal constant STORAGE_SLOT = keccak256('citydao.contracts.storage.ParcelNFT');

//noinspection NoReturn
function layout() internal pure returns (Layout storage _layout) {
bytes32 slot = STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
_layout.slot := slot
}
}

function baseURI() internal view returns (string memory) {
return layout().baseURI;
}

function setBaseURI(string memory _baseURI) internal {
layout().baseURI = _baseURI;
}
}
10 changes: 10 additions & 0 deletions contracts/Roles.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.9;

library Roles {
bytes32 public constant SUPER_ADMIN = 0x00;
bytes32 public constant PARCEL_MANAGER = keccak256('citydao.ParcelManager');
bytes32 public constant PAUSER = keccak256('citydao.Pauser');
bytes32 public constant UPGRADER = keccak256('citydao.Upgrader');
}
53 changes: 53 additions & 0 deletions contracts/common/RoyaltyEventSupport.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity ^0.8.9;

import '@gnus.ai/contracts-upgradeable-diamond/token/common/ERC2981Upgradeable.sol';

abstract contract RoyaltyEventSupport is ERC2981Upgradeable {
/**
* @dev Emitted when the default royalty is updated.
*/
event DefaultRoyaltyChanged(address indexed receiver, uint96 indexed feeNumerator);

/**
* @dev Emitted when a token royalty is updated.
*/
event TokenRoyaltyChanged(uint256 indexed tokenId, address indexed receiver, uint96 indexed feeNumerator);

/**
* @inheritdoc ERC2981Upgradeable
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual override {
super._setDefaultRoyalty(receiver, feeNumerator);
emit DefaultRoyaltyChanged(receiver, feeNumerator);
}

/**
* @inheritdoc ERC2981Upgradeable
*/
function _deleteDefaultRoyalty() internal virtual override {
super._deleteDefaultRoyalty();
emit DefaultRoyaltyChanged(address(0), 0);
}

/**
* @inheritdoc ERC2981Upgradeable
*/
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual override {
super._setTokenRoyalty(tokenId, receiver, feeNumerator);
emit TokenRoyaltyChanged(tokenId, receiver, feeNumerator);
}

/**
* @inheritdoc ERC2981Upgradeable
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual override {
super._resetTokenRoyalty(tokenId);
emit TokenRoyaltyChanged(tokenId, address(0), 0);
}
}
26 changes: 26 additions & 0 deletions contracts/test/ERC165IdCalc.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity ^0.8.9;

import '@gnus.ai/contracts-upgradeable-diamond/access/IAccessControlUpgradeable.sol';
import '@gnus.ai/contracts-upgradeable-diamond/interfaces/IERC2981Upgradeable.sol';
import '@gnus.ai/contracts-upgradeable-diamond/token/ERC721/IERC721Upgradeable.sol';
import '@gnus.ai/contracts-upgradeable-diamond/token/ERC721/extensions/IERC721MetadataUpgradeable.sol';

library ERC165IdCalc {
function calcAccessControlInterfaceId() external pure returns (bytes4) {
return type(IAccessControlUpgradeable).interfaceId;
}

function calcERC2981InterfaceId() external pure returns (bytes4) {
return type(IERC2981Upgradeable).interfaceId;
}

function calcERC721InterfaceId() external pure returns (bytes4) {
return type(IERC721Upgradeable).interfaceId;
}

function calcERC721MetadataInterfaceId() external pure returns (bytes4) {
return type(IERC721MetadataUpgradeable).interfaceId;
}
}
1 change: 1 addition & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const hardhatConfig: HardhatUserConfig = {
},

typechain: {
externalArtifacts: ['node_modules/@openzeppelin/contracts/build/contracts/ERC1967Proxy.json'],
outDir: 'types/contracts',
target: 'ethers-v5',
},
Expand Down
Loading

0 comments on commit a54bc2e

Please sign in to comment.