feat: erc interface and split out access points to single module (#151)

* wip: compilant version of interface

* refactor: split out access point to single module

* test: fix mint call on hardhat tests

* fix: remove auto approval from NewMint event
This commit is contained in:
Felipe Mendes 2023-03-13 11:07:40 -03:00 committed by GitHub
parent fbee0945fd
commit df6fbea5c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 906 additions and 791 deletions

View File

@ -0,0 +1,212 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import {FleekStrings} from "./util/FleekStrings.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
error AccessPointNotExistent();
error AccessPointAlreadyExists();
error AccessPointScoreCannotBeLower();
error MustBeAccessPointOwner();
error InvalidTokenIdForAccessPoint();
error AccessPointCreationStatusAlreadySet();
abstract contract FleekAccessPoints is Initializable {
using FleekStrings for FleekAccessPoints.AccessPoint;
event NewAccessPoint(string apName, uint256 indexed tokenId, address indexed owner);
event RemoveAccessPoint(string apName, uint256 indexed tokenId, address indexed owner);
event ChangeAccessPointScore(string apName, uint256 indexed tokenId, uint256 score, address indexed triggeredBy);
event ChangeAccessPointNameVerify(
string apName,
uint256 tokenId,
bool indexed verified,
address indexed triggeredBy
);
event ChangeAccessPointContentVerify(
string apName,
uint256 tokenId,
bool indexed verified,
address indexed triggeredBy
);
event ChangeAccessPointCreationStatus(
string apName,
uint256 tokenId,
AccessPointCreationStatus status,
address indexed triggeredBy
);
/**
* Creation status enums for access points
*/
enum AccessPointCreationStatus {
DRAFT,
APPROVED,
REJECTED,
REMOVED
}
/**
* The stored data for each AccessPoint.
*/
struct AccessPoint {
uint256 tokenId;
uint256 score;
bool contentVerified;
bool nameVerified;
address owner;
AccessPointCreationStatus status;
}
mapping(string => AccessPoint) private _accessPoints;
mapping(uint256 => bool) private _autoApproval;
/**
* @dev Checks if the AccessPoint exists.
*/
modifier requireAP(string memory apName) {
if (_accessPoints[apName].owner == address(0)) revert AccessPointNotExistent();
_;
}
/**
* @dev A view function to gether information about an AccessPoint.
* It returns a JSON string representing the AccessPoint information.
*/
function getAccessPointJSON(string memory apName) public view requireAP(apName) returns (string memory) {
AccessPoint storage _ap = _accessPoints[apName];
return _ap.toString();
}
/**
* @dev A view function to check if a AccessPoint is verified.
*/
function isAccessPointNameVerified(string memory apName) public view requireAP(apName) returns (bool) {
return _accessPoints[apName].nameVerified;
}
/**
* @dev Increases the score of a AccessPoint registry.
*/
function increaseAccessPointScore(string memory apName) public requireAP(apName) {
_accessPoints[apName].score++;
emit ChangeAccessPointScore(apName, _accessPoints[apName].tokenId, _accessPoints[apName].score, msg.sender);
}
/**
* @dev Decreases the score of a AccessPoint registry if is greater than 0.
*/
function decreaseAccessPointScore(string memory apName) public requireAP(apName) {
if (_accessPoints[apName].score == 0) revert AccessPointScoreCannotBeLower();
_accessPoints[apName].score--;
emit ChangeAccessPointScore(apName, _accessPoints[apName].tokenId, _accessPoints[apName].score, msg.sender);
}
/**
* @dev Add a new AccessPoint register for an app token.
* The AP name should be a DNS or ENS url and it should be unique.
*/
function _addAccessPoint(uint256 tokenId, string memory apName) internal {
if (_accessPoints[apName].owner != address(0)) revert AccessPointAlreadyExists();
emit NewAccessPoint(apName, tokenId, msg.sender);
if (_autoApproval[tokenId]) {
// Auto Approval is on.
_accessPoints[apName] = AccessPoint(
tokenId,
0,
false,
false,
msg.sender,
AccessPointCreationStatus.APPROVED
);
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.APPROVED, msg.sender);
} else {
// Auto Approval is off. Should wait for approval.
_accessPoints[apName] = AccessPoint(tokenId, 0, false, false, msg.sender, AccessPointCreationStatus.DRAFT);
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.DRAFT, msg.sender);
}
}
/**
* @dev Remove an AccessPoint registry for an app token.
* It will also remove the AP from the app token APs list.
*/
function _removeAccessPoint(string memory apName) internal requireAP(apName) {
if (msg.sender != _accessPoints[apName].owner) revert MustBeAccessPointOwner();
_accessPoints[apName].status = AccessPointCreationStatus.REMOVED;
uint256 tokenId = _accessPoints[apName].tokenId;
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.REMOVED, msg.sender);
emit RemoveAccessPoint(apName, tokenId, msg.sender);
}
/**
* @dev Updates the `accessPointAutoApproval` settings on minted `tokenId`.
*/
function _setAccessPointAutoApproval(uint256 tokenId, bool _apAutoApproval) internal {
_autoApproval[tokenId] = _apAutoApproval;
}
/**
* @dev Set approval settings for an access point.
* It will add the access point to the token's AP list, if `approved` is true.
*/
function _setApprovalForAccessPoint(uint256 tokenId, string memory apName, bool approved) internal {
AccessPoint storage accessPoint = _accessPoints[apName];
if (accessPoint.tokenId != tokenId) revert InvalidTokenIdForAccessPoint();
if (accessPoint.status != AccessPointCreationStatus.DRAFT) revert AccessPointCreationStatusAlreadySet();
if (approved) {
// Approval
accessPoint.status = AccessPointCreationStatus.APPROVED;
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.APPROVED, msg.sender);
} else {
// Not Approved
accessPoint.status = AccessPointCreationStatus.REJECTED;
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.REJECTED, msg.sender);
}
}
/**
* @dev Set the content verification of a AccessPoint registry.
*/
function _setAccessPointContentVerify(string memory apName, bool verified) internal requireAP(apName) {
_accessPoints[apName].contentVerified = verified;
emit ChangeAccessPointContentVerify(apName, _accessPoints[apName].tokenId, verified, msg.sender);
}
/**
* @dev Set the name verification of a AccessPoint registry.
*/
function _setAccessPointNameVerify(string memory apName, bool verified) internal requireAP(apName) {
_accessPoints[apName].nameVerified = verified;
emit ChangeAccessPointNameVerify(apName, _accessPoints[apName].tokenId, verified, msg.sender);
}
/**
* @dev Get the AccessPoint token id.
*/
function _getAccessPointTokenId(string memory apName) internal view requireAP(apName) returns (uint256) {
return _accessPoints[apName].tokenId;
}
/**
* @dev Get the Auto Approval setting for token id.
*/
function _getAccessPointAutoApproval(uint256 tokenId) internal view returns (bool) {
return _autoApproval[tokenId];
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}

View File

