iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
Web 3

Web3 X 公共財系列 第 22

Day 22- 細看官方介紹、IHypercertToken及ERC1155使用

  • 分享至 

  • xImage
  •  

官方介紹

Hypercerts as a semi-fungible token (ERC1155)
為了使代幣可識別、可追蹤和可轉讓,hypercerts 被表示為 ERC-1155 代幣。ERC-1155 標準使得單個部署的合約能夠存儲許多 hypercerts,從而在單個命名空間內更簡單地創建、轉移、拆分和合併 hypercerts。作為一種半可替代代幣,每個獨特的代幣代表了一個 hypercert 的所有權的一部分。然後,hypercerts 被表示為一組代幣,其中總所有權總和為 100%。為了方便識別一個代幣屬於哪個 hypercert,我們利用 256 位代幣 ID 的前 128 位來識別 hypercert。同一 hypercert 群組內的所有代幣應共享相同的 ERC-1155 元數據。

https://ithelp.ithome.com.tw/upload/images/20231007/20103331s9vFA0xwzj.png
舉例說明,假設TokenID有2個Bytes,其中第一個byte表示超證ID,最後一個byte表示所有權的比例。Alice可以創建一個新的超證token 0x2301,代表超證0x23的100%所有權。如果Alice想將20%轉讓給Bob,她可以通過鑄造Token: 0x2302並將價值的20%轉移到該token上來執行拆分(SPLIT)操作,這樣Token: 0x2301和0x2302分別代表超證0x23的80%和20%所有權。然後Alice將Token:0x2302轉給BOB。同樣地,他們可以將這兩個Token合併(MERGE)在一起,重新形成代表100%所有權的Token。在這種情況下,0x2301的價值將轉移到0x2302,然後0x2301將被銷毀。

IhypercertToken

 /**
     * AllowAll = Unrestricted
     * DisallowAll = Transfers disabled after minting
     * FromCreatorOnly = Only the original creator can transfer
     */
    /// @dev Transfer restriction policies on hypercerts
    enum TransferRestrictions {
        AllowAll,
        DisallowAll,
        FromCreatorOnly
    }

HypercertMinter.sol

不同的mint方法

  // Mint a semi-fungible token for the impact claim referenced via `uri`
  function mintClaim(
        address account,
        uint256 units,
        string memory _uri,
        TransferRestrictions restrictions
    ) external override whenNotPaused {
        // This enables us to release this restriction in the future
        if (msg.sender != account) revert Errors.NotAllowed();
        uint256 claimID = _mintNewTypeWithToken(account, units, _uri);
        typeRestrictions[claimID] = restrictions;
        emit ClaimStored(claimID, _uri, units);
        
    }
    // Mint semi-fungible tokens for the impact claim referenced via `uri`
     function mintClaimWithFractions(
        address account,
        uint256 units,
        uint256[] calldata fractions,
        string memory _uri,
        TransferRestrictions restrictions
    ) external override whenNotPaused {
        // This enables us to release this restriction in the future
        if (msg.sender != account) revert Errors.NotAllowed();
        //Using sum to compare units and fractions (sanity check)
        if (_getSum(fractions) != units) revert Errors.Invalid();

        uint256 claimID = _mintNewTypeWithTokens(account, fractions, _uri);
        typeRestrictions[claimID] = restrictions;
        emit ClaimStored(claimID, _uri, units);
    }
    
    //Mint a semi-fungible token representing a fraction of the claim
    /// @dev Calls AllowlistMinter to verify `proof`.
    /// @dev Mints the `amount` of units for the hypercert stored under `claimID`
    function mintClaimFromAllowlist(
        address account,
        bytes32[] calldata proof,
        uint256 claimID,
        uint256 units
    ) external whenNotPaused {
        _processClaim(proof, claimID, units);
        _mintToken(account, claimID, units);
    }

Allowlist明天會看到

    /// @notice Register a claim and the whitelist for minting token(s) belonging to that claim
    /// @dev Calls SemiFungible1155 to store the claim referenced in `uri` with amount of `units`
    /// @dev Calls AllowlistMinter to store the `merkleRoot` as proof to authorize claims
    function createAllowlist(
        address account,
        uint256 units,
        bytes32 merkleRoot,
        string memory _uri,
        TransferRestrictions restrictions
    ) external whenNotPaused {
        uint256 claimID = _createTokenType(account, units, _uri);
        _createAllowlist(claimID, merkleRoot, units);
        typeRestrictions[claimID] = restrictions;
        emit ClaimStored(claimID, _uri, units);
    }

ERC1155

