DCIPs/assets/eip-6220/contracts/utils/MultiAssetRenderUtils.sol

195 lines
6.2 KiB
Solidity

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.16;
import "../IERC5773.sol";
error TokenHasNoAssets();
/**
* @title MultiAssetRenderUtils
* @author RMRK team
*/
contract MultiAssetRenderUtils {
uint16 private constant _LOWEST_POSSIBLE_PRIORITY = 2**16 - 1;
/**
* @notice The structure used to display information about an active asset.
* @return id ID of the asset
* @return priority The priority assigned to the asset
* @return metadata The metadata URI of the asset
*/
struct ActiveAsset {
uint64 id;
uint16 priority;
string metadata;
}
/**
* @notice The structure used to display information about a pending asset.
* @return id ID of the asset
* @return acceptRejectIndex An index to use in order to accept or reject the given asset
* @return replacesAssetWithId ID of the asset that would be replaced if this asset gets accepted
* @return metadata The metadata URI of the asset
*/
struct PendingAsset {
uint64 id;
uint128 acceptRejectIndex;
uint64 replacesAssetWithId;
string metadata;
}
/**
* @notice Used to get the active assets of the given token.
* @dev The full `ActiveAsset` looks like this:
* [
* id,
* priority,
* metadata
* ]
* @param target Address of the smart contract of the given token
* @param tokenId ID of the token to retrieve the active assets for
* @return struct[] An array of ActiveAssets present on the given token
*/
function getActiveAssets(address target, uint256 tokenId)
public
view
virtual
returns (ActiveAsset[] memory)
{
IERC5773 target_ = IERC5773(target);
uint64[] memory assets = target_.getActiveAssets(tokenId);
uint16[] memory priorities = target_.getActiveAssetPriorities(tokenId);
uint256 len = assets.length;
if (len == 0) {
revert TokenHasNoAssets();
}
ActiveAsset[] memory activeAssets = new ActiveAsset[](len);
string memory metadata;
for (uint256 i; i < len; ) {
metadata = target_.getAssetMetadata(tokenId, assets[i]);
activeAssets[i] = ActiveAsset({
id: assets[i],
priority: priorities[i],
metadata: metadata
});
unchecked {
++i;
}
}
return activeAssets;
}
/**
* @notice Used to get the pending assets of the given token.
* @dev The full `PendingAsset` looks like this:
* [
* id,
* acceptRejectIndex,
* replacesAssetWithId,
* metadata
* ]
* @param target Address of the smart contract of the given token
* @param tokenId ID of the token to retrieve the pending assets for
* @return struct[] An array of PendingAssets present on the given token
*/
function getPendingAssets(address target, uint256 tokenId)
public
view
virtual
returns (PendingAsset[] memory)
{
IERC5773 target_ = IERC5773(target);
uint64[] memory assets = target_.getPendingAssets(tokenId);
uint256 len = assets.length;
if (len == 0) {
revert TokenHasNoAssets();
}
PendingAsset[] memory pendingAssets = new PendingAsset[](len);
string memory metadata;
uint64 replacesAssetWithId;
for (uint256 i; i < len; ) {
metadata = target_.getAssetMetadata(tokenId, assets[i]);
replacesAssetWithId = target_.getAssetReplacements(
tokenId,
assets[i]
);
pendingAssets[i] = PendingAsset({
id: assets[i],
acceptRejectIndex: uint128(i),
replacesAssetWithId: replacesAssetWithId,
metadata: metadata
});
unchecked {
++i;
}
}
return pendingAssets;
}
/**
* @notice Used to retrieve the metadata URI of specified assets in the specified token.
* @dev Requirements:
*
* - `assetIds` must exist.
* @param target Address of the smart contract of the given token
* @param tokenId ID of the token to retrieve the specified assets for
* @param assetIds[] An array of asset IDs for which to retrieve the metadata URIs
* @return string[] An array of metadata URIs belonging to specified assets
*/
function getAssetsById(
address target,
uint256 tokenId,
uint64[] calldata assetIds
) public view virtual returns (string[] memory) {
IERC5773 target_ = IERC5773(target);
uint256 len = assetIds.length;
string[] memory assets = new string[](len);
for (uint256 i; i < len; ) {
assets[i] = target_.getAssetMetadata(tokenId, assetIds[i]);
unchecked {
++i;
}
}
return assets;
}
/**
* @notice Used to retrieve the metadata URI of the specified token's asset with the highest priority.
* @param target Address of the smart contract of the given token
* @param tokenId ID of the token for which to retrieve the metadata URI of the asset with the highest priority
* @return string The metadata URI of the asset with the highest priority
*/
function getTopAssetMetaForToken(address target, uint256 tokenId)
external
view
returns (string memory)
{
IERC5773 target_ = IERC5773(target);
uint16[] memory priorities = target_.getActiveAssetPriorities(tokenId);
uint64[] memory assets = target_.getActiveAssets(tokenId);
uint256 len = priorities.length;
if (len == 0) {
revert TokenHasNoAssets();
}
uint16 maxPriority = _LOWEST_POSSIBLE_PRIORITY;
uint64 maxPriorityAsset;
for (uint64 i; i < len; ) {
uint16 currentPrio = priorities[i];
if (currentPrio < maxPriority) {
maxPriority = currentPrio;
maxPriorityAsset = assets[i];
}
unchecked {
++i;
}
}
return target_.getAssetMetadata(tokenId, maxPriorityAsset);
}
}