Wrapper Architecture
Overview
Integral Components
The Wrapper module employs a suite of essential and supporting components to enable its functionalities. To grasp the mechanics of this module, let's delve into the explanation of its foundational contracts:
Wrapper
The Wrapper smart contract is the primary gateway for wrapping and unwrapping external assets into ODCs, streamlining the process through interactions with the corresponding External ERC Property Manager implementation tailored to each asset type involved. Integrating new asset types consists of registering the respective External ERC PM implementations in the Wrapper, which is exclusively facilitated by the owner (i.e., deployer of the Nexera Protocol).
/**
* @notice RegisterNewType
* @dev This function is called by the owner to register a new type of asset.
* @param propertyManager The address of the External ERC PM responsible for handling the newly registered type.
* @param isFungible Flag indicating whether the asset type is Fungible (true) or Non-Fungible (false).
*/
function registerNewType(IExternalTokenPropertyManager propertyManager, bool isFungible) external onlyOwner;
Upon registration, each integrated asset type is allocated a distinctive code ID. These unique identifiers serve as pivotal keys, enabling seamless linkage to the corresponding External ERC PM interface.
/// @dev Mapping from asset type code ID to the associated External ERC PM.
mapping(uint256 => IExternalTokenPropertyManager) public typeContractPm;
Currently, the Wrapper stores the following codes for each asset type:
1
→ for ERC-20 (Fungible) assets.2
→ for ERC-721 (Non-fungible) assets.3
→ for ERC-1155 (Semi-fungible) assets.
In the following sections, we introduce the functions provided by the Wrapper smart contract for user interaction.
Wrap
Users can call the wrap()
function to wrap specified assets inside a targeted ODC.
/**
* @notice This struct receives all parameters for the `wrap` function.
* @param tokens The addresses of the targeted assets to wrap.
* @param amounts The amount of each asset to wrap (if applicable, i.e., for fungible assets).
* @param ids The ID of each asset to wrap (if applicable, i.e., for non-fungible and semi-fungible assets).
* @param types The codes indicating the asset types (e.g., `1` for ERC-20, `2` for ERC-721 etc.).
* @param unlockTimestamps Unix timestamps specifying when each asset can be unwrapped (or partially unwrapped).
* @param existingOuidToUse The ID of the targeted ODC (Use `0` value to mint a new ODC).
*/
struct WrapData {
address[] tokens;
uint256[] amounts;
uint256[] ids;
uint256[] types;
uint256[] unlockTimestamps;
uint256 existingOuidToUse;
}
/**
* @notice Wrap
* @dev This function is called by the users to wrap assets inside an ODC.
* @param data The data used when wrapping.
* @return The ID of the ODC that the assets were wrapped.
* @return The indices of the generated Restrictions within the array of Restrictions associated with the ODC.
*/
function wrap(WrapData memory data) external returns (uint256, uint256[] memory);
Rewrap
Users can call the rewrap()
function to extend the amounts of wrapped Fungible and Semi-Fungible assets within an ODC.
- Only Fungible and Semi-Fungible assets can be rewrapped.
- Caller →
msg.sender
must be the owner of the targeted ODC.
/**
* @dev This struct receives all parameters for the `rewrap` function.
* @param ouid The ID of the ODC to rewrap assets to.
* @param tokens The addresses of the targeted fungible and/or semi-fungible assets to wrap.
* @param amounts The amount of each asset to wrap.
* @param types The codes indicating the asset types (e.g., `1` for ERC-20, `2` for ERC-721, etc.).
* @param unlockTimestamps Unix timestamps specifying when each asset can be unwrapped (or partially unwrapped).
* @param restrictionIds The indices of the Restrictions associated with the targeted wrapped assets.
* @param tokenIds The IDs of the Semi-Fungible assets (if applicable).
*/
struct RewrapData {
uint256 ouid;
address[] tokens;
uint256[] amounts;
uint256[] types;
uint256[] unlockTimestamps;
uint256[] restrictionIds;
uint256[] tokenIds;
}
/**
* @notice Rewrap
* @dev Called by the users to extend the amounts of already wrapped Fungible and/or Semi-fungible assets.
* @param data The data used when rewrapping.
* @return The ID of the ODC that the assets were rewrapped.
* @return The indices of the generated Restrictions within the array of Restrictions associated with the ODC.
*/
function rewrap(RewrapData memory data) external returns (uint256, uint256[] memory);
Unwrap
Users can call the unwrap()
function to fully unwrap specified assets from a targeted ODC.
Caller →
msg.sender
must be the owner of the targeted ODC and will be the receiver of the unwrapped assets.
/**
* @dev This struct receives all parameters for the `unwrap` function.
* @param ouid The ID of the ODC to unwrap assets from.
* @param restrictionIds The indices of the Restrictions associated with the targeted wrapped assets.
* @param tokens The addresses of the assets to unwrap.
* @param types The codes indicating the asset types (e.g., `1` for ERC-20, `2` for ERC-721, etc.).
* @param tokenIds The IDs of the assets to unwrap (only applicable for Non-Fungible and Semi-Fungible assets).
*/
struct UnwrapData {
uint256 ouid;
uint256[] restrictionIds;
address[] tokens;
uint256[] types;
uint256[] tokenIds;
}
/**
* @notice Unwrap
* @dev Called by the users to fully unwrap specified assets from a targeted ODC.
* @param data The data used when unwrapping.
*/
function unwrap(UnwrapData memory data) external;
UnwrapPartially
Users can call the unwrapPartially()
function to unwrap percentages of specified assets from a targeted ODC.
- Only Fungible and Semi-Fungible assets can be partially unwrapped.
- Percentages are parsed with 18 decimals (i.e., 100% == 1e18).
- When partially unwrapping Semi-Fungible assets (e.g., ERC-1155), percentages that yield non-integer amounts result in rounding down to the nearest whole token. For instance, unwrapping 58% of a total of 70 ERC-1155 tokens results in 40 tokens being unwrapped.
- Caller →
msg.sender
must be the owner of the targeted ODC.
/**
* @notice This struct receives all parameters for the `unwrapPartially` function.
* @dev If `amountPercentage` is non-zero, then the same percentage is used for all targeted
* wrapped assets. Otherwise, the `amountPercentages` array's members are used.
* @param ouid The ID of the ODC to partially unwrap assets from.
* @param tokens The addresses of the targeted fungible and/or semi-fungible wrapped assets.
* @param types The codes indicating the asset types (e.g., `1` for ERC-20, `3` for ERC-1155).
* @param restrictionIds The restriction indices of the targeted wrapped assets.
* @param tokenIds The token IDs of the semi-fungible wrapped assets (if applicable).
* @param amountPercentages The percentages to be unwrapped for each asset, in case they differ.
* @param amountPercentage The percentage to be unwrapped for each asset, if the same for all assets.
* @param account The address that will receive the unwrapped assets.
*/
struct UnwrapPartiallyData {
uint256 ouid;
address[] tokens;
uint256[] types;
uint256[] restrictionIds;
uint256[] tokenIds;
uint256[] amountPercentages;
uint256 amountPercentage;
address account;
}
/**
* @notice Unwrap Partially
* @dev This function is called by the users to unwrap percentages of specified assets from a targeted ODC.
* @param data The data used when unwrapping partially.
* @return The ID of the ODC from which the assets were partially unwrapped.
* @return The indices of the generated Restrictions within the array of Restrictions associated with the ODC.
*/
function unwrapPartially(UnwrapPartiallyData memory data) external returns (uint256, uint256[] memory);
External ERC Property Managers
The External ERC Property Managers are custom implementations selectively employed by the Wrapper smart contract based on the asset type involved. They are crucial in facilitating the seamless wrapping and unwrapping of assets into and from ODCs by utilizing Properties and token-related Restrictions within the ODC system. Each implementation manages a distinct Category of Properties, dynamically handling essential information pertinent to the type of assets they interact with.
Currently, the following dedicated implementations correspond to supported asset types:
- ExternalErc20PropertyManager for ERC-20 tokens.
- ExternalErc721PropertyManager for ERC-721 tokens.
- ExternalErc1155PropertyManager for ERC-1155 tokens.
While these implementations cover the currently supported types, new implementations can be developed for any other ERC token standard, whether existing or future.
The following sections provide an overview of the underlying mechanics featured in the External ERC Property Managers.
Wrap Mechanics
To facilitate the wrapping process of an external asset into an On-Chain Data Container (ODC), the associated External ERC Property Manager (PM) performs the following tasks:
-
Data Validation: The PM verifies the data provided by the Wrapper smart contract, including the token address, amount (if applicable), token ID (if applicable), and unlock timestamp, ensuring the validity of the wrapping process.
-
Asset Allocation: The PM securely transfers the specified token from the user to itself.
-
Approval: The PM approves the ODC contract for the received token.
-
Property Generation: A unique Property ID is calculated based on the PM's and token's address. If the Property doesn't exist (i.e., the token involved has never been wrapped before), it is registered within the system under the designated Category managed by the PM.
-
Restriction Application: A token-related Restriction corresponding to the asset type and the specified unlock timestamp is created and applied to the Property, which is added to the ODC.
-
Internal Hook Activation: The application of the Restriction triggers an associated internal hook programmed to securely transfer the token from the PM to the ODC contract for locking.
Rewrap Mechanics
To facilitate the rewrapping process of an external asset into an On-Chain Data Container (ODC), the associated External ERC Property Manager (PM) performs the following tasks:
-
Data Validation: The PM verifies the data provided by the Wrapper smart contract, including the token address, amount to extend, and unlock timestamp, ensuring the integrity of the rewrapping process.
-
Asset Allocation: The PM securely transfers the specified token amount from the user to itself.
-
Property Verification: The PM confirms the existence of the Property associated with the token, verifying if the token has been previously wrapped.
-
Restriction Removal: The existing token-related Restriction associated with the Property is removed. The removal of the Restriction triggers an associated internal hook programmed to securely transfer the wrapped token amount from the ODC contract to the PM. The PM also caches its token balance before the removal of the Restriction.
-
Relock Amount Calculation: After removing Restriction, the PM calculates the token amount to be relocked. This calculation includes the specified amount to extend and the difference between the token balance after and before removing the Restriction.
-
Approval: The PM approves the ODC contract for the calculated token relock amount.
-
Restriction Application: A new token-related Restriction is applied to the Property, specifying the calculated token amount and the new unlock timestamp. The application of the Restriction triggers an associated internal hook programmed to securely transfer the calculated token relock amount from the PM to the ODC contract for locking.
Unwrap Mechanics
To facilitate the unwrapping process of an external asset from an On-Chain Data Container (ODC), the associated External ERC Property Manager (PM) performs the following tasks:
-
Data Validation: The PM verifies the data provided by the Wrapper smart contract, including the token address, the token ID (if applicable), and the receiver address, ensuring the integrity of the unwrapping process.
-
Property Verification: The PM confirms the existence of the Property associated with the token, verifying if the token has been previously wrapped.
-
Restriction Removal: The existing token-related Restriction associated with the Property is removed. The removal of the Restriction triggers an associated internal hook programmed to securely transfer the wrapped asset from the ODC contract to the PM. The PM also caches its token balance before the removal of the Restriction.
-
Asset Allocation: After removing the Restriction, the function calculates the amount (if applicable) of previously wrapped tokens based on the difference between the token balance after and before the removal. It then securely transfers the asset back to the designated receiver account.
UnwrapPartially Mechanics
To facilitate the partially unwrapping process of an external asset from an On-Chain Data Container (ODC), the associated External ERC Property Manager (PM) performs the following tasks:
-
Data Validation: The PM verifies the data provided by the Wrapper smart contract, including the token address, the token ID (if applicable), and percentage value, ensuring the integrity of the process.
-
Property Verification: The PM confirms the existence of the Property associated with the token, verifying if the token has been previously wrapped.
-
Restriction Removal: The existing token-related Restriction associated with the Property is removed. The removal of the Restriction triggers an associated internal hook programmed to securely transfer the wrapped asset from the ODC contract to the PM. The PM also caches its token balance before removing the Restriction.
-
Unwrap Amount Calculation: The PM calculates the difference in token balance before and after removing the Restriction to determine the total amount available for partial unwrapping. Based on the specified percentage value, it computes the amount of tokens to be unwrapped.
-
Asset Allocation: The PM securely transfers the calculated unwrap amount to the designated receiver account.
-
Restriction Application: A new token-related Restriction is applied to the Property, reflecting the remaining amount (i.e., totalAmount - UnwrapAmount). The application of the Restriction triggers an associated internal hook programmed to securely transfer the remaining amount from the PM to the ODC contract for locking.