@ -7,22 +7,25 @@ import "@openzeppelin/contracts/utils/Base64.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./FleekAccessControl.sol";
import "./FleekBilling.sol";
import "./util/FleekStrings.sol";
import "./FleekPausable.sol";
import "./FleekAccessPoints.sol";
import "./util/FleekStrings.sol";
import "./IERCX.sol";
error AccessPointNotExistent();
error AccessPointAlreadyExists();
error AccessPointScoreCannotBeLower();
error MustBeAccessPointOwner();
error MustBeTokenOwner(uint256 tokenId);
error ThereIsNoTokenMinted();
error InvalidTokenIdForAccessPoint();
error AccessPointCreationStatusAlreadySet();
contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, FleekPausable, FleekBilling {
contract FleekERC721 is
IERCX,
Initializable,
ERC721Upgradeable,
FleekAccessControl,
FleekPausable,
FleekBilling,
FleekAccessPoints
{
using Strings for uint256;
using FleekStrings for FleekERC721.App;
using FleekStrings for FleekERC721.AccessPoint;
using FleekStrings for FleekERC721.Token;
using FleekStrings for string;
using FleekStrings for uint24;
@ -36,89 +39,12 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
string gitRepository,
string logo,
uint24 color,
bool accessPointAutoApproval,
address indexed minter,
address indexed owner
);
event MetadataUpdate(uint256 indexed _tokenId, string key, string value, address indexed triggeredBy);
event MetadataUpdate(uint256 indexed _tokenId, string key, uint24 value, address indexed triggeredBy);
event MetadataUpdate(uint256 indexed _tokenId, string key, string[2] value, address indexed triggeredBy);
event MetadataUpdate(uint256 indexed _tokenId, string key, bool value, address indexed triggeredBy);
event NewAccessPoint(string apName, uint256 indexed tokenId, address indexed owner);
event RemoveAccessPoint(string apName, uint256 indexed tokenId, address indexed owner);
event ChangeAccessPointScore(string apName, uint256 indexed tokenId, uint256 score, address indexed triggeredBy);
event ChangeAccessPointNameVerify(
string apName,
uint256 tokenId,
bool indexed verified,
address indexed triggeredBy
);
event ChangeAccessPointContentVerify(
string apName,
uint256 tokenId,
bool indexed verified,
address indexed triggeredBy
);
event ChangeAccessPointCreationStatus(
string apName,
uint256 tokenId,
AccessPointCreationStatus status,
address indexed triggeredBy
);
/**
* The properties are stored as string to keep consistency with
* other token contracts, we might consider changing for bytes32
* in the future due to gas optimization.
*/
struct App {
string name; // Name of the site
string description; // Description about the site
string externalURL; // Site URL
string ENS; // ENS ID
uint256 currentBuild; // The current build number (Increments by one with each change, starts at zero)
mapping(uint256 => Build) builds; // Mapping to build details for each build number
string logo;
uint24 color; // Color of the nft
bool accessPointAutoApproval; // AP Auto Approval
}
/**
* The metadata that is stored for each build.
*/
struct Build {
string commitHash;
string gitRepository;
}
/**
* Creation status enums for access points
*/
enum AccessPointCreationStatus {
DRAFT,
APPROVED,
REJECTED,
REMOVED
}
/**
* The stored data for each AccessPoint.
*/
struct AccessPoint {
uint256 tokenId;
uint256 score;
bool contentVerified;
bool nameVerified;
address owner;
AccessPointCreationStatus status;
}
uint256 private _appIds;
mapping(uint256 => App) private _apps;
mapping(string => AccessPoint) private _accessPoints;
mapping(uint256 => Token) private _apps;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
@ -134,14 +60,6 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
__FleekPausable_init();
}
/**
* @dev Checks if the AccessPoint exists.
*/
modifier requireAP(string memory apName) {
if (_accessPoints[apName].owner == address(0)) revert AccessPointNotExistent();
_;
}
/**
* @dev Mints a token and returns a tokenId.
*
@ -163,22 +81,20 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
string memory commitHash,
string memory gitRepository,
string memory logo,
uint24 color,
bool accessPointAutoApproval
uint24 color
) public payable requirePayment(Billing.Mint) returns (uint256) {
uint256 tokenId = _appIds;
_mint(to, tokenId);
_appIds += 1;
App storage app = _apps[tokenId];
Token storage app = _apps[tokenId];
app.name = name;
app.description = description;
app.externalURL = externalURL;
app.ENS = ENS;
app.logo = logo;
app.color = color;
app.accessPointAutoApproval = accessPointAutoApproval;
// The mint interaction is considered to be the first build of the site. Updates from now on all increment the currentBuild by one and update the mapping.
app.currentBuild = 0;
@ -193,7 +109,6 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
gitRepository,
logo,
color,
accessPointAutoApproval,
msg.sender,
to
);
@ -210,12 +125,13 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
* - the tokenId must be minted and valid.
*
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
function tokenURI(uint256 tokenId) public view virtual override(ERC721Upgradeable, IERCX) returns (string memory) {
_requireMinted(tokenId);
address owner = ownerOf(tokenId);
App storage app = _apps[tokenId];
bool accessPointAutoApproval = _getAccessPointAutoApproval(tokenId);
Token storage app = _apps[tokenId];
return string(abi.encodePacked(_baseURI(), app.toString(owner).toBase64()));
return string(abi.encodePacked(_baseURI(), app.toString(owner, accessPointAutoApproval).toBase64()));
}
/**
@ -237,7 +153,7 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
returns (string memory, string memory, string memory, string memory, uint256, string memory, uint24)
{
_requireMinted(tokenId);
App storage app = _apps[tokenId];
Token storage app = _apps[tokenId];
return (app.name, app.description, app.externalURL, app.ENS, app.currentBuild, app.logo, app.color);
}
@ -287,26 +203,6 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
return "data:application/json;base64,";
}
/**
* @dev Updates the `accessPointAutoApproval` settings on minted `tokenId`.
*
* May emit a {MetadataUpdate} event.
*
* Requirements:
*
* - the tokenId must be minted and valid.
* - the sender must have the `tokenController` role.
*
*/
function setAccessPointAutoApproval(
uint256 tokenId,
bool _apAutoApproval
) public virtual requireTokenOwner(tokenId) {
_requireMinted(tokenId);
_apps[tokenId].accessPointAutoApproval = _apAutoApproval;
emit MetadataUpdate(tokenId, "accessPointAutoApproval", _apAutoApproval, msg.sender);
}
/**
* @dev Updates the `externalURL` metadata field of a minted `tokenId`.
*
@ -443,197 +339,6 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
setTokenColor(tokenId, _tokenColor);
}
/**
* @dev Add a new AccessPoint register for an app token.
* The AP name should be a DNS or ENS url and it should be unique.
* Anyone can add an AP but it should requires a payment.
*
* May emit a {NewAccessPoint} event.
*
* Requirements:
*
* - the tokenId must be minted and valid.
* - billing for add acess point may be applied.
* - the contract must be not paused.
*
*/
function addAccessPoint(
uint256 tokenId,
string memory apName
) public payable whenNotPaused requirePayment(Billing.AddAccessPoint) {
// require(msg.value == 0.1 ether, "You need to pay at least 0.1 ETH"); // TODO: define a minimum price
_requireMinted(tokenId);
if (_accessPoints[apName].owner != address(0)) revert AccessPointAlreadyExists();
emit NewAccessPoint(apName, tokenId, msg.sender);
if (_apps[tokenId].accessPointAutoApproval) {
// Auto Approval is on.
_accessPoints[apName] = AccessPoint(
tokenId,
0,
false,
false,
msg.sender,
AccessPointCreationStatus.APPROVED
);
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.APPROVED, msg.sender);
} else {
// Auto Approval is off. Should wait for approval.
_accessPoints[apName] = AccessPoint(tokenId, 0, false, false, msg.sender, AccessPointCreationStatus.DRAFT);
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.DRAFT, msg.sender);
}
}
/**
* @dev Set approval settings for an access point.
* It will add the access point to the token's AP list, if `approved` is true.
*
* May emit a {ChangeAccessPointApprovalStatus} event.
*
* Requirements:
*
* - the tokenId must exist and be the same as the tokenId that is set for the AP.
* - the AP must exist.
* - must be called by a token controller.
*/
function setApprovalForAccessPoint(
uint256 tokenId,
string memory apName,
bool approved
) public requireTokenOwner(tokenId) {
AccessPoint storage accessPoint = _accessPoints[apName];
if (accessPoint.tokenId != tokenId) revert InvalidTokenIdForAccessPoint();
if (accessPoint.status != AccessPointCreationStatus.DRAFT) revert AccessPointCreationStatusAlreadySet();
if (approved) {
// Approval
accessPoint.status = AccessPointCreationStatus.APPROVED;
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.APPROVED, msg.sender);
} else {
// Not Approved
accessPoint.status = AccessPointCreationStatus.REJECTED;
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.REJECTED, msg.sender);
}
}
/**
* @dev Remove an AccessPoint registry for an app token.
* It will also remove the AP from the app token APs list.
*
* May emit a {RemoveAccessPoint} event.
*
* Requirements:
*
* - the AP must exist.
* - must be called by the AP owner.
* - the contract must be not paused.
*
*/
function removeAccessPoint(string memory apName) public whenNotPaused requireAP(apName) {
if (msg.sender != _accessPoints[apName].owner) revert MustBeAccessPointOwner();
_accessPoints[apName].status = AccessPointCreationStatus.REMOVED;
uint256 tokenId = _accessPoints[apName].tokenId;
emit ChangeAccessPointCreationStatus(apName, tokenId, AccessPointCreationStatus.REMOVED, msg.sender);
emit RemoveAccessPoint(apName, tokenId, msg.sender);
}
/**
* @dev A view function to gether information about an AccessPoint.
* It returns a JSON string representing the AccessPoint information.
*
* Requirements:
*
* - the AP must exist.
*
*/
function getAccessPointJSON(string memory apName) public view requireAP(apName) returns (string memory) {
AccessPoint storage _ap = _accessPoints[apName];
return _ap.toString();
}
/**
* @dev A view function to check if a AccessPoint is verified.
*
* Requirements:
*
* - the AP must exist.
*
*/
function isAccessPointNameVerified(string memory apName) public view requireAP(apName) returns (bool) {
return _accessPoints[apName].nameVerified;
}
/**
* @dev Increases the score of a AccessPoint registry.
*
* May emit a {ChangeAccessPointScore} event.
*
* Requirements:
*
* - the AP must exist.
*
*/
function increaseAccessPointScore(string memory apName) public requireAP(apName) {
_accessPoints[apName].score++;
emit ChangeAccessPointScore(apName, _accessPoints[apName].tokenId, _accessPoints[apName].score, msg.sender);
}
/**
* @dev Decreases the score of a AccessPoint registry if is greater than 0.
*
* May emit a {ChangeAccessPointScore} event.
*
* Requirements:
*
* - the AP must exist.
*
*/
function decreaseAccessPointScore(string memory apName) public requireAP(apName) {
if (_accessPoints[apName].score == 0) revert AccessPointScoreCannotBeLower();
_accessPoints[apName].score--;
emit ChangeAccessPointScore(apName, _accessPoints[apName].tokenId, _accessPoints[apName].score, msg.sender);
}
/**
* @dev Set the content verification of a AccessPoint registry.
*
* May emit a {ChangeAccessPointContentVerify} event.
*
* Requirements:
*
* - the AP must exist.
* - the sender must have collection verifier role.
*
*/
function setAccessPointContentVerify(
string memory apName,
bool verified
) public requireAP(apName) requireCollectionRole(CollectionRoles.Verifier) {
_accessPoints[apName].contentVerified = verified;
emit ChangeAccessPointContentVerify(apName, _accessPoints[apName].tokenId, verified, msg.sender);
}
/**
* @dev Set the name verification of a AccessPoint registry.
*
* May emit a {ChangeAccessPointNameVerify} event.
*
* Requirements:
*
* - the AP must exist.
* - the sender must have collection verifier role.
*
*/
function setAccessPointNameVerify(
string memory apName,
bool verified
) public requireAP(apName) requireCollectionRole(CollectionRoles.Verifier) {
_accessPoints[apName].nameVerified = verified;
emit ChangeAccessPointNameVerify(apName, _accessPoints[apName].tokenId, verified, msg.sender);
}
/**
* @dev Adds a new build to a minted `tokenId`'s builds mapping.
*
@ -675,6 +380,142 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
}
}
/*//////////////////////////////////////////////////////////////
ACCESS POINTS
//////////////////////////////////////////////////////////////*/
/**
* @dev Mints with access auto approval setting
*/
function mint(
address to,
string memory name,
string memory description,
string memory externalURL,
string memory ENS,
string memory commitHash,
string memory gitRepository,
string memory logo,
uint24 color,
bool accessPointAutoApproval
) public payable returns (uint256) {
uint256 tokenId = mint(to, name, description, externalURL, ENS, commitHash, gitRepository, logo, color);
_setAccessPointAutoApproval(tokenId, accessPointAutoApproval);
return tokenId;
}
/**
* @dev Add a new AccessPoint register for an app token.
* The AP name should be a DNS or ENS url and it should be unique.
* Anyone can add an AP but it should requires a payment.
*
* May emit a {NewAccessPoint} event.
*
* Requirements:
*
* - the tokenId must be minted and valid.
* - billing for add acess point may be applied.
* - the contract must be not paused.
*
*/
function addAccessPoint(
uint256 tokenId,
string memory apName
) public payable whenNotPaused requirePayment(Billing.AddAccessPoint) {
_requireMinted(tokenId);
_addAccessPoint(tokenId, apName);
}
/**
* @dev Remove an AccessPoint registry for an app token.
* It will also remove the AP from the app token APs list.
*
* May emit a {RemoveAccessPoint} event.
*
* Requirements:
*
* - the AP must exist.
* - must be called by the AP owner.
* - the contract must be not paused.
*
*/
function removeAccessPoint(string memory apName) public whenNotPaused {
_removeAccessPoint(apName);
}
/**
* @dev Updates the `accessPointAutoApproval` settings on minted `tokenId`.
*
* May emit a {MetadataUpdate} event.
*
* Requirements:
*
* - the tokenId must be minted and valid.
* - the sender must have the `tokenController` role.
*
*/
function setAccessPointAutoApproval(uint256 tokenId, bool _apAutoApproval) public requireTokenOwner(tokenId) {
_requireMinted(tokenId);
_setAccessPointAutoApproval(tokenId, _apAutoApproval);
emit MetadataUpdate(tokenId, "accessPointAutoApproval", _apAutoApproval, msg.sender);
}
/**
* @dev Set approval settings for an access point.
* It will add the access point to the token's AP list, if `approved` is true.
*
* May emit a {ChangeAccessPointApprovalStatus} event.
*
* Requirements:
*
* - the tokenId must exist and be the same as the tokenId that is set for the AP.
* - the AP must exist.
* - must be called by a token controller.
*/
function setApprovalForAccessPoint(
uint256 tokenId,
string memory apName,
bool approved
) public requireTokenOwner(tokenId) {
_setApprovalForAccessPoint(tokenId, apName, approved);
}
/**
* @dev Set the content verification of a AccessPoint registry.
*
* May emit a {ChangeAccessPointContentVerify} event.
*
* Requirements:
*
* - the AP must exist.
* - the sender must have the token controller role.
*
*/
function setAccessPointContentVerify(
string memory apName,
bool verified
) public requireCollectionRole(CollectionRoles.Verifier) {
_setAccessPointContentVerify(apName, verified);
}
/**
* @dev Set the name verification of a AccessPoint registry.
*
* May emit a {ChangeAccessPointNameVerify} event.
*
* Requirements:
*
* - the AP must exist.
* - the sender must have the token controller role.
*
*/
function setAccessPointNameVerify(
string memory apName,
bool verified
) public requireCollectionRole(CollectionRoles.Verifier) {
_setAccessPointNameVerify(apName, verified);
}
/*//////////////////////////////////////////////////////////////
ACCESS CONTROL
//////////////////////////////////////////////////////////////*/

