-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat(tokens): add helpers for fetching metadata #77
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@rabbitholegg/questdk": minor | ||
--- | ||
|
||
Adds a client and helper functions for fetching metadata given either contract or boost information |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { | ||
fetchERC721Media, | ||
fetchERC721Metadata, | ||
fetchERC721MetadataByUUID, | ||
} from '../tokens/erc721.js' | ||
import { | ||
fetchERC1155Media, | ||
fetchERC1155Metadata, | ||
fetchERC1155MetadataByUUID, | ||
} from '../tokens/erc1155.js' | ||
import { type PublicClient, createClient, http } from 'viem' | ||
/** | ||
* Initializes an Ethereum client with the specified RPC URL and provides methods for ERC721 and ERC1155 token interactions. | ||
* @param {string} rpcUrl - The RPC URL for connecting to the Ethereum network. | ||
* @returns An object with methods for fetching token metadata and media. | ||
*/ | ||
function createEthereumClient(rpcUrl: string) { | ||
const client = createClient({ | ||
transport: http(rpcUrl), | ||
}) as PublicClient | ||
|
||
return { | ||
fetchERC721Metadata: (contractAddress: string, tokenId: number) => | ||
fetchERC721Metadata(client, contractAddress, tokenId), | ||
fetchERC721Media: (contractAddress: string, tokenId: number) => | ||
fetchERC721Media(client, contractAddress, tokenId), | ||
fetchERC1155Metadata: (contractAddress: string, tokenId: number) => | ||
fetchERC1155Metadata(client, contractAddress, tokenId), | ||
fetchERC1155Media: (contractAddress: string, tokenId: number) => | ||
fetchERC1155Media(client, contractAddress, tokenId), | ||
fetchERC721MetadataByUUID: (uuid: string) => | ||
fetchERC721MetadataByUUID(client, uuid), | ||
fetchERC1155MetadataByUUID: (uuid: string) => | ||
fetchERC1155MetadataByUUID(client, uuid), | ||
} | ||
} | ||
|
||
export default createEthereumClient |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import axios from 'axios' | ||
|
||
/** | ||
* Fetches quest data from RabbitHole API and extracts action parameters. | ||
* @param {string} uuid The UUID of the quest. | ||
* @returns {Promise<any>} The action parameters extracted from the quest data. | ||
*/ | ||
export async function fetchQuestActionParams(uuid: string): Promise<any> { | ||
const endpoint = `https://api.rabbithole.gg/v1.2/quest/public/${uuid}` | ||
|
||
try { | ||
const response = await axios.get(endpoint) | ||
const actionParams = response.data.actionParams | ||
return actionParams | ||
} catch (error) { | ||
console.error('Error fetching quest data:', error) | ||
throw new Error('Failed to fetch quest data') | ||
} | ||
} | ||
|
||
export default fetchQuestActionParams |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import fetchQuestActionParams from '../quests/fetchQuestData.js' | ||
import axios from 'axios' | ||
import { type Address, type PublicClient } from 'viem' | ||
|
||
/** | ||
* Fetches ERC1155 token metadata from a given contract. | ||
* @async | ||
* @param {PublicClient} client The Viem client instance. | ||
* @param {string} contractAddress The ERC1155 contract address. | ||
* @param {number} tokenId The token ID. | ||
* @returns {Promise<any>} The metadata of the ERC1155 token. | ||
*/ | ||
export async function fetchERC1155Metadata( | ||
client: PublicClient, | ||
contractAddress: string, | ||
tokenId: number, | ||
): Promise<any> { | ||
const tokenURI: string = await (client.readContract({ | ||
address: contractAddress as Address, | ||
abi: [ | ||
'function uri(uint256 tokenId) external view returns (string memory)', | ||
], | ||
functionName: 'uri', | ||
args: [tokenId], | ||
}) as Promise<string>) | ||
|
||
const response = await axios.get(tokenURI) | ||
return response.data | ||
} | ||
|
||
/** | ||
* Fetches the media URL from ERC1155 token metadata and performs basic validation or sanitization. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't think there's "basic validation or sanitization" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's not - I'll change this comment we discussed using a service for this but I think we're just going to handle it with the dom purify in the front-end There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be worth purifying on the BE wherever we serve the info to prevent passing dangerous data to third party clients or w/e |
||
* @async | ||
* @param {PublicClient} client - The Viem client instance. | ||
* @param {string} contractAddress - The ERC1155 contract address. | ||
* @param {number} tokenId - The token ID. | ||
* @returns {Promise<string | undefined>} - The media URL if available and valid. | ||
*/ | ||
export async function fetchERC1155Media( | ||
client: PublicClient, | ||
contractAddress: string, | ||
tokenId: number, | ||
): Promise<string | undefined> { | ||
const metadata = await fetchERC1155Metadata(client, contractAddress, tokenId) | ||
return metadata.image || metadata.animation_url | ||
} | ||
|
||
/** | ||
* Fetches ERC1155 token metadata using quest UUID from RabbitHole. | ||
* @param {PublicClient} client The Viem client instance. | ||
* @param {string} uuid The UUID of the quest. | ||
* @returns {Promise<any>} The metadata of the ERC1155 token associated with the quest. | ||
*/ | ||
export async function fetchERC1155MetadataByUUID( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] Wonder if it makes sense to rename function to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like it, rather a more specific long name |
||
client: PublicClient, | ||
uuid: string, | ||
): Promise<any> { | ||
const actionParams = await fetchQuestActionParams(uuid) | ||
if (actionParams.type !== 'mint') { | ||
throw new Error('Quest action is not of type mint') | ||
} | ||
const contractAddress = actionParams.data.contractAddress | ||
const tokenId = actionParams.data.tokenId | ||
return fetchERC1155Metadata(client, contractAddress, tokenId) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would add a TODO or open up an issue to update this endpoint to a Boost API in the near future