import { canResizeContentType, generateUrl, getContentTypeFromUrl, getMetadataFromUrl, getNetwork, getProgramId } from './utils'; import { PFPHolder, ProfilePicture, ProfilePictureConfig } from './types'; import { getObjectDisplay, getObjectFields, getObjectId, getObjectOwner, JsonRpcProvider, TransactionBlock } from '@mysten/sui.js'; const DEFAULT_CONFIG = { fallback: true, resize: { width: 100 } }; const getProgramData = async (network: string, programId?: string, globalState?: string) => { if (!programId || !globalState) { const data = await getProgramId(); programId = data[network].program_id; globalState = data[network].global_state; } return { programId, globalState }; }; export async function getProfilePicture( client: JsonRpcProvider, address: string, config?: ProfilePictureConfig, programId?: string, globalState?: string ): Promise { const finalConfig = { ...DEFAULT_CONFIG, ...config }; const network = getNetwork(client.connection.fullnode); try { const programData = await getProgramData(network, programId, globalState); programId = programData.programId; globalState = programData.globalState; const dynamicField = await client.getDynamicFieldObject({ parentId: globalState, name: { type: 'address', value: address } }); const pfpHolderData = getObjectFields(dynamicField) as PFPHolder; const nftData = await client.getObject({ id: pfpHolderData.nft_id, options: { showType: true, showContent: true, showBcs: true, showOwner: true, showPreviousTransaction: true, showStorageRebate: true, showDisplay: true } }); if (!nftData) { throw new Error("NFT doesn't exist."); } const nftDataFields = getObjectDisplay(nftData).data; const nftOwner = getObjectOwner(nftData) as any; if (nftOwner?.ObjectOwner) { const ownerData = await client.getObject({ id: nftOwner?.ObjectOwner, options: { showType: true, showContent: true, showBcs: true, showOwner: true, showPreviousTransaction: true, showStorageRebate: true, showDisplay: true } }); if (!ownerData || !ownerData.data) { throw new Error('Invalid NFT owner.'); } const realOwnerData = await client.getObject({ id: (ownerData.data?.owner as any).ObjectOwner, options: { showType: true, showContent: true, showBcs: true, showOwner: true, showPreviousTransaction: true, showStorageRebate: true, showDisplay: true } }); if (!realOwnerData || !realOwnerData.data) { throw new Error('Invalid NFT owner.'); } if (realOwnerData.data.content?.dataType !== 'moveObject') { throw new Error('Invalid NFT owner metadata.'); } if (realOwnerData.data.content.fields.owner !== address) { throw new Error('Invalid NFT owner.'); } } else { if (nftOwner?.AddressOwner !== address) { throw new Error('Invalid NFT owner.'); } } if (!nftDataFields?.description || !nftDataFields?.image_url) { throw new Error('No metadata'); } const metadata = await getMetadataFromUrl(nftDataFields?.image_url); let imageUri = metadata?.image || metadata?.image_uri || nftDataFields?.image_url || null; imageUri = imageUri?.replace(/\n/g, ''); imageUri = imageUri?.startsWith('ipfs://') ? `https://ipfs.io/ipfs/${imageUri?.split('ipfs://')[1]}` : imageUri; const contentType = await getContentTypeFromUrl(imageUri); finalConfig.resizable = canResizeContentType(contentType); return { isAvailable: true, url: generateUrl(imageUri, address, finalConfig), name: nftDataFields?.name || '', address, nftId: pfpHolderData.nft_id, pfpId: getObjectId(dynamicField) }; } catch (err) { return { isAvailable: false, url: generateUrl(null, address, finalConfig) }; } } export async function createSetProfilePicturePayload( client: JsonRpcProvider, address: string, nftId: string, nftStandard: string, programId?: string, globalState?: string ): Promise { const network = getNetwork(client.connection.fullnode); const programData = await getProgramData(network, programId, globalState); programId = programData.programId; globalState = programData.globalState; const tx = new TransactionBlock(); tx.setSender(address); tx.moveCall({ target: `${programId}::PFPData::set_pfp`, typeArguments: [nftStandard], arguments: [tx.object(globalState), tx.object(nftId)] }); return await tx.build({ provider: client }); } export async function createUnsetProfilePicturePayload( client: JsonRpcProvider, address: string, programId?: string, globalState?: string ): Promise { const network = getNetwork(client.connection.fullnode); const programData = await getProgramData(network, programId, globalState); programId = programData.programId; globalState = programData.globalState; const tx = new TransactionBlock(); tx.setSender(address); tx.moveCall({ target: `${programId}::PFPData::unset_pfp`, typeArguments: [], arguments: [tx.object(globalState)] }); return await tx.build({ provider: client }); }