View File

@ -0,0 +1,109 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
/**
* @title ERCX Interface
* @author
* @notice
*
* ERCX is a standard for NFTs that represent websites. It is a standard that
* allows for the storage of metadata about a website, and allows for the
* storage of multiple builds of a website. This allows for the NFT to be
* used as a way to store the history of a website.
*/
interface IERCX {
/**
* Event emitted when a token's metadata is updated.
* @param _tokenId the updated token id.
* @param key which metadata key was updated
* @param value the new value of the metadata
* @param triggeredBy the address that triggered the update
*/
event MetadataUpdate(uint256 indexed _tokenId, string key, string value, address indexed triggeredBy);
event MetadataUpdate(uint256 indexed _tokenId, string key, uint24 value, address indexed triggeredBy);
event MetadataUpdate(uint256 indexed _tokenId, string key, string[2] value, address indexed triggeredBy);
event MetadataUpdate(uint256 indexed _tokenId, string key, bool value, address indexed triggeredBy);
/**
* The metadata that is stored for each build.
*/
struct Build {
string commitHash;
string gitRepository;
}
/**
* The properties are stored as string to keep consistency with
* other token contracts, we might consider changing for bytes32
* in the future due to gas optimization.
*/
struct Token {
string name; // Name of the site
string description; // Description about the site
string externalURL; // Site URL
string ENS; // ENS for the site
string logo; // Branding logo
uint24 color; // Branding color
uint256 currentBuild; // The current build number (Increments by one with each change, starts at zero)
mapping(uint256 => Build) builds; // Mapping to build details for each build number
}
/**
* @dev Mints a token and returns a tokenId.
*/
function mint(
address to,
string memory name,
string memory description,
string memory externalURL,
string memory ENS,
string memory commitHash,
string memory gitRepository,
string memory logo,
uint24 color
) external payable returns (uint256);
/**
* @dev Sets a minted token's external URL.
*/
function setTokenExternalURL(uint256 tokenId, string memory _tokenExternalURL) external;
/**
* @dev Sets a minted token's ENS.
*/
function setTokenENS(uint256 tokenId, string memory _tokenENS) external;
/**
* @dev Sets a minted token's name.
*/
function setTokenName(uint256 tokenId, string memory _tokenName) external;
/**
* @dev Sets a minted token's description.
*/
function setTokenDescription(uint256 tokenId, string memory _tokenDescription) external;
/**
* @dev Sets a minted token's logo.
*/
function setTokenLogo(uint256 tokenId, string memory _tokenLogo) external;
/**
* @dev Sets a minted token's color.
*/
function setTokenColor(uint256 tokenId, uint24 _tokenColor) external;
/**
* @dev Sets a minted token's build.
*/
function setTokenBuild(uint256 tokenId, string memory commitHash, string memory gitRepository) external;
/**
* @dev Returns the token metadata for a given tokenId.
* It must return a valid JSON object in string format encoded in Base64.
*/
function tokenURI(uint256 tokenId) external returns (string memory);
}

