195 lines
6.2 KiB
Solidity
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);
|
||
|
}
|
||
|
}
|