沿用了ERC1155Upgradeable、ERC1155BurnableUpgradeable,及ERC1155URIStorageUpgradeable

    /// @dev Bitmask used to expose only upper 128 bits of uint256
    uint256 internal constant TYPE_MASK = type(uint256).max << 128;

    /// @dev Bitmask used to expose only lower 128 bits of uint256
    uint256 internal constant NF_INDEX_MASK = type(uint256).max >> 128;

    uint256 internal constant FRACTION_LIMIT = 253;

TokenID分別對應到現有owners及Creators的mapping(可作為Transfer限制的依據)

/// METADATA

    /// @dev see { openzeppelin-contracts-upgradeable/token/ERC1155/extensions/ERC1155URIStorageUpgradeable.sol }
    /// @dev Always returns the URI for the basetype so that it's managed in one place.
    function uri(
        uint256 tokenID
    ) public view virtual override(ERC1155Upgradeable, ERC1155URIStorageUpgradeable) returns (string memory _uri) {
        // All tokens share the same metadata at the moment
        _uri = ERC1155URIStorageUpgradeable.uri(getBaseType(tokenID));
    }
 /// @dev Split the units of `_tokenID` owned by `account` across `_values`
    /// @dev `_values` must sum to total `units` held at `_tokenID`
    function _splitTokenUnits(address _account, uint256 _tokenID, uint256[] calldata _values) internal {
        if (_values.length > FRACTION_LIMIT || _values.length < 2) revert Errors.ArraySize();
        if (tokenValues[_tokenID] != _getSum(_values)) revert Errors.NotAllowed();

        // Current token
        uint256 _typeID = getBaseType(_tokenID);
        uint256 valueLeft = tokenValues[_tokenID];

        // Prepare batch processing, we want to skip the first entry
        uint256 len = _values.length - 1;

        uint256[] memory typeIDs = new uint256[](len);
        uint256[] memory fromIDs = new uint256[](len);
        uint256[] memory toIDs = new uint256[](len);
        uint256[] memory amounts = new uint256[](len);
        uint256[] memory values = new uint256[](len);

        {
            uint256[] memory _valuesCache = _values;
            uint256 swapValue = _valuesCache[len];
            _valuesCache[len] = _valuesCache[0];
            _valuesCache[0] = swapValue;

            for (uint256 i; i < len; ) {
                _notMaxItem(maxIndex[_typeID]);

                typeIDs[i] = _typeID;
                fromIDs[i] = _tokenID;
                toIDs[i] = _typeID + ++maxIndex[_typeID];
                amounts[i] = 1;
                values[i] = _valuesCache[i];

                unchecked {
                    ++i;
                }
            }
        }

        _beforeUnitTransfer(_msgSender(), _account, fromIDs, toIDs, values, "");

        for (uint256 i; i < len; ) {
            valueLeft -= values[i];

            tokenValues[toIDs[i]] = values[i];

            unchecked {
                ++i;
            }
        }

        tokenValues[_tokenID] = valueLeft;

        _mintBatch(_account, toIDs, amounts, "");

        emit BatchValueTransfer(typeIDs, fromIDs, toIDs, values);
    }

    /// @dev Merge the units of `_fractionIDs`.
    /// @dev Base type of `_fractionIDs` must be identical for all tokens.
    function _mergeTokensUnits(address _account, uint256[] memory _fractionIDs) internal {
        if (_fractionIDs.length > FRACTION_LIMIT || _fractionIDs.length < 2) {
            revert Errors.ArraySize();
        }
        uint256 len = _fractionIDs.length - 1;

        uint256 target = _fractionIDs[len];

        uint256 _totalValue;
        uint256[] memory fromIDs = new uint256[](len);
        uint256[] memory toIDs = new uint256[](len);
        uint256[] memory values = new uint256[](len);
        uint256[] memory amounts = new uint256[](len);

        {
            for (uint256 i; i < len; ) {
                uint256 _fractionID = _fractionIDs[i];
                fromIDs[i] = _fractionID;
                toIDs[i] = target;
                amounts[i] = 1;
                values[i] = tokenValues[_fractionID];

                unchecked {
                    ++i;
                }
            }
        }

        _beforeUnitTransfer(_msgSender(), _account, fromIDs, toIDs, values, "");

        for (uint256 i; i < len; ) {
            _totalValue += values[i];

            delete tokenValues[fromIDs[i]];
            unchecked {
                ++i;
            }
        }

        tokenValues[target] += _totalValue;

        _burnBatch(_account, fromIDs, amounts);
    }


上一篇
Day 21 - Hypercert初探
下一篇
Day 23 - IAllowlist、AllowlistMinter、Murky及HypercertMinter.sol
系列文
Web3 X 公共財30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言