View File

@ -2,7 +2,6 @@
pragma solidity ^0.8.7;
import "../FleekERC721.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";

View File

@ -2,10 +2,11 @@
pragma solidity ^0.8.7;
import "../FleekERC721.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "./FleekSVG.sol";
import "../IERCX.sol";
import "../FleekAccessPoints.sol";
library FleekStrings {
using Strings for uint256;
@ -29,10 +30,14 @@ library FleekStrings {
}
/**
* @dev Converts FleekERC721.App to a JSON string.
* @dev Converts IERCX.Token to a JSON string.
* It requires to receive owner address as a parameter.
*/
function toString(FleekERC721.App storage app, address owner) internal view returns (string memory) {
function toString(
IERCX.Token storage app,
address owner,
bool accessPointAutoApproval
) internal view returns (string memory) {
// prettier-ignore
return string(abi.encodePacked(
'{',
@ -41,7 +46,7 @@ library FleekStrings {
'"owner":"', uint160(owner).toHexString(20), '",',
'"external_url":"', app.externalURL, '",',
'"image":"', FleekSVG.generateBase64(app.name, app.ENS, app.logo, app.color.toColorString()), '",',
'"access_point_auto_approval":',app.accessPointAutoApproval.toString(),',',
'"access_point_auto_approval":', accessPointAutoApproval.toString(),',',
'"attributes": [',
'{"trait_type": "ENS", "value":"', app.ENS,'"},',
'{"trait_type": "Commit Hash", "value":"', app.builds[app.currentBuild].commitHash,'"},',
@ -54,9 +59,9 @@ library FleekStrings {
}
/**
* @dev Converts FleekERC721.AccessPoint to a JSON string.
* @dev Converts FleekAccessPoints.AccessPoint to a JSON string.
*/
function toString(FleekERC721.AccessPoint storage ap) internal view returns (string memory) {
function toString(FleekAccessPoints.AccessPoint storage ap) internal view returns (string memory) {
// prettier-ignore
return string(abi.encodePacked(
"{",

View File

@ -91,7 +91,9 @@ const mintTo = '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049';
console.log('SVG length: ', params[params.length - 1].length);
params.push(await getSVGColor(svgPath));
const transaction = await contract.mint(...params);
const transaction = await contract[
'mint(address,string,string,string,string,string,string,string,uint24)'
](...params);
console.log('Response: ', transaction);
})();

View File

@ -1,7 +1,12 @@
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
import { ethers } from 'hardhat';
import { expect } from 'chai';
import { Fixtures, TestConstants, Errors } from './helpers';
import {
Fixtures,
TestConstants,
Errors,
OverloadedFunctions,
} from './helpers';
const { Billing, MintParams } = TestConstants;
@ -12,7 +17,7 @@ describe('FleekERC721.Billing', () => {
const mint = (value?: any) => {
const { contract, owner } = fixture;
return contract.mint(
return contract[OverloadedFunctions.Mint.Default](
owner.address,
MintParams.name,
MintParams.description,
@ -22,7 +27,6 @@ describe('FleekERC721.Billing', () => {
MintParams.gitRepository,
MintParams.logo,
MintParams.color,
MintParams.accessPointAutoApprovalSettings,
{ value }
);
};

View File

@ -1,6 +1,11 @@
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
import { expect } from 'chai';
import { TestConstants, Fixtures, Errors } from './helpers';
import {
TestConstants,
Fixtures,
Errors,
OverloadedFunctions,
} from './helpers';
const { CollectionRoles } = TestConstants;
@ -179,7 +184,7 @@ describe('FleekERC721.CollectionRoles', () => {
it('should not be able to verify access point if not verifier', async () => {
const { contract, otherAccount } = fixture;
await contract.mint(
await contract[OverloadedFunctions.Mint.Default](
otherAccount.address,
TestConstants.MintParams.name,
TestConstants.MintParams.description,
@ -188,8 +193,7 @@ describe('FleekERC721.CollectionRoles', () => {
TestConstants.MintParams.commitHash,
TestConstants.MintParams.gitRepository,
TestConstants.MintParams.logo,
TestConstants.MintParams.color,
TestConstants.MintParams.accessPointAutoApprovalSettings
TestConstants.MintParams.color
);
await contract.addAccessPoint(0, 'random.com');

View File

@ -1,15 +1,17 @@
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
import { expect } from 'chai';
import { TestConstants, Fixtures, Errors } from './helpers';
import { ethers } from 'hardhat';
const { MintParams, Roles } = TestConstants;
import {
TestConstants,
Fixtures,
Errors,
OverloadedFunctions,
} from './helpers';
describe('FleekERC721.GetLastTokenId', () => {
let fixture: Awaited<ReturnType<typeof Fixtures.default>>;
const mint = async () => {
const response = await fixture.contract.mint(
const response = await fixture.contract[OverloadedFunctions.Mint.Default](
fixture.owner.address,
TestConstants.MintParams.name,
TestConstants.MintParams.description,
@ -18,8 +20,7 @@ describe('FleekERC721.GetLastTokenId', () => {
TestConstants.MintParams.commitHash,
TestConstants.MintParams.gitRepository,
TestConstants.MintParams.logo,
TestConstants.MintParams.color,
false
TestConstants.MintParams.color
);
return response;

View File

@ -1,5 +1,6 @@
import { ethers, upgrades } from 'hardhat';
import { TestConstants } from './constants';
import { OverloadedFunctions } from './overloaded-functions';
export abstract class Fixtures {
static async paused() {}
@ -35,7 +36,9 @@ export abstract class Fixtures {
static async withMint() {
const fromDefault = await Fixtures.default();
const response = await fromDefault.contract.mint(
const response = await fromDefault.contract[
OverloadedFunctions.Mint.Default
](
fromDefault.owner.address,
TestConstants.MintParams.name,
TestConstants.MintParams.description,
@ -44,8 +47,7 @@ export abstract class Fixtures {
TestConstants.MintParams.commitHash,
TestConstants.MintParams.gitRepository,
TestConstants.MintParams.logo,
TestConstants.MintParams.color,
TestConstants.MintParams.accessPointAutoApprovalSettings
TestConstants.MintParams.color
);
const tokenId = response.value.toNumber();

View File

@ -3,3 +3,4 @@ export * from './fixture';
export * from './utils';
export * from './errors';
export * from './events';
export * from './overloaded-functions';

View File

@ -0,0 +1,8 @@
export const OverloadedFunctions = Object.freeze({
Mint: {
Default:
'mint(address,string,string,string,string,string,string,string,uint24)',
WithAPAutoApproval:
'mint(address,string,string,string,string,string,string,string,uint24,bool)',
},
});

View File

@ -1,15 +1,15 @@
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
import { expect } from 'chai';
import { TestConstants, Fixtures, Errors } from './helpers';
import { TestConstants, Fixtures, OverloadedFunctions } from './helpers';
import { ethers } from 'hardhat';
const { MintParams, CollectionRoles } = TestConstants;
const { MintParams } = TestConstants;
describe('FleekERC721.Minting', () => {
it('should be able to mint a new token', async () => {
const { owner, contract } = await loadFixture(Fixtures.default);
const response = await contract.mint(
const response = await contract[OverloadedFunctions.Mint.Default](
owner.address,
MintParams.name,
MintParams.description,
@ -18,8 +18,7 @@ describe('FleekERC721.Minting', () => {
MintParams.commitHash,
MintParams.gitRepository,
MintParams.logo,
MintParams.color,
MintParams.accessPointAutoApprovalSettings
MintParams.color
);
expect(response.value).to.be.instanceOf(ethers.BigNumber);
@ -31,7 +30,7 @@ describe('FleekERC721.Minting', () => {
Fixtures.default
);
const response = await contract.mint(
const response = await contract[OverloadedFunctions.Mint.Default](
owner.address,
MintParams.name,
MintParams.description,
@ -40,8 +39,7 @@ describe('FleekERC721.Minting', () => {
MintParams.commitHash,
MintParams.gitRepository,
MintParams.logo,
MintParams.color,
MintParams.accessPointAutoApprovalSettings
MintParams.color
);
const tokenId = response.value.toNumber();

View File

@ -1,6 +1,11 @@
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
import { expect } from 'chai';
import { TestConstants, Fixtures, Errors } from './helpers';
import {
TestConstants,
Fixtures,
Errors,
OverloadedFunctions,
} from './helpers';
const { MintParams, CollectionRoles, TokenRoles } = TestConstants;
@ -10,7 +15,7 @@ describe('FleekERC721.Pausable', () => {
const mint = () => {
const { owner, contract } = fixture;
return contract.mint(
return contract[OverloadedFunctions.Mint.Default](
owner.address,
MintParams.name,
MintParams.description,
@ -19,8 +24,7 @@ describe('FleekERC721.Pausable', () => {
MintParams.commitHash,
MintParams.gitRepository,
MintParams.logo,
MintParams.color,
false
MintParams.color
);
};

View File

@ -25,7 +25,7 @@ import {
NewAccessPoint as NewAccessPointEvent,
ChangeAccessPointNameVerify as ChangeAccessPointNameVerifyEvent,
ChangeAccessPointContentVerify as ChangeAccessPointContentVerifyEvent,
TokenRolesCleared as TokenRolesClearedEvent
TokenRolesCleared as TokenRolesClearedEvent,
} from '../generated/FleekNFA/FleekNFA';
// Entity Imports [based on the schema]

View File

@ -1,4 +1,4 @@
{
"version": "0.5.4",
"timestamp": 1678390993500
}
}

View File

@ -7,7 +7,13 @@ import {
afterAll,
} from 'matchstick-as/assembly/index';
import { BigInt, Bytes } from '@graphprotocol/graph-ts';
import { createNewCollectionRoleChanged, handleCollectionRoleChangedList, makeEventId, USER_ONE, USER_TWO } from '../helpers/utils';
import {
createNewCollectionRoleChanged,
handleCollectionRoleChangedList,
makeEventId,
USER_ONE,
USER_TWO,
} from '../helpers/utils';
import { CollectionRoleChanged } from '../../../generated/FleekNFA/FleekNFA';
describe('Collection Role Changed tests', () => {
@ -16,14 +22,13 @@ describe('Collection Role Changed tests', () => {
let collectionRoleChangedList: CollectionRoleChanged[] = [];
collectionRoleChangedList.push(
createNewCollectionRoleChanged(0, 0, USER_ONE, true, USER_TWO) // User Two grants collection owner access to User One
createNewCollectionRoleChanged(0, 0, USER_ONE, true, USER_TWO) // User Two grants collection owner access to User One
);
collectionRoleChangedList.push(
createNewCollectionRoleChanged(2, 0, USER_ONE, false, USER_TWO) // User Two revokes the owner access of User One to the collection
);
handleCollectionRoleChangedList(collectionRoleChangedList);
});
@ -33,18 +38,8 @@ describe('Collection Role Changed tests', () => {
describe('Assertions', () => {
test('Check the `role` field of each CollectionRoleChanged event entity', () => {
assert.fieldEquals(
'CollectionRoleChanged',
makeEventId(0),
'role',
'0'
);
assert.fieldEquals(
'CollectionRoleChanged',
makeEventId(2),
'role',
'0'
);
assert.fieldEquals('CollectionRoleChanged', makeEventId(0), 'role', '0');
assert.fieldEquals('CollectionRoleChanged', makeEventId(2), 'role', '0');
});
test('Check the `toAddress` field of each CollectionRoleChanged event entity', () => {
@ -78,18 +73,8 @@ describe('Collection Role Changed tests', () => {
});
test('Check the `status` field of each CollectionRoleChanged event entity', () => {
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(0),
'status',
'true'
);
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(2),
'status',
'false'
);
assert.fieldEquals('TokenRoleChanged', makeEventId(0), 'status', 'true');
assert.fieldEquals('TokenRoleChanged', makeEventId(2), 'status', 'false');
});
});
});
});

View File

@ -7,7 +7,13 @@ import {
afterAll,
} from 'matchstick-as/assembly/index';
import { BigInt, Bytes } from '@graphprotocol/graph-ts';
import { createNewTokenRoleChanged, handleTokenRoleChangedList, makeEventId, USER_ONE, USER_TWO } from '../helpers/utils';
import {
createNewTokenRoleChanged,
handleTokenRoleChangedList,
makeEventId,
USER_ONE,
USER_TWO,
} from '../helpers/utils';
import { TokenRoleChanged } from '../../../generated/FleekNFA/FleekNFA';
describe('Token Role Changed tests', () => {
@ -16,18 +22,38 @@ describe('Token Role Changed tests', () => {
let tokenRoleChangedList: TokenRoleChanged[] = [];
tokenRoleChangedList.push(
createNewTokenRoleChanged(0, BigInt.fromI32(0), 0, USER_ONE, true, USER_TWO) // User Two gives User One controller access to TokenId 0
createNewTokenRoleChanged(
0,
BigInt.fromI32(0),
0,
USER_ONE,
true,
USER_TWO
) // User Two gives User One controller access to TokenId 0
);
tokenRoleChangedList.push(
createNewTokenRoleChanged(1, BigInt.fromI32(1), 0, USER_TWO, true, USER_ONE) // User One gives User Two controller access to TokenId 1
createNewTokenRoleChanged(
1,
BigInt.fromI32(1),
0,
USER_TWO,
true,
USER_ONE
) // User One gives User Two controller access to TokenId 1
);
tokenRoleChangedList.push(
createNewTokenRoleChanged(2, BigInt.fromI32(0), 0, USER_ONE, false, USER_TWO) // User Two revokes the controller access of User One to tokenId 0
createNewTokenRoleChanged(
2,
BigInt.fromI32(0),
0,
USER_ONE,
false,
USER_TWO
) // User Two revokes the controller access of User One to tokenId 0
);
handleTokenRoleChangedList(tokenRoleChangedList);
});
@ -37,44 +63,14 @@ describe('Token Role Changed tests', () => {
describe('Assertions', () => {
test('Check the `tokenId` field of each TokenRoleChanged event entity', () => {
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(0),
'tokenId',
'0'
);
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(1),
'tokenId',
'1'
);
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(2),
'tokenId',
'0'
);
assert.fieldEquals('TokenRoleChanged', makeEventId(0), 'tokenId', '0');
assert.fieldEquals('TokenRoleChanged', makeEventId(1), 'tokenId', '1');
assert.fieldEquals('TokenRoleChanged', makeEventId(2), 'tokenId', '0');
});
test('Check the `role` field of each TokenRoleChanged event entity', () => {
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(0),
'role',
'0'
);
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(1),
'role',
'0'
);
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(2),
'role',
'0'
);
assert.fieldEquals('TokenRoleChanged', makeEventId(0), 'role', '0');
assert.fieldEquals('TokenRoleChanged', makeEventId(1), 'role', '0');
assert.fieldEquals('TokenRoleChanged', makeEventId(2), 'role', '0');
});
test('Check the `toAddress` field of each TokenRoleChanged event entity', () => {
@ -120,24 +116,9 @@ describe('Token Role Changed tests', () => {
});
test('Check the `status` field of each TokenRoleChanged event entity', () => {
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(0),
'status',
'true'
);
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(1),
'status',
'true'
);
assert.fieldEquals(
'TokenRoleChanged',
makeEventId(2),
'status',
'false'
);
assert.fieldEquals('TokenRoleChanged', makeEventId(0), 'status', 'true');
assert.fieldEquals('TokenRoleChanged', makeEventId(1), 'status', 'true');
assert.fieldEquals('TokenRoleChanged', makeEventId(2), 'status', 'false');
});
});
});
});

View File

@ -1,98 +1,115 @@
import {
assert,
describe,
test,
clearStore,
beforeAll,
afterAll,
} from 'matchstick-as/assembly/index';
import { BigInt, Bytes } from '@graphprotocol/graph-ts';
import { createNewAccessPointEvent, createNewChangeAccessPointCreationStatus, handleChangeAccessPointCreationStatusList, handleNewAccessPoints, makeEventId, USER_ONE, USER_TWO } from '../helpers/utils';
import { ChangeAccessPointCreationStatus, NewAccessPoint } from '../../../generated/FleekNFA/FleekNFA';
assert,
describe,
test,
clearStore,
beforeAll,
afterAll,
} from 'matchstick-as/assembly/index';
import { BigInt, Bytes } from '@graphprotocol/graph-ts';
import {
createNewAccessPointEvent,
createNewChangeAccessPointCreationStatus,
handleChangeAccessPointCreationStatusList,
handleNewAccessPoints,
makeEventId,
USER_ONE,
USER_TWO,
} from '../helpers/utils';
import {
ChangeAccessPointCreationStatus,
NewAccessPoint,
} from '../../../generated/FleekNFA/FleekNFA';
describe('Change Access Point Creation Status tests', () => {
beforeAll(() => {
beforeAll(() => {
// New Access Points
let newAccessPoints: NewAccessPoint[] = [];
// User One has two access points: one for tokenId 0 and one for tokenId 1
newAccessPoints.push(
createNewAccessPointEvent(0, 'firstAP', BigInt.fromI32(0), USER_ONE)
);
newAccessPoints.push(
createNewAccessPointEvent(1, 'secondAP', BigInt.fromI32(1), USER_ONE)
);
// User Two has one access point for tokenId 0
newAccessPoints.push(
createNewAccessPointEvent(2, 'thirdAP', BigInt.fromI32(0), USER_TWO)
);
handleNewAccessPoints(newAccessPoints);
});
afterAll(() => {
clearStore();
});
describe('Assertions', () => {
test('Check the `creationStatus` field of each access point entity', () => {
assert.fieldEquals('AccessPoint', 'firstAP', 'creationStatus', 'DRAFT');
assert.fieldEquals('AccessPoint', 'secondAP', 'creationStatus', 'DRAFT');
assert.fieldEquals('AccessPoint', 'thirdAP', 'creationStatus', 'DRAFT');
});
test('Check the `creationStatus` field of each access point entity after changing it', () => {
// New Access Points
let newAccessPoints: NewAccessPoint[] = [];
let changeAccessPointCreationStatusList: ChangeAccessPointCreationStatus[] =
[];
// User One has two access points: one for tokenId 0 and one for tokenId 1
newAccessPoints.push(
createNewAccessPointEvent(0, 'firstAP', BigInt.fromI32(0), USER_ONE)
changeAccessPointCreationStatusList.push(
createNewChangeAccessPointCreationStatus(
0,
'firstAP',
BigInt.fromI32(0),
1,
USER_ONE
)
);
newAccessPoints.push(
createNewAccessPointEvent(1, 'secondAP', BigInt.fromI32(1), USER_ONE)
changeAccessPointCreationStatusList.push(
createNewChangeAccessPointCreationStatus(
0,
'secondAP',
BigInt.fromI32(1),
1,
USER_ONE
)
);
// User Two has one access point for tokenId 0
newAccessPoints.push(
createNewAccessPointEvent(2, 'thirdAP', BigInt.fromI32(0), USER_TWO)
changeAccessPointCreationStatusList.push(
createNewChangeAccessPointCreationStatus(
0,
'thirdAP',
BigInt.fromI32(0),
1,
USER_TWO
)
);
handleNewAccessPoints(newAccessPoints);
});
afterAll(() => {
clearStore();
});
describe('Assertions', () => {
test('Check the `creationStatus` field of each access point entity', () => {
assert.fieldEquals(
'AccessPoint',
'firstAP',
'creationStatus',
'DRAFT'
);
assert.fieldEquals(
'AccessPoint',
'secondAP',
'creationStatus',
'DRAFT'
);
assert.fieldEquals(
'AccessPoint',
'thirdAP',
'creationStatus',
'DRAFT'
);
});
test('Check the `creationStatus` field of each access point entity after changing it', () => {
// New Access Points
let changeAccessPointCreationStatusList: ChangeAccessPointCreationStatus[] = [];
// User One has two access points: one for tokenId 0 and one for tokenId 1
changeAccessPointCreationStatusList.push(
createNewChangeAccessPointCreationStatus(0, 'firstAP', BigInt.fromI32(0), 1, USER_ONE)
);
changeAccessPointCreationStatusList.push(
createNewChangeAccessPointCreationStatus(0, 'secondAP', BigInt.fromI32(1), 1, USER_ONE)
);
handleChangeAccessPointCreationStatusList(
changeAccessPointCreationStatusList
);
// User Two has one access point for tokenId 0
changeAccessPointCreationStatusList.push(
createNewChangeAccessPointCreationStatus(0, 'thirdAP', BigInt.fromI32(0), 1, USER_TWO)
);
handleChangeAccessPointCreationStatusList(changeAccessPointCreationStatusList);
assert.fieldEquals(
'AccessPoint',
'firstAP',
'creationStatus',
'APPROVED'
);
assert.fieldEquals(
'AccessPoint',
'secondAP',
'creationStatus',
'APPROVED'
);
assert.fieldEquals(
'AccessPoint',
'thirdAP',
'creationStatus',
'APPROVED'
);
});
assert.fieldEquals(
'AccessPoint',
'firstAP',
'creationStatus',
'APPROVED'
);
assert.fieldEquals(
'AccessPoint',
'secondAP',
'creationStatus',
'APPROVED'
);
assert.fieldEquals(
'AccessPoint',
'thirdAP',
'creationStatus',
'APPROVED'
);
});
});
});
});

View File

@ -1,96 +1,94 @@
import {
assert,
describe,
test,
clearStore,
beforeAll,
afterAll,
} from 'matchstick-as/assembly/index';
import { BigInt } from '@graphprotocol/graph-ts';
import { createNewAccessPointEvent, createNewChangeAccessPointNameVerify, handleChangeAccessPointNameVerifies, handleNewAccessPoints, USER_ONE, USER_TWO } from '../helpers/utils';
import { ChangeAccessPointNameVerify, NewAccessPoint } from '../../../generated/FleekNFA/FleekNFA';
assert,
describe,
test,
clearStore,
beforeAll,
afterAll,
} from 'matchstick-as/assembly/index';
import { BigInt } from '@graphprotocol/graph-ts';
import {
createNewAccessPointEvent,
createNewChangeAccessPointNameVerify,
handleChangeAccessPointNameVerifies,
handleNewAccessPoints,
USER_ONE,
USER_TWO,
} from '../helpers/utils';
import {
ChangeAccessPointNameVerify,
NewAccessPoint,
} from '../../../generated/FleekNFA/FleekNFA';
describe('Change Access Point Name Verify tests', () => {
beforeAll(() => {
// New Access Points
let newAccessPoints: NewAccessPoint[] = [];
beforeAll(() => {
// New Access Points
let newAccessPoints: NewAccessPoint[] = [];
// User One has two access points: one for tokenId 0 and one for tokenId 1
newAccessPoints.push(
createNewAccessPointEvent(0, 'firstAP', BigInt.fromI32(0), USER_ONE)
// User One has two access points: one for tokenId 0 and one for tokenId 1
newAccessPoints.push(
createNewAccessPointEvent(0, 'firstAP', BigInt.fromI32(0), USER_ONE)
);
newAccessPoints.push(
createNewAccessPointEvent(1, 'secondAP', BigInt.fromI32(1), USER_ONE)
);
// User Two has one access point for tokenId 0
newAccessPoints.push(
createNewAccessPointEvent(2, 'thirdAP', BigInt.fromI32(0), USER_TWO)
);
handleNewAccessPoints(newAccessPoints);
});
afterAll(() => {
clearStore();
});
describe('Assertions', () => {
test('Check the `nameVerified` field of each access point entity', () => {
assert.fieldEquals('AccessPoint', 'firstAP', 'nameVerified', 'false');
assert.fieldEquals('AccessPoint', 'secondAP', 'nameVerified', 'false');
assert.fieldEquals('AccessPoint', 'thirdAP', 'nameVerified', 'false');
});
test('Check the `nameVerified` field of each access point entity after changing it', () => {
// New Access Point Name Verified fields
let changeAccessPointNameVerifies: ChangeAccessPointNameVerify[] = [];
changeAccessPointNameVerifies.push(
createNewChangeAccessPointNameVerify(
0,
'firstAP',
BigInt.fromI32(0),
true,
USER_ONE
)
);
newAccessPoints.push(
createNewAccessPointEvent(1, 'secondAP', BigInt.fromI32(1), USER_ONE)
changeAccessPointNameVerifies.push(
createNewChangeAccessPointNameVerify(
0,
'secondAP',
BigInt.fromI32(1),
true,
USER_ONE
)
);
// User Two has one access point for tokenId 0
newAccessPoints.push(
createNewAccessPointEvent(2, 'thirdAP', BigInt.fromI32(0), USER_TWO)
changeAccessPointNameVerifies.push(
createNewChangeAccessPointNameVerify(
0,
'thirdAP',
BigInt.fromI32(0),
true,
USER_TWO
)
);
handleNewAccessPoints(newAccessPoints);
});
afterAll(() => {
clearStore();
});
describe('Assertions', () => {
test('Check the `nameVerified` field of each access point entity', () => {
assert.fieldEquals(
'AccessPoint',
'firstAP',
'nameVerified',
'false'
);
assert.fieldEquals(
'AccessPoint',
'secondAP',
'nameVerified',
'false'
);
assert.fieldEquals(
'AccessPoint',
'thirdAP',
'nameVerified',
'false'
);
});
test('Check the `nameVerified` field of each access point entity after changing it', () => {
// New Access Point Name Verified fields
let changeAccessPointNameVerifies: ChangeAccessPointNameVerify[] = [];
changeAccessPointNameVerifies.push(
createNewChangeAccessPointNameVerify(0, 'firstAP', BigInt.fromI32(0), true, USER_ONE)
);
changeAccessPointNameVerifies.push(
createNewChangeAccessPointNameVerify(0, 'secondAP', BigInt.fromI32(1), true, USER_ONE)
);
handleChangeAccessPointNameVerifies(changeAccessPointNameVerifies);
changeAccessPointNameVerifies.push(
createNewChangeAccessPointNameVerify(0, 'thirdAP', BigInt.fromI32(0), true, USER_TWO)
);
handleChangeAccessPointNameVerifies(changeAccessPointNameVerifies);
assert.fieldEquals(
'AccessPoint',
'firstAP',
'nameVerified',
'true'
);
assert.fieldEquals(
'AccessPoint',
'secondAP',
'nameVerified',
'true'
);
assert.fieldEquals(
'AccessPoint',
'thirdAP',
'nameVerified',
'true'
);
});
assert.fieldEquals('AccessPoint', 'firstAP', 'nameVerified', 'true');
assert.fieldEquals('AccessPoint', 'secondAP', 'nameVerified', 'true');
assert.fieldEquals('AccessPoint', 'thirdAP', 'nameVerified', 'true');
});
});
});
});

View File

@ -1,109 +1,100 @@
import {
assert,
describe,
test,
clearStore,
beforeAll,
afterAll,
} from 'matchstick-as/assembly/index';
import { BigInt, Bytes } from '@graphprotocol/graph-ts';
import { createNewAccessPointEvent, handleNewAccessPoints, makeEventId, USER_ONE, USER_TWO } from '../helpers/utils';
assert,
describe,
test,
clearStore,
beforeAll,
afterAll,
} from 'matchstick-as/assembly/index';
import { BigInt, Bytes } from '@graphprotocol/graph-ts';
import {
createNewAccessPointEvent,
handleNewAccessPoints,
makeEventId,
USER_ONE,
USER_TWO,
} from '../helpers/utils';
import { NewAccessPoint } from '../../../generated/FleekNFA/FleekNFA';
describe('New Access Point tests', () => {
beforeAll(() => {
// New Access Points
let newAccessPoints: NewAccessPoint[] = [];
beforeAll(() => {
// New Access Points
let newAccessPoints: NewAccessPoint[] = [];
// User One has two access points: one for tokenId 0 and one for tokenId 1
newAccessPoints.push(
createNewAccessPointEvent(0, 'firstAP', BigInt.fromI32(0), USER_ONE)
);
newAccessPoints.push(
createNewAccessPointEvent(1, 'secondAP', BigInt.fromI32(1), USER_ONE)
);
// User One has two access points: one for tokenId 0 and one for tokenId 1
newAccessPoints.push(
createNewAccessPointEvent(0, 'firstAP', BigInt.fromI32(0), USER_ONE)
);
newAccessPoints.push(
createNewAccessPointEvent(1, 'secondAP', BigInt.fromI32(1), USER_ONE)
);
// User Two has one access point for tokenId 0
newAccessPoints.push(
createNewAccessPointEvent(2, 'thirdAP', BigInt.fromI32(0), USER_TWO)
);
handleNewAccessPoints(newAccessPoints);
// User Two has one access point for tokenId 0
newAccessPoints.push(
createNewAccessPointEvent(2, 'thirdAP', BigInt.fromI32(0), USER_TWO)
);
handleNewAccessPoints(newAccessPoints);
});
afterAll(() => {
clearStore();
});
describe('Assertions', () => {
test('Check the number of `NewAccessPoint` events to be valid', () => {
assert.entityCount('NewAccessPoint', 3);
});
afterAll(() => {
clearStore();
test('Check the `apName` field of each event', () => {
assert.fieldEquals(
'NewAccessPoint',
makeEventId(0),
'apName',
'firstAP'.toString()
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(1),
'apName',
'secondAP'.toString()
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(2),
'apName',
'thirdAP'.toString()
);
});
describe('Assertions', () => {
test('Check the number of `NewAccessPoint` events to be valid', () => {
assert.entityCount('NewAccessPoint', 3);
});
test('Check the `apName` field of each event', () => {
assert.fieldEquals(
'NewAccessPoint',
makeEventId(0),
'apName',
'firstAP'.toString()
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(1),
'apName',
'secondAP'.toString()
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(2),
'apName',
'thirdAP'.toString()
);
});
test('Check the `tokenId` field of each event', () => {
assert.fieldEquals(
'NewAccessPoint',
makeEventId(0),
'tokenId',
'0'
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(1),
'tokenId',
'1'
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(2),
'tokenId',
'0'
);
});
test('Check the `owner` field of each event', () => {
assert.fieldEquals(
'NewAccessPoint',
makeEventId(0),
'owner',
USER_ONE.toString()
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(1),
'owner',
USER_ONE.toString()
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(2),
'owner',
USER_TWO.toString()
);
});
test('check the existence of a nonexistent event in the database', () => {
assert.notInStore('NewAccessPoint', makeEventId(3));
});
test('Check the `tokenId` field of each event', () => {
assert.fieldEquals('NewAccessPoint', makeEventId(0), 'tokenId', '0');
assert.fieldEquals('NewAccessPoint', makeEventId(1), 'tokenId', '1');
assert.fieldEquals('NewAccessPoint', makeEventId(2), 'tokenId', '0');
});
});
test('Check the `owner` field of each event', () => {
assert.fieldEquals(
'NewAccessPoint',
makeEventId(0),
'owner',
USER_ONE.toString()
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(1),
'owner',
USER_ONE.toString()
);
assert.fieldEquals(
'NewAccessPoint',
makeEventId(2),
'owner',
USER_TWO.toString()
);
});
test('check the existence of a nonexistent event in the database', () => {
assert.notInStore('NewAccessPoint', makeEventId(3));
});
});
});

View File

@ -10,7 +10,7 @@ import {
ChangeAccessPointNameVerify,
TokenRoleChanged,
CollectionRoleChanged,
TokenRolesCleared
TokenRolesCleared,
} from '../../../generated/FleekNFA/FleekNFA';
import {
handleApproval,
@ -198,10 +198,7 @@ export function createNewAccessPointEvent(
);
newAccessPoint.parameters.push(
new ethereum.EventParam(
'owner',
ethereum.Value.fromAddress(owner)
)
new ethereum.EventParam('owner', ethereum.Value.fromAddress(owner))
);
newAccessPoint.transaction.hash = Bytes.fromI32(event_count);
@ -217,7 +214,8 @@ export function createNewChangeAccessPointCreationStatus(
status: i32,
triggeredBy: Address
): ChangeAccessPointCreationStatus {
let changeAccessPointCreationStatus = changetype<ChangeAccessPointCreationStatus>(newMockEvent());
let changeAccessPointCreationStatus =
changetype<ChangeAccessPointCreationStatus>(newMockEvent());
changeAccessPointCreationStatus.parameters = new Array();
@ -236,10 +234,7 @@ export function createNewChangeAccessPointCreationStatus(
);
changeAccessPointCreationStatus.parameters.push(
new ethereum.EventParam(
'creationStatus',
ethereum.Value.fromI32(status)
)
new ethereum.EventParam('creationStatus', ethereum.Value.fromI32(status))
);
changeAccessPointCreationStatus.parameters.push(
@ -262,7 +257,9 @@ export function createNewChangeAccessPointNameVerify(
verified: boolean,
triggeredBy: Address
): ChangeAccessPointNameVerify {
let changeAccessPointNameVerify = changetype<ChangeAccessPointNameVerify>(newMockEvent());
let changeAccessPointNameVerify = changetype<ChangeAccessPointNameVerify>(
newMockEvent()
);
changeAccessPointNameVerify.parameters = new Array();
@ -281,10 +278,7 @@ export function createNewChangeAccessPointNameVerify(
);
changeAccessPointNameVerify.parameters.push(
new ethereum.EventParam(
'verified',
ethereum.Value.fromBoolean(verified)
)
new ethereum.EventParam('verified', ethereum.Value.fromBoolean(verified))
);
changeAccessPointNameVerify.parameters.push(
@ -320,31 +314,19 @@ export function createNewTokenRoleChanged(
);
tokenRoleChanged.parameters.push(
new ethereum.EventParam(
'role',
ethereum.Value.fromI32(role)
)
new ethereum.EventParam('role', ethereum.Value.fromI32(role))
);
tokenRoleChanged.parameters.push(
new ethereum.EventParam(
'toAddress',
ethereum.Value.fromAddress(toAddress)
)
new ethereum.EventParam('toAddress', ethereum.Value.fromAddress(toAddress))
);
tokenRoleChanged.parameters.push(
new ethereum.EventParam(
'status',
ethereum.Value.fromBoolean(status)
)
new ethereum.EventParam('status', ethereum.Value.fromBoolean(status))
);
tokenRoleChanged.parameters.push(
new ethereum.EventParam(
'byAddress',
ethereum.Value.fromAddress(byAddress)
)
new ethereum.EventParam('byAddress', ethereum.Value.fromAddress(byAddress))
);
tokenRoleChanged.transaction.hash = Bytes.fromI32(event_count);
@ -365,31 +347,19 @@ export function createNewCollectionRoleChanged(
collectionRoleChanged.parameters = new Array();
collectionRoleChanged.parameters.push(
new ethereum.EventParam(
'role',
ethereum.Value.fromI32(role)
)
new ethereum.EventParam('role', ethereum.Value.fromI32(role))
);
collectionRoleChanged.parameters.push(
new ethereum.EventParam(
'toAddress',
ethereum.Value.fromAddress(toAddress)
)
new ethereum.EventParam('toAddress', ethereum.Value.fromAddress(toAddress))
);
collectionRoleChanged.parameters.push(
new ethereum.EventParam(
'status',
ethereum.Value.fromBoolean(status)
)
new ethereum.EventParam('status', ethereum.Value.fromBoolean(status))
);
collectionRoleChanged.parameters.push(
new ethereum.EventParam(
'byAddress',
ethereum.Value.fromAddress(byAddress)
)
new ethereum.EventParam('byAddress', ethereum.Value.fromAddress(byAddress))
);
collectionRoleChanged.transaction.hash = Bytes.fromI32(event_count);
@ -400,8 +370,8 @@ export function createNewCollectionRoleChanged(
export function createNewTokenRolesCleared(
event_count: i32,
tokenId: BigInt,
byAddress: Address
tokenId: BigInt,
byAddress: Address
): TokenRolesCleared {
let tokenRolesCleared = changetype<TokenRolesCleared>(newMockEvent());
@ -415,10 +385,7 @@ export function createNewTokenRolesCleared(
);
tokenRolesCleared.parameters.push(
new ethereum.EventParam(
'byAddress',
ethereum.Value.fromAddress(byAddress)
)
new ethereum.EventParam('byAddress', ethereum.Value.fromAddress(byAddress))
);
tokenRolesCleared.transaction.hash = Bytes.fromI32(event_count);
@ -470,13 +437,17 @@ export function handleNewAccessPoints(events: NewAccessPoint[]): void {
});
}
export function handleChangeAccessPointCreationStatusList(events: ChangeAccessPointCreationStatus[]): void {
export function handleChangeAccessPointCreationStatusList(
events: ChangeAccessPointCreationStatus[]
): void {
events.forEach((event) => {
handleChangeAccessPointCreationStatus(event);
});
}
export function handleChangeAccessPointNameVerifies(events: ChangeAccessPointNameVerify[]): void {
export function handleChangeAccessPointNameVerifies(
events: ChangeAccessPointNameVerify[]
): void {
events.forEach((event) => {
handleChangeAccessPointNameVerify(event);
});
@ -488,7 +459,9 @@ export function handleTokenRoleChangedList(events: TokenRoleChanged[]): void {
});
}
export function handleCollectionRoleChangedList(events: CollectionRoleChanged[]): void {
export function handleCollectionRoleChangedList(
events: CollectionRoleChanged[]
): void {
events.forEach((event) => {
handleCollectionRoleChanged(event);
});

View File

@ -46,23 +46,13 @@ describe('Owner tests', () => {
createTransferEvent(3, CONTRACT, USER_ONE, BigInt.fromI32(3))
);
transfers.push(
createTransferEvent(
4,
USER_TWO,
USER_ONE,
BigInt.fromI32(1)
)
createTransferEvent(4, USER_TWO, USER_ONE, BigInt.fromI32(1))
);
transfers.push(
createTransferEvent(5, CONTRACT, USER_TWO, BigInt.fromI32(4))
);
transfers.push(
createTransferEvent(
6,
USER_ONE,
USER_TWO,
BigInt.fromI32(0)
)
createTransferEvent(6, USER_ONE, USER_TWO, BigInt.fromI32(0))
);
handleTransfers(transfers);
//logStore();

View File

@ -36,23 +36,13 @@ describe('Transfer tests', () => {
createTransferEvent(3, CONTRACT, USER_ONE, BigInt.fromI32(3))
);
transfers.push(
createTransferEvent(
4,
USER_TWO,
USER_ONE,
BigInt.fromI32(1)
)
createTransferEvent(4, USER_TWO, USER_ONE, BigInt.fromI32(1))
);
transfers.push(
createTransferEvent(5, CONTRACT, USER_TWO, BigInt.fromI32(4))
);
transfers.push(
createTransferEvent(
6,
USER_ONE,
USER_TWO,
BigInt.fromI32(0)
)
createTransferEvent(6, USER_ONE, USER_TWO, BigInt.fromI32(0))
);
handleTransfers(transfers);
// logStore();