diff --git a/Solana.Unity.Metaplex.Test/MetadataTest.cs b/Solana.Unity.Metaplex.Test/MetadataTest.cs index 05fb3b3..0e330f9 100644 --- a/Solana.Unity.Metaplex.Test/MetadataTest.cs +++ b/Solana.Unity.Metaplex.Test/MetadataTest.cs @@ -8,6 +8,7 @@ using System.Text; using System; using Solana.Unity.Metaplex.NFT.Library; +using System.Threading.Tasks; namespace Solana.Unity.Metaplex.Test @@ -260,5 +261,49 @@ public void TestGetAndDecodeMessage() } } } + + [TestMethod] + public async Task TestGetMetadata() + { + var pk = "7w2aWAR2KNmLRC8jKqs245EW5ZauNysXh2gvCkXDQoMr"; + Console.WriteLine("### Get Metadata example ###"); + Console.WriteLine("Getting account {0}", pk ); + + var client = ClientFactory.GetClient( Cluster.MainNet); + var account = await MetadataAccount.GetAccount( client, new PublicKey(pk )); + + Console.WriteLine( $"Owner: {account.owner}"); + Console.WriteLine( $"Authority key: {account.updateAuthority}"); + Console.WriteLine( $"Mint key: {account.mint}"); + Console.WriteLine( $"Name: {account.metadata.name}"); + Console.WriteLine( $"Symbol: {account.metadata.symbol}"); + Console.WriteLine( $"Uri: {account.metadata.uri}"); + Console.WriteLine( $"SellerFeeBasisPoints: {account.metadata.sellerFeeBasisPoints}"); + + Console.WriteLine( $"---Creators---"); + foreach( Creator c in account.metadata.creators) + { + Console.WriteLine( $"Creator Key: {c.key}"); + Console.WriteLine( $"Creator Share: {c.share}"); + Console.WriteLine( $"Creator is verified: {c.verified}"); + } + + Console.WriteLine( "-------Metadata-------"); + Console.WriteLine($"Name: {account.offchainData.name}"); + Console.WriteLine($"Description: {account.offchainData.description}"); + Console.WriteLine($"Symbol: {account.offchainData.symbol}"); + Console.WriteLine($"Collection: {account.offchainData.collection}"); + Console.WriteLine($"Default Image: { account.offchainData.default_image }" ); + Console.WriteLine($"Animation url: {account.offchainData.animation_url}"); + + foreach (var attribute in account.offchainData.attributes) + { + if(attribute != null) + Console.WriteLine($"Attribute: { attribute.trait_type } | { attribute.value }"); + + } + + Console.WriteLine ( "------------------"); + } } } \ No newline at end of file diff --git a/Solana.Unity.Metaplex/Metadata Program/Account/MetadataAccount.cs b/Solana.Unity.Metaplex/Metadata Program/Account/MetadataAccount.cs index bfe03de..9b0a35a 100644 --- a/Solana.Unity.Metaplex/Metadata Program/Account/MetadataAccount.cs +++ b/Solana.Unity.Metaplex/Metadata Program/Account/MetadataAccount.cs @@ -3,6 +3,7 @@ using Solana.Unity.Metaplex.Utilities.Json; using Solana.Unity.Programs.Utilities; using Solana.Unity.Rpc; +using Solana.Unity.Rpc.Core.Http; using Solana.Unity.Rpc.Models; using Solana.Unity.Wallet; using System; @@ -38,38 +39,56 @@ public class MetadataAccount /// owner, should be Metadata program public PublicKey owner; - /// Constructor - /// Soloana account info - public MetadataAccount(AccountInfo accInfo) + private MetadataAccount() + { + + } + + /// + /// Constructor to build a MetadataAccount from a Solana AccountInfo + /// + /// + /// + public static async Task BuildMetadataAccount(AccountInfo accInfo) { try { - metadata = ParseData(accInfo.Data); - offchainData = FetchOffChainMetadata(metadata.uri); - + var met = ParseData(accInfo.Data); + + byte[] data = Convert.FromBase64String(accInfo.Data[0]); - Span _updateAuthority = data.AsSpan(1, 32); - Span _mint = data.AsSpan(33, 32); - - owner = new PublicKey(accInfo.Owner); - updateAuthority = new PublicKey(_updateAuthority); - mint = new PublicKey(_mint); + + var updateAuthority = new ArraySegment( data, 1, 32).ToArray(); + var mint = new ArraySegment( data, 33, 32).ToArray(); + + var metadata = new MetadataAccount() + { + metadata = met, + offchainData = await FetchOffChainMetadata(met.uri), + owner = new PublicKey(accInfo.Owner), + updateAuthority = new PublicKey(updateAuthority), + mint = new PublicKey(mint) + }; + return metadata; } catch (Exception ex) { Console.WriteLine(ex); } + + return null; } /// Tries to get a json file from the uri - public static MetaplexTokenStandard FetchOffChainMetadata(string URI) + public static async Task FetchOffChainMetadata(string URI) { MetaplexTokenStandard _Metadata = null; try { using var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0"); - var offsiteTokenRetrieval = httpClient.GetStringAsync(new Uri(URI)).Result; + var response = await CrossHttpClient.SendAsyncRequest(httpClient, new HttpRequestMessage(HttpMethod.Get, URI)); + var offsiteTokenRetrieval = response.Content.ReadAsStringAsync().Result; _Metadata = JsonConvert.DeserializeObject(offsiteTokenRetrieval); } catch (Exception ex) @@ -207,7 +226,7 @@ async public static Task GetAccount(IRpcClient client, PublicKe if (accInfo.Owner.Contains("meta")) { //Triggered after first jump using token account address & metadata address has been retrieved from the first run - return new MetadataAccount(accInfo); + return await BuildMetadataAccount(accInfo); } else //Account Inception first jump - if metadata address doesnt return null {