import { ethers } from "ethers";
import { MyriaClient } from "../clients/MyriaClient";
import { AssetAPI } from "../core/apis/asset.api";
import { AssetMarketpAPI } from "../core/apis/asset.marketp.api";
import { QueryAssetParams } from "../types";
import { APIResponseType } from "../types/APIResponseType";
import {
AssetByCollectionIdResponse,
AssetDetailsResponse, AssetDetailsResponseData, AssetHaveOrderResponse, AssetOwnerPublicKeyResponse,
AssetStarkKeyResponse,
AssetVaultDetailsResponseAPI, CollectionByIdDetailsParams,
CollectionDetailsParams, NftAssetEqualMetadataResponse,
QueryAssetParamsByOwner,
QueryAssetRequestAPIParams,
QueryAssetsWithCollectionResponse,
QueryEqualMetadataNftAssetParams,
RecrawlBatchNftMetadataParams,
RecrawlBatchNftMetadataResponse,
UpdateAssetMetadataParams,
UpdatedAssetParams
} from "../types/AssetTypes";
import {
CommonPaginateDataTypes,
PagingDataParams
} from "../types/CommonTypes";
import { MintedAssetType } from "../types/MintTypes";
import { CommonModule } from "./CommonModule";
/**
* Create OnchainAssetManager instance object
* @class OnchainAssetManager
* @param {MyriaClient} MyriaClient Interface of Myria Client
* @example <caption>Constructor for OnchainAssetManager</caption>
*
*
// Approach #1
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const moduleFactory = ModuleFactory.getInstance(mClient);
const onchainAssetManager = moduleFactory.getOnchainAssetManager();
// Approach #2
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
*/
export class OnchainAssetManager {
private assetApi: AssetAPI;
private assetMarketpApi: AssetMarketpAPI;
private commonModule: CommonModule;
public client: MyriaClient;
constructor(client: MyriaClient) {
this.client = client;
this.assetApi = new AssetAPI(client.env);
this.assetMarketpApi = new AssetMarketpAPI(client.env);
this.commonModule = new CommonModule(client);
}
public async getListAssetsByStarkKey(starkKey: string): Promise<any> {
const assetVaults = await this.assetApi.getAssetVaultsByStarkKey(starkKey);
return assetVaults;
}
public async getAssetVaultDetails(
starkKey: string,
assetId: string
): Promise<APIResponseType<AssetVaultDetailsResponseAPI> | undefined> {
const assetVaultDetails = await this.assetApi.getAssetVaultDetails({
starkKey,
assetId,
});
return assetVaultDetails;
}
// /**
// *
// * @description Get all of minted NFTs (MINTABLE_ERC721) for specific stark key
// * @param {string} starkKey Stark public key of user
// * @returns
// */
public async getNftAssets(
starkKey: string
): Promise<APIResponseType<MintedAssetType[]> | undefined> {
const nftAssets = await this.assetApi.getNftAssets(starkKey);
return nftAssets;
}
/**
* @description Get list of selling NFTs/assets
* @param {PagingDataParams=} data requested the list assets/NFTs in paging format
* @returns {CommonPaginateDataTypes<AssetDetailsResponse[]> | undefined} The response data for list assets details
* @example <caption>Staging example code for getAssets</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
const queryAssets: PagingDataParams = {
limit: 50,
page: 1
};
const assetsData = await onchainAssetManager.getAssets(queryAssets);
*/
public async getAssets(
data?: PagingDataParams
): Promise<
APIResponseType<CommonPaginateDataTypes<AssetDetailsResponse[]>> | undefined> {
const result = await this.assetMarketpApi.requestGetAsset(data);
return result;
}
/**
* @description Get NFTs asset details by ID
* @param {string} assetId The ID of the asset/NFT
* @throws {string} Exception: AssetId is required
* @returns {APIResponseType<AssetDetailsResponse>} The full information of the NFTs/Assets
* @example <caption>Staging example code for getAssetById</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
const requestAssetDetails = {
assetId: 1, // Asset id number
}
const assetsData: AssetDetailsResponse = await onchainAssetManager.getAssetById(requestAssetDetails);
*/
public async getAssetById(
assetId: string
): Promise<APIResponseType<AssetDetailsResponse> | undefined> {
if (!assetId) {
throw new Error("AssetId is required");
} else {
const result = await this.assetMarketpApi.requestGetAssetById(assetId);
return result;
}
}
/**
* @description Refresh metadata for the NFTs and sync up with latest off-chain data for specific NFTs
* @param {string} assetId The ID of the asset/NFT
* @param {string} starkKey The stark key owner of the asset to request refresh
* @throws {string} Exception: Asset Id is required
* @throws {string} Exception: Stark Key is required
* @returns {APIResponseType<AssetDetailsResponse> | undefined} The full information of the refreshed NFTs/Assets
* @example <caption>Staging example code for refreshAssetMetadata({})</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
const assetId = 100;
const starkKey = '0xfb....'; // Stark key of user;
const refreshNftResponse: APIResponseType<AssetDetailsResponse> | undefined = await onchainAssetManager.refreshAssetMetadata(assetId, starkKey);
*/
public async refreshAssetMetadata(
assetId: string,
starkKey: string
): Promise<APIResponseType<AssetDetailsResponse> | undefined> {
if (!assetId) {
throw new Error("Asset Id is required");
}
if (!starkKey) {
throw new Error("Stark Key is required");
}
const result = await this.assetMarketpApi.requestSyncAttributeMetadata(assetId, starkKey);
return result;
}
public async getAssetsByOwnerPublicKey(
ownerPublicKey: string
): Promise<APIResponseType<AssetOwnerPublicKeyResponse> | undefined> {
if (!ownerPublicKey) {
throw new Error("OwnerPublicKey is required");
} else {
const result = await this.assetMarketpApi.requestAssetOwnerPublicKey(
ownerPublicKey
);
return result;
}
}
public async getAssetsByCollectionId(
payload: CollectionDetailsParams
): Promise<
| APIResponseType<CommonPaginateDataTypes<AssetByCollectionIdResponse>>
| undefined
> {
if (!payload.collectionId) {
throw new Error("OwnerPublicKey is required");
}
const result = await this.assetMarketpApi.getAssetByCollectionId(payload);
return result;
}
/**
* @description Query the assets / NFTs and apply filtering (mostly for NFTs querying based on metadata)
* @param {CollectionByIdDetailsParams} payload Query the assets / NFTs request with collection IDs and filterField, filterValue
* @throws {string} Exception: Owner public key is required
* @returns {APIResponseType<CommonPaginateDataTypes<AssetByCollectionIdResponse>>| undefined} Get list assets of NFTs
* @example <caption>Staging example code for getAssetsWithFilter</caption>
*
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
const queryAssetsPayload: CollectionByIdDetailsParams = {
sortingField: 'created_at',
orderBy: AssetOrderBy.DESC,
filterField: 'metadata',
filterValue: '{body: ["Mustard"]}',
collectionId: 10,
};
const listFilteredNfts = await onchainAssetManager.getAssetsWithFilter(queryAssetsPayload);
*/
public async getAssetsWithFilter(
payload: CollectionByIdDetailsParams
): Promise<
| APIResponseType<CommonPaginateDataTypes<AssetByCollectionIdResponse>>
| undefined
> {
if (!payload.collectionId) {
throw new Error("Owner public key is required");
}
const result = await this.assetMarketpApi.requestAssetByCollectionId(
payload
);
return result;
}
/**
* @description Get all of NFTs/Assets belonging to the specific users (StarkKey)
* @param {string} starkKey The stark key owner for the assets NFTs
* @param {number?} page The index of page (1,2,3,...etc)
* @param {number?} limit The total number of limited items per page
* @throws {string} Exception: Stark Key is required
* @returns {CommonPaginateDataTypes<AssetStarkKeyResponse> | undefined} The full information of NFTs/Assets list (Id, price, order, status...)
* @example <caption>Staging example code for getAssetByStarkKey()</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
const starkKey = '0xfb...'; // User stark key
const page = 1;
const limit = 100;
const listFilteredNfts = await onchainAssetManager.getAssetByStarkKey(starkKey, page, limit);
*/
public async getAssetByStarkKey(
starkKey: string,
page?: number,
limit?: number
): Promise<APIResponseType<CommonPaginateDataTypes<AssetStarkKeyResponse[]>> | undefined> {
if (!starkKey) {
throw new Error("Stark Key is required");
} else {
const pageNumber = page || 1;
const limitNumber = limit || 10;
const result = await this.assetMarketpApi.requestAssetStarkKey(
starkKey,
pageNumber,
limitNumber
);
return result;
}
}
/**
* @description Query the assets list by the collection owner
* @param {QueryAssetParamsByOwner} queryAssetParams
* @throws {string} Exception: Collection IDs are required
* @throws {string} Exception: Owner stark key is required
* @returns {QueryAssetsWithCollectionResponse} The assets list data includes collections / NFTs data of all and specific players
* @example <caption>Staging example code for queryAssetsByCollectionOwner({})</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
const queryNftPayload: QueryAssetParamsByOwner = {
starkKey: '0xfb...',
ownerWalletAddress: '0xab....', // Owner of the nfts
collectionIds: [1,2,3,5], // The list of collections ID that partners have in myria system
walletAddress: '0xa9a......', // Example of user's wallet address - it's optional, if wallet address is not passed, it's default to return all of nft's data for different users wallet address
page: 1,
limit: 100,
};
const listFilteredNfts = await onchainAssetManager.queryAssetsByCollectionOwner(queryNftPayload);
*/
public async queryAssetsByCollectionOwner(
queryAssetParams: QueryAssetParamsByOwner
): Promise<APIResponseType<CommonPaginateDataTypes<QueryAssetsWithCollectionResponse>> | undefined> {
if (!queryAssetParams.collectionIds || queryAssetParams.collectionIds.length === 0) {
throw new Error("Collection IDs are required")
}
if (!queryAssetParams.starkKey) {
throw new Error("Owner stark key is required");
}
const requestAssetsAPIParams: QueryAssetRequestAPIParams = {
starkKey: queryAssetParams.starkKey,
collectionIds: queryAssetParams.collectionIds,
walletAddress: queryAssetParams.walletAddress,
limit: queryAssetParams.limit,
page: queryAssetParams.page
};
const result = await this.assetMarketpApi.requestAssetsByCollectionOwner(requestAssetsAPIParams);
if (!result) {
throw new Error("Request assets by collection owner failed");
}
return result;
}
public async updateAssetById(
assetId: string,
data: UpdatedAssetParams
): Promise<APIResponseType<UpdatedAssetParams[]> | undefined> {
let assetIdData;
if (!assetId) {
throw new Error("AssetId is required");
}
if (!data.starkKey) {
throw new Error("StarkKey is required");
}
if (!data.uri) {
throw new Error("Uri is required");
}
if (!data.assetType) {
throw new Error("AssetType is required");
}
if (!data.tokenId) {
throw new Error("TokenId is required");
}
if (!data.tokenAddress) {
throw new Error("TokenAddress is required");
}
if (!data.collectionId) {
throw new Error("CollectionId is required");
}
if (!data.status) {
throw new Error("Status is required");
}
try {
const result = await this.assetMarketpApi.requestUpdateAssetId(
assetId,
data
);
if (result?.status === "success") {
assetIdData = result;
}
} catch (error) {
throw new Error("UpdateAssetIdMarketp failure");
}
return assetIdData;
}
public async updateAssetMetadataByAssetId(
assetId: number,
data: UpdateAssetMetadataParams
): Promise<APIResponseType<AssetDetailsResponseData[]> | undefined> {
let assetIdMetadata;
if (!assetId) {
throw new Error("AssetId is required");
}
if (!data.name) {
throw new Error("Name is required");
}
if (!data.animationUrl) {
throw new Error("AnimationUrl is required");
}
if (!data.animationUrlMimeType) {
throw new Error("AnimationUrlMimeType is required");
}
if (!data.imageUrl) {
throw new Error("Image is required");
}
if (!data.attack) {
throw new Error("Attack is required");
}
if (!data.collectable) {
throw new Error("Collectable is required");
}
if (!data.god) {
throw new Error("God is required");
}
if (!data.element) {
throw new Error("Element is required");
}
if (!data.product) {
throw new Error("Product is required");
}
if (!data.rarity) {
throw new Error("Rarity is required");
}
if (!data.type) {
throw new Error("Type is required");
}
try {
const result = await this.assetMarketpApi.requestUpdateAssetIdMetadata(
assetId,
data
);
if (result?.status === "success") {
assetIdMetadata = result;
}
} catch (error) {
throw new Error("UpdateAssetIdMetadataMarketp failure");
}
return assetIdMetadata;
}
/**
* @description Get NFTs with same metadata
* @param {QueryEqualMetadataNftAssetParams} payload The payload to request the same assets/NFTs
* @throws {string} Exception: AssetId is required
* @returns {CommonPaginateDataTypes<NftAssetEqualMetadataResponse> | undefined} The list of same NFTs which have same metadata for the asset request
* @example <caption>Staging example code for getAssetEqualMetadataById({})</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
const assetId = 100;
const requestEqualMetadata = {
assetId: 100,
};
const sameNftsWithMetadata = await onchainAssetManager.getAssetEqualMetadataById(requestEqualMetadata);
*/
public async getAssetEqualMetadataById(
payload: QueryEqualMetadataNftAssetParams
): Promise<
| APIResponseType<CommonPaginateDataTypes<NftAssetEqualMetadataResponse>>| undefined> {
if (!payload.assetId) {
throw new Error("AssetId is required");
} else {
const result = await this.assetMarketpApi.requestAssetEqualMetadataById(
payload
);
return result;
}
}
/**
* @description Function is to query the list of NFTs with a given order status along with the option to sort the data by specific fields
* @param {QueryAssetParams} payload The requested for assets query
* @throws {string} Exception: Order status is required
* @returns {CommonPaginateDataTypes<AssetHaveOrderResponse[]> | undefined}
* @example <caption>Staging example code for getNftAssetsByStatus({})</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
const queryNftParams: QueryAssetParams = {
orderType: OrderType.SELL,
status: OrderStatus.ACTIVE,
sortingField: "amountSell",
orderBy: AssetOrderBy.ASC; // increasement by the prices of NFT list
};
const sameNftsWithMetadata = await onchainAssetManager.getNftAssetsByStatus(queryNftParams);
*/
public async getNftAssetsByStatus(
payload: QueryAssetParams
): Promise<
| APIResponseType<CommonPaginateDataTypes<AssetHaveOrderResponse[]>>
| undefined
> {
if (!payload.status) {
throw new Error("Order status is required");
}
const listNftAssets = await this.assetMarketpApi.getAssetsByStatus(payload);
return listNftAssets;
}
/**
* @description The function to recrawl the list of NFTs in range with start token id and end token id
* @param {RecrawlBatchNftMetadataParams} payload The request payload to recraw the list of NFT's metadata
* @throws {string} Exception: CreatorStarkKey is required
* @throws {string} Exception: StartTokenId is required
* @throws {string} Exception: EndTokenId is required
* @throws {string} Exception: TokenAddress is required
* @throws {string} Exception: Start tokenId should be less than end tokenId.
* @throws {string} Exception: Token address should be the valid ethereum address type
* @throws {string} Http Status 500: Refresh metadata failed: ${INTERNAL_SERVER_ERROR}
* @returns {APIResponseType<RecrawlBatchNftMetadataResponse> | undefined}
* @example <caption>Staging example code for recrawlBatchNftMetadata({})</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const onchainAssetManager = new OnchainAssetManager(myriaClient);
const recrawlNftMetadata: RecrawlBatchNftMetadataParams = {
creatorStarkKey: '0xfbc.....',
startTokenId: '1',
endTokenId: '100',
tokenAddress: '0xfbc.....'
};
const recrawlBatchNfts = await onchainAssetManager.recrawlBatchNftMetadata(recrawlNftMetadata);
*/
public async recrawlBatchNftMetadata(
payload: RecrawlBatchNftMetadataParams
): Promise<APIResponseType<RecrawlBatchNftMetadataResponse> | undefined> {
if (!payload.creatorStarkKey) {
throw new Error("CreatorStarkKey is required");
}
if (!payload.startTokenId || !Number(payload.startTokenId?.trim())) {
throw new Error("StartTokenId is required");
}
if (!payload.endTokenId || !Number(payload.endTokenId?.trim())) {
throw new Error("EndTokenId is required");
}
if (!payload.tokenAddress) {
throw new Error("TokenAddress is required");
}
if(payload.startTokenId > payload.endTokenId) {
throw new Error(`Start tokenId should be less than end tokenId. \n Current value is: \n startTokenId: ${payload.startTokenId}, \n endTokenId: ${payload.endTokenId}`)
}
if(!ethers.utils.isAddress(payload.tokenAddress)) {
throw new Error("Token address should be the valid ethereum address type.");
}
try {
const response = await this.assetMarketpApi.requestRecrawlBatchNftMetadata(payload);
if (response?.status === 'success') {
return response
} else {
throw new Error(`Refresh metadata failed: ${response}`);
}
} catch (err) {
throw new Error(`Refresh metadata failed: ${err}`);
}
}
}
Source