๐Ÿ’„Other Topics

UX, Security, Future...

For UX, all Object initially use setApproveForAll to PhiMap contract

This function returns whether a specific account is approved by a specific operator for all tokens. If the operator is equal to phiMapAddress, the function always returns true.

    // this method always allow PhiMap contract to move Object
    // then users don't need to call `setApprovalForAll`
    // reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol#L110
    function isApprovedForAll(address account, address operator) public view override returns (bool) {
        if (operator == phiMapAddress) {
            return true;
        return super.isApprovedForAll(account, operator);

We introduce superApprove for UX perspective. These are all implemented in object contracts(Quest, Premium, Free, Wallpaper, and Baseplate).

Control Sale Status by SetOpenForSale Method

This function called "setOpenForSale" takes two arguments: a token ID of type "uint256" and a boolean value "check". The function sets the "forSale" property of the object with the specified token ID to the value of "check".

function setOpenForSale(uint256 tokenId, bool check) public virtual onlyOwner {
        allObjects[tokenId].forSale = check;
        emit SetOpenForSale(tokenId, check);

With this function, we can control whether a user can claim or not. Essentially, we respect the community's opinion, but we might change it.


You can bulk purchase Objects other than Quest Object and also deposit to Map at the same time. (*Gas fees may be expensive when Polygon network is congested especially operate many objects.)

     * @title shopBuyAndDepositObject
     * @param receiverAddress : receive address
     * @param ftokenIds : free object tokenId list
     * @param ptokenIds : premium object tokenId list
     * @param wtokenIds : wallpaper tokenId list
     * @param depositContractAddresses : array of deposit contract addresses
     * @param depositTokenIds :  array of deposit token ids
     * @param depositAmounts :  array of deposit amounts
    function shopBuyAndDepositObject(
        string memory name,
        uint256[] memory ftokenIds,
        uint256[] memory ptokenIds,
        uint256[] memory wtokenIds,
        uint256[] memory btokenIds,
        address[] memory depositContractAddresses,
        uint256[] memory depositTokenIds,
        uint256[] memory depositAmounts
    ) external payable nonReentrant

PhiShop: '0xc6E5240054DBE92BDe25546cF0C72dC499c41Ca8' https://polygonscan.com/address/0xc6E5240054DBE92BDe25546cF0C72dC499c41Ca8


All object contracts are managed by Owners. Currently, only timelock contracts have owner privileges. Methods with the 'onlyowner' modifier can only be executed through the Timelock contract.

     * @dev Set the address of the owner.
    function setOwner(address newOwner) external virtual onlyOwner {
        _owners[newOwner] = true;
        emit OwnershipGranted(msg.sender, newOwner);

     * @dev Remove the address of the owner list.
    function removeOwner(address oldOwner) external virtual onlyOwner {
        _owners[oldOwner] = false;
        emit OwnershipRemoved(msg.sender, oldOwner);


EIP2981 is a proposal for a royalty payment mechanism in the Ethereum network.

The proposal specifies a way for contract creators to receive a share of the transaction fees when their contracts are used. This would allow creators to be rewarded for their contributions to the Ethereum ecosystem. All object contracts have royalty functions based on EIP2981.

    /* -------------------------------------------------------------------------- */
    /*                                  ROYALTIES                                 */
    /* -------------------------------------------------------------------------- */
    /* --------------------------------- PUBLIC --------------------------------- */
    /// @notice EIP2981 royalty standard
    function royaltyInfo(uint256, uint256 salePrice)
        returns (address receiver, uint256 royaltyAmount)
        return (address(this), (salePrice * secondaryRoyalty) / 10000);

    /// @notice Receive royalties
    receive() external payable {

    /// @notice Adds funds to the payment balance for the owner.
    /// @param amount The amount to add to the balance.
    function addToOwnerBalance(uint256 amount) internal {
        emit PaymentReceivedOwner(amount);
        paymentBalanceOwner += amount;

    /* ---------------------------------- ADMIN --------------------------------- */
    /// @notice set primary market ratio.
    function setRoyalityFee(uint256 newRoyalityFee) external onlyOwner {
        royalityFee = newRoyalityFee;
        emit SetRoyalityFee(newRoyalityFee);

    function setSecondaryRoyalityFee(uint256 newSecondaryRoyalty) external onlyOwner {
        secondaryRoyalty = newSecondaryRoyalty;
        emit SetSecondaryRoyalityFee(newSecondaryRoyalty);

    /// @notice Sends you your full available balance.
    /// @param withdrawTo The address to send the balance to.
    function withdrawOwnerBalance(address withdrawTo) external onlyOwner nonReentrant {
        require(withdrawTo != address(0), "cant set address(0)");
        if (paymentBalanceOwner == 0) revert PaymentBalanceZero();
        uint256 balance = paymentBalanceOwner;
        paymentBalanceOwner = 0;

        (bool success, ) = withdrawTo.call{ value: balance }("");
        if (!success) revert PaymentBalanceZero();

        emit PaymentWithdrawnOwner(balance);


We love board games and video games... In the past, we have tried a theme in Encode Hackthon and published it as a MetaMaterial. Of course, we also think that it is one feature element that may be deployed in PHI.

Last updated