From 0e14fbcbac47cf8e16dca24a65e4f2696429b4d6 Mon Sep 17 00:00:00 2001 From: Don Kackman Date: Fri, 4 Aug 2023 18:43:25 -0500 Subject: [PATCH 1/5] through dl_owned_singletons --- src/CodeGen/Program.cs | 22 +-- src/CodeGen/Properties/launchSettings.json | 2 +- src/chia-dotnet/ChiaTypes/SingletonRecord.cs | 6 + src/chia-dotnet/DataLayerWallet.cs | 173 ++++++++++++++++++ .../Properties/launchSettings.json | 8 + 5 files changed, 198 insertions(+), 13 deletions(-) create mode 100644 src/chia-dotnet/DataLayerWallet.cs create mode 100644 src/chia-dotnet/Properties/launchSettings.json diff --git a/src/CodeGen/Program.cs b/src/CodeGen/Program.cs index f3a13ef6..f9e5702f 100644 --- a/src/CodeGen/Program.cs +++ b/src/CodeGen/Program.cs @@ -57,10 +57,7 @@ private static string GenerateCSharpMethod(OpenApiOperation operation, string? r } var returnsArray = GetResponseArrayType(responseSchema) != null; - if (returnsArray) - { - returnType = "IEnumerable<" + returnType + ">"; - } + var fullReturnType = returnsArray ? "IEnumerable<" + returnType + ">" : returnType; // Generate method parameters, parameter comments, and data initialization var methodParameters = "CancellationToken cancellationToken = default"; @@ -89,12 +86,12 @@ private static string GenerateCSharpMethod(OpenApiOperation operation, string? r } // Generate method signature - var methodSignature = returnType is not null ? "public async Task<" + returnType + "> " + methodName + "(" + methodParameters + ")" : "public async Task " + methodName + "(" + methodParameters + ")"; + var methodSignature = fullReturnType is not null ? "public async Task<" + fullReturnType + "> " + methodName + "(" + methodParameters + ")" : "public async Task " + methodName + "(" + methodParameters + ")"; // Determine the result key from the response schema var resultKey = GetResultKeyFromSchema(responseSchema); - var methodBody = GetMethodBody(dataInitialization, returnType, operation, resultKey); + var methodBody = GetMethodBody(dataInitialization, fullReturnType, operation, resultKey); var returnsComment = returnsArray ? "/// A list of " : "/// "; // Generate summary comment @@ -108,20 +105,20 @@ private static string GenerateCSharpMethod(OpenApiOperation operation, string? r return comment + "\n" + methodSignature + "\n" + methodBody; } - private static string GetMethodBody(string dataInitialization, string? returnType, OpenApiOperation operation, string? resultKey) + private static string GetMethodBody(string dataInitialization, string? fullReturnType, OpenApiOperation operation, string? resultKey) { - if (returnType is not null) + if (fullReturnType is not null) { return "{\n" + dataInitialization + - " return await SendMessage<" + returnType + ">(\"" + operation.OperationId + "\", " + (string.IsNullOrEmpty(dataInitialization) ? "null" : "data") + ", \"" + resultKey + "\", cancellationToken).ConfigureAwait(false);\n" + + " return await SendMessage<" + fullReturnType + ">(\"" + operation.OperationId + "\", " + (string.IsNullOrEmpty(dataInitialization) ? "null" : "data") + ", \"" + resultKey + "\", cancellationToken).ConfigureAwait(false);\n" + "}"; } else if (resultKey is not null) { return "{\n" + dataInitialization + - " var resonse = await SendMessage(\"" + operation.OperationId + "\", " + (string.IsNullOrEmpty(dataInitialization) ? "null" : "data") + ", \"" + resultKey + "\", cancellationToken).ConfigureAwait(false);\n" + + " var response = await SendMessage(\"" + operation.OperationId + "\", " + (string.IsNullOrEmpty(dataInitialization) ? "null" : "data") + ", \"" + resultKey + "\", cancellationToken).ConfigureAwait(false);\n" + " return response;\n" + "}"; } @@ -215,9 +212,10 @@ private static string ConvertOpenApiTypeToCSharpType(string type, string format) } else if (combinedSchema.Type == "object" && combinedSchema.Properties.Count() == 1) { - if (combinedSchema.Properties.First().Value.Type == "array") + var property = combinedSchema.Properties.First(); + if (property.Value.Type == "array") { - return combinedSchema.Properties.First().Value.Items.Type; + return property.Value.Items.Type ?? "object"; } } } diff --git a/src/CodeGen/Properties/launchSettings.json b/src/CodeGen/Properties/launchSettings.json index 049f8021..3c8c250b 100644 --- a/src/CodeGen/Properties/launchSettings.json +++ b/src/CodeGen/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "CodeGen": { "commandName": "Project", - "commandLineArgs": "C:\\Users\\don\\src\\github\\dkackman\\chia-api\\src\\data_layer.yaml take_offer" + "commandLineArgs": "C:\\Users\\don\\src\\github\\dkackman\\chia-api\\src\\wallet.yaml dl_singletons_by_root SingletonRecord" } } } \ No newline at end of file diff --git a/src/chia-dotnet/ChiaTypes/SingletonRecord.cs b/src/chia-dotnet/ChiaTypes/SingletonRecord.cs index 3d6042ce..32613679 100644 --- a/src/chia-dotnet/ChiaTypes/SingletonRecord.cs +++ b/src/chia-dotnet/ChiaTypes/SingletonRecord.cs @@ -3,6 +3,12 @@ namespace chia.dotnet { + public record SingletonInfo + { + public string Launcher { get; init; } = string.Empty; + public string LauncRootherId { get; init; } = string.Empty; + } + public record SingletonRecord { public string CoinId { get; init; } = string.Empty; diff --git a/src/chia-dotnet/DataLayerWallet.cs b/src/chia-dotnet/DataLayerWallet.cs new file mode 100644 index 00000000..484e15cf --- /dev/null +++ b/src/chia-dotnet/DataLayerWallet.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace chia.dotnet +{ + /// + /// Wraps a Data Layer Wallet + /// + public sealed class DataLayerWallet : Wallet + { + /// + /// ctor + /// + /// The wallet_id to wrap + /// Wallet RPC proxy to use for communication + public DataLayerWallet(uint walletId, WalletProxy walletProxy) + : base(walletId, walletProxy) + { + } + + /// + /// Validates that is a + /// + /// True if the wallet is a Data Layer wallet + public override async Task Validate(CancellationToken cancellationToken = default) + { + await Validate(WalletType.DATA_LAYER, cancellationToken).ConfigureAwait(false); + } + + /// + /// Initialize the new data layer wallets. + /// + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task<(IEnumerable Transactions, string LauncherId)> CreateNewDl(string root, ulong fee = 0, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.root = root; + data.fee = fee; + var response = await WalletProxy.SendMessage("create_new_dl", data, cancellationToken).ConfigureAwait(false); + return (Converters.ToEnumerable(response.transactions), response.launcher_id); + } + + /// + /// Get the singleton record for the latest singleton of a launcher ID. + /// + /// + /// + /// + /// + /// A token to allow the call to be cancelled + /// A list of + public async Task> History(string launcherId, uint? minGeneration = null, uint? maxGeneration = null, uint? numResults = null, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.launcher_id = launcherId; + if (minGeneration.HasValue) + { + data.min_generation = minGeneration; + } + if (maxGeneration.HasValue) + { + data.max_generation = maxGeneration; + } + if (numResults.HasValue) + { + data.num_results = numResults; + } + return await WalletProxy.SendMessage>("dl_history", data, "history", cancellationToken).ConfigureAwait(false); + } + + /// + /// Get the singleton records that contain the specified root. + /// + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task LatestSingleton(string root, string launcherId, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.launcher_id = launcherId; + data.root = root; + return await WalletProxy.SendMessage("dl_latest_singleton", data, "singleton", cancellationToken).ConfigureAwait(false); + } + + /// + /// Get all owned singleton records. + /// + /// A token to allow the call to be cancelled + /// A list of + public async Task> DlOwnedSingletons(CancellationToken cancellationToken = default) + { + return await SendMessage>("dl_owned_singletons", null, "history", cancellationToken).ConfigureAwait(false); + } + + /// + /// Get the singleton records that contain the specified root. + /// + /// + /// + /// A token to allow the call to be cancelled + /// A list of + public async Task> SingletonsByRoot(string root, string launcherId, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.launcher_id = launcherId; + data.root = root; + return await WalletProxy.SendMessage>("dl_singletons_by_root", data, "singleton", cancellationToken).ConfigureAwait(false); + } + + /// + /// Stop tracking the data layer wallets. + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task StopTracking(string launcherId, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.launcher_id = launcherId; + await WalletProxy.SendMessage("dl_stop_tracking", data, cancellationToken).ConfigureAwait(false); + } + + /// + /// Track the new data layer wallet + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task TrackNew(string launcherId, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.launcher_id = launcherId; + await WalletProxy.SendMessage("dl_track_new", data, cancellationToken).ConfigureAwait(false); + } + + /// + /// Update multiple singletons with new merkle roots + /// + /// + /// A token to allow the call to be cancelled + /// A list of + public async Task> UpdateMultiple(IEnumerable updates, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.updates = updates.ToList(); + return await WalletProxy.SendMessage>("dl_update_multiple", data, "tx_records", cancellationToken).ConfigureAwait(false); + } + + /// + /// Update a data layer root. + /// + /// + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task UpdateRoot(string newRoot, string launcherId, ulong fee = 0, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.launcher_id = launcherId; + data.new_root = newRoot; + data.fee = fee; + return await WalletProxy.SendMessage("dl_update_root", data, "tx_record", cancellationToken).ConfigureAwait(false); + } + } +} diff --git a/src/chia-dotnet/Properties/launchSettings.json b/src/chia-dotnet/Properties/launchSettings.json new file mode 100644 index 00000000..f671d62d --- /dev/null +++ b/src/chia-dotnet/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "chia-dotnet": { + "commandName": "Project", + "commandLineArgs": "C:\\Users\\don\\src\\github\\dkackman\\chia-api\\src\\wallet.yaml dl_singletons_by_root SingletonRecord" + } + } +} \ No newline at end of file From b6de438c99d1f2ff134c602eabbfae1dfa6bde11 Mon Sep 17 00:00:00 2001 From: Don Kackman Date: Fri, 4 Aug 2023 18:51:42 -0500 Subject: [PATCH 2/5] DL methods --- src/chia-dotnet/DataLayerWallet.cs | 51 ++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/chia-dotnet/DataLayerWallet.cs b/src/chia-dotnet/DataLayerWallet.cs index 484e15cf..f3c58e82 100644 --- a/src/chia-dotnet/DataLayerWallet.cs +++ b/src/chia-dotnet/DataLayerWallet.cs @@ -46,6 +46,34 @@ public override async Task Validate(CancellationToken cancellationToken = defaul return (Converters.ToEnumerable(response.transactions), response.launcher_id); } + /// + /// Remove an existing mirror for a specific singleton. + /// + /// + /// + /// A token to allow the call to be cancelled + /// A list of + public async Task> DeleteMirror(string coinId, ulong fee = 0, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.coin_id = coinId; + data.fee = fee; + return await WalletProxy.SendMessage>("dl_delete_mirror", data, "transactions", cancellationToken).ConfigureAwait(false); + } + + /// + /// Get all of the mirrors for a specific singleton. + /// + /// + /// A token to allow the call to be cancelled + /// A list of + public async Task> GetMirrors(string launcherId, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.launcher_id = launcherId; + return await WalletProxy.SendMessage>("dl_get_mirrors", data, "mirrors", cancellationToken).ConfigureAwait(false); + } + /// /// Get the singleton record for the latest singleton of a launcher ID. /// @@ -89,14 +117,33 @@ public async Task LatestSingleton(string root, string launcherId, return await WalletProxy.SendMessage("dl_latest_singleton", data, "singleton", cancellationToken).ConfigureAwait(false); } + /// + /// Add a new on chain message for a specific singleton. + /// + /// + /// + /// + /// + /// A token to allow the call to be cancelled + /// A list of + public async Task> NewMirror(string launcherId, ulong amount, IEnumerable urls, ulong fee = 0, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.launcher_id = launcherId; + data.amount = amount; + data.urls = urls.ToList(); + data.fee = fee; + return await WalletProxy.SendMessage>("dl_new_mirror", data, "transactions", cancellationToken).ConfigureAwait(false); + } + /// /// Get all owned singleton records. /// /// A token to allow the call to be cancelled /// A list of - public async Task> DlOwnedSingletons(CancellationToken cancellationToken = default) + public async Task> OwnedSingletons(CancellationToken cancellationToken = default) { - return await SendMessage>("dl_owned_singletons", null, "history", cancellationToken).ConfigureAwait(false); + return await WalletProxy.SendMessage>("dl_owned_singletons", null, "history", cancellationToken).ConfigureAwait(false); } /// From 39e3848aa5092efb3d2d53d1a550373856726819 Mon Sep 17 00:00:00 2001 From: Don Kackman Date: Sat, 5 Aug 2023 07:59:29 -0500 Subject: [PATCH 3/5] nft_mint_bulk --- .../ChiaTypes/NFTBulkMintingInfo.cs | 41 ++++++++ src/chia-dotnet/ChiaTypes/NFTInfo.cs | 2 +- src/chia-dotnet/ChiaTypes/NFTMintingInfo.cs | 20 ++-- src/chia-dotnet/DataLayerWallet.cs | 18 +--- src/chia-dotnet/NFTWallet.cs | 98 +++++++++++++++++-- src/chia-dotnet/WalletProxy.cs | 16 +++ 6 files changed, 159 insertions(+), 36 deletions(-) create mode 100644 src/chia-dotnet/ChiaTypes/NFTBulkMintingInfo.cs diff --git a/src/chia-dotnet/ChiaTypes/NFTBulkMintingInfo.cs b/src/chia-dotnet/ChiaTypes/NFTBulkMintingInfo.cs new file mode 100644 index 00000000..86a7a3cd --- /dev/null +++ b/src/chia-dotnet/ChiaTypes/NFTBulkMintingInfo.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + +namespace chia.dotnet +{ + /// + /// Info for minting NFTs in bulk + /// + public record NFTBulkMintingInfo + { + public string? RoyaltyAddress { get; init; } = string.Empty; + public ushort? RoyaltyPercentage { get; init; } + public IEnumerable MetadataList { get; init; } = new List(); + /// + /// a list of targets for transferring minted NFTs (aka airdrop) + /// + public IEnumerable? TargetList { get; init; } + /// + /// The starting point for mint number used in intermediate launcher puzzle + /// + public int MintNumberStart { get; init; } = 1; + /// + /// The total number of NFTs being minted + /// + public int? MintTotal { get; init; } + /// + /// For use with bulk minting to provide the coin used for funding the minting spend. + /// This coin can be one that will be created in the future + /// + public IEnumerable? XchCoins { get; init; } + /// + /// For use with bulk minting, so we can specify the puzzle hash that the change + // from the funding transaction goes to. + /// + public string? XchChangeTarget { get; init; } + public string? NewInnerpuzhash { get; init; } + public string? NewP2Puzhash { get; init; } + public Coin? DidCoin { get; init; } + public string? DidLineageParentHex { get; init; } + public bool MintFromDid { get; init; } + } +} diff --git a/src/chia-dotnet/ChiaTypes/NFTInfo.cs b/src/chia-dotnet/ChiaTypes/NFTInfo.cs index a190c185..0a9555c2 100644 --- a/src/chia-dotnet/ChiaTypes/NFTInfo.cs +++ b/src/chia-dotnet/ChiaTypes/NFTInfo.cs @@ -42,7 +42,7 @@ public record NFTInfo /// /// Hash of the metadata /// - public string MetaataHash { get; init; } = string.Empty; + public string MetadataHash { get; init; } = string.Empty; /// /// A list of license URIs /// diff --git a/src/chia-dotnet/ChiaTypes/NFTMintingInfo.cs b/src/chia-dotnet/ChiaTypes/NFTMintingInfo.cs index b67c35f0..56445cc4 100644 --- a/src/chia-dotnet/ChiaTypes/NFTMintingInfo.cs +++ b/src/chia-dotnet/ChiaTypes/NFTMintingInfo.cs @@ -2,15 +2,9 @@ namespace chia.dotnet { - /// - /// Info for minting an NFT - /// - public record NFTMintingInfo + public record NftMintEntry { - public string RoyaltyAddress { get; init; } = string.Empty; - public string TargetAddress { get; init; } = string.Empty; - public string? DIDID { get; init; } - public ushort RoyaltyPercentage { get; init; } = 0; + public ushort RoyaltyPercentage { get; init; } public IEnumerable Uris { get; init; } = new List(); public string Hash { get; init; } = string.Empty; public IEnumerable MetaUris { get; init; } = new List(); @@ -20,4 +14,14 @@ public record NFTMintingInfo public ulong EditionTotal { get; init; } = 1; public ulong EditionNumber { get; init; } = 1; } + + /// + /// Info for minting an NFT + /// + public record NFTMintingInfo : NftMintEntry + { + public string? RoyaltyAddress { get; init; } = string.Empty; + public string? TargetAddress { get; init; } + public string? DidId { get; init; } + } } diff --git a/src/chia-dotnet/DataLayerWallet.cs b/src/chia-dotnet/DataLayerWallet.cs index f3c58e82..6d6afe70 100644 --- a/src/chia-dotnet/DataLayerWallet.cs +++ b/src/chia-dotnet/DataLayerWallet.cs @@ -30,27 +30,11 @@ public override async Task Validate(CancellationToken cancellationToken = defaul await Validate(WalletType.DATA_LAYER, cancellationToken).ConfigureAwait(false); } - /// - /// Initialize the new data layer wallets. - /// - /// - /// - /// A token to allow the call to be cancelled - /// - public async Task<(IEnumerable Transactions, string LauncherId)> CreateNewDl(string root, ulong fee = 0, CancellationToken cancellationToken = default) - { - dynamic data = new ExpandoObject(); - data.root = root; - data.fee = fee; - var response = await WalletProxy.SendMessage("create_new_dl", data, cancellationToken).ConfigureAwait(false); - return (Converters.ToEnumerable(response.transactions), response.launcher_id); - } - /// /// Remove an existing mirror for a specific singleton. /// - /// /// + /// /// A token to allow the call to be cancelled /// A list of public async Task> DeleteMirror(string coinId, ulong fee = 0, CancellationToken cancellationToken = default) diff --git a/src/chia-dotnet/NFTWallet.cs b/src/chia-dotnet/NFTWallet.cs index 7db9a3f5..f2ecdc5d 100644 --- a/src/chia-dotnet/NFTWallet.cs +++ b/src/chia-dotnet/NFTWallet.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Dynamic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -79,24 +81,100 @@ public async Task GetDID(CancellationToken cancellationToken = default) /// Transaction fee /// A token to allow the call to be cancelled /// A - public async Task MintNFT(NFTMintingInfo info, ulong fee = 0, CancellationToken cancellationToken = default) + public async Task<(SpendBundle SpendBundle, string NftId)> MintNFT(NFTMintingInfo info, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default) { dynamic data = CreateWalletDataObject(); - data.royalty_address = info.RoyaltyAddress; - data.target_address = info.TargetAddress; - data.uris = info.Uris; - data.meta_uris = info.MetaUris; - data.license_uris = info.LicenseUris; + if (info.RoyaltyAddress is not null) + { + data.royalty_address = info.RoyaltyAddress; + } + if (info.TargetAddress is not null) + { + data.target_address = info.TargetAddress; + } + if (info.MetaHash is not null) + { + data.meta_hash = info.MetaHash; + } + if (info.LicenseHash is not null) + { + data.license_hash = info.LicenseHash; + } + if (info.DidId is not null) + { + data.did_id = info.DidId; + } + data.uris = info.Uris.ToList(); + data.meta_uris = info.MetaUris.ToList(); + data.license_uris = info.LicenseUris.ToList(); data.hash = info.Hash; data.edition_number = info.EditionNumber; data.edition_total = info.EditionTotal; - data.meta_hash = info.MetaHash; - data.license_hash = info.LicenseHash; - data.did_id = info.DIDID; data.royalty_percentage = info.RoyaltyPercentage; data.fee = fee; + data.reuse_puzhash = reusePuzhash; - return await WalletProxy.SendMessage("nft_mint_nft", "spend_bundle", data, cancellationToken).ConfigureAwait(false); + var response = await WalletProxy.SendMessage("nft_mint_nft", data, cancellationToken).ConfigureAwait(false); + return (Converters.ToObject(response.spend_bundle), response.nft_id); + } + + /// + /// + /// A list of dicts containing the metadata for each NFT to be minted + /// A token to allow the call to be cancelled + /// + public async Task<(SpendBundle SpendBundle, IEnumerable NftIdList)> NftMintBulk(NFTBulkMintingInfo info, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default) + { + dynamic data = CreateWalletDataObject(); + + data.metadata_list = info.MetadataList.ToList(); + data.mint_number_start = info.MintNumberStart; + + if (info.RoyaltyAddress is not null) + { + data.royalty_address = info.RoyaltyAddress; + } + if (info.RoyaltyPercentage is not null) + { + data.royalty_percentage = info.RoyaltyPercentage; + } + if (info.TargetList is not null) + { + data.target_list = info.TargetList.ToList(); + } + if (info.MintTotal is not null) + { + data.mint_total = info.MintTotal; + } + if (info.XchCoins is not null) + { + data.xch_coin = info.XchCoins.ToList(); + } + if (info.XchChangeTarget is not null) + { + data.xch_change_target = info.XchChangeTarget; + } + if (info.NewInnerpuzhash is not null) + { + data.new_innerpuzhash = info.NewInnerpuzhash; + } + if (info.NewP2Puzhash is not null) + { + data.new_p2_puzhash = info.NewP2Puzhash; + } + if (info.DidCoin is not null) + { + data.did_coin = info.DidCoin; + } + if (info.DidLineageParentHex is not null) + { + data.did_lineage_parent_hex = info.DidLineageParentHex; + } + data.mint_from_did = info.MintFromDid; + data.fee = fee; + data.reuse_puzhash = reusePuzhash; + var response = await WalletProxy.SendMessage("nft_mint_bulk", data, cancellationToken).ConfigureAwait(false); + return (Converters.ToObject(response.spend_bundle), Converters.ToEnumerable(response.nft_id_list)); } /// diff --git a/src/chia-dotnet/WalletProxy.cs b/src/chia-dotnet/WalletProxy.cs index eb007831..710e7b09 100644 --- a/src/chia-dotnet/WalletProxy.cs +++ b/src/chia-dotnet/WalletProxy.cs @@ -696,5 +696,21 @@ public async Task> GetCoinRecordsByNames(IEnumerable>("get_coin_records_by_names", data, "coin_records", cancellationToken).ConfigureAwait(false); } + + /// + /// Initialize the new data layer wallets. + /// + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task<(IEnumerable Transactions, string LauncherId)> CreateNewDl(string root, ulong fee = 0, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.root = root; + data.fee = fee; + var response = await SendMessage("create_new_dl", data, cancellationToken).ConfigureAwait(false); + return (Converters.ToEnumerable(response.transactions), response.launcher_id); + } } } From e9e249b712405b3e445835ec9494d427a5b3bce4 Mon Sep 17 00:00:00 2001 From: Don Kackman Date: Sat, 5 Aug 2023 08:59:29 -0500 Subject: [PATCH 4/5] nft updates --- src/CodeGen/Program.cs | 2 +- src/CodeGen/Properties/launchSettings.json | 2 +- src/chia-dotnet/ChiaTypes/Asset.cs | 22 ++++++++ src/chia-dotnet/Converters.cs | 14 +++++ src/chia-dotnet/DIDWallet.cs | 2 +- src/chia-dotnet/NFTWallet.cs | 59 +++++++++++++++++----- src/chia-dotnet/WalletProxy.cs | 6 ++- 7 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 src/chia-dotnet/ChiaTypes/Asset.cs diff --git a/src/CodeGen/Program.cs b/src/CodeGen/Program.cs index f9e5702f..0f01fd8e 100644 --- a/src/CodeGen/Program.cs +++ b/src/CodeGen/Program.cs @@ -153,7 +153,7 @@ private static string GetMethodBody(string dataInitialization, string? fullRetur return schema.Properties.Keys.FirstOrDefault(); } - throw new InvalidOperationException("Could not determine result key from schema"); + return null; } diff --git a/src/CodeGen/Properties/launchSettings.json b/src/CodeGen/Properties/launchSettings.json index 3c8c250b..e97ec0ca 100644 --- a/src/CodeGen/Properties/launchSettings.json +++ b/src/CodeGen/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "CodeGen": { "commandName": "Project", - "commandLineArgs": "C:\\Users\\don\\src\\github\\dkackman\\chia-api\\src\\wallet.yaml dl_singletons_by_root SingletonRecord" + "commandLineArgs": "C:\\Users\\don\\src\\github\\dkackman\\chia-api\\src\\wallet.yaml nft_calculate_royalties" } } } \ No newline at end of file diff --git a/src/chia-dotnet/ChiaTypes/Asset.cs b/src/chia-dotnet/ChiaTypes/Asset.cs new file mode 100644 index 00000000..0cb08e6a --- /dev/null +++ b/src/chia-dotnet/ChiaTypes/Asset.cs @@ -0,0 +1,22 @@ +namespace chia.dotnet +{ + public record AssetInfo + { + public string Asset { get; init; } = string.Empty; + public string Address { get; init; } = string.Empty; + public ulong Amount { get; init; } + } + + public record FungibleAsset + { + public string Asset { get; init; } = string.Empty; + public ulong Amount { get; init; } + } + + public record RoyaltyAsset + { + public string Asset { get; init; } = string.Empty; + public string RoyaltyAddress { get; init; } = string.Empty; + public ushort RoyaltyPercentage { get; init; } + } +} diff --git a/src/chia-dotnet/Converters.cs b/src/chia-dotnet/Converters.cs index 2b93a1e1..1922cd58 100644 --- a/src/chia-dotnet/Converters.cs +++ b/src/chia-dotnet/Converters.cs @@ -40,6 +40,20 @@ internal static class Converters }); } + public static IDictionary ToDictionary(dynamic dictionary) + { + // TODO - this mneeds a unit test + // good data example here https://docs.chia.net/nft-rpc?_highlight=nft_calculate_royalties#nft_calculate_royalties + Debug.Assert(dictionary is not null); + // we're just gonna re-round trip this for now + var settings = new JsonSerializerSettings + { + ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() } + }; + var jsonString = JsonConvert.SerializeObject(dictionary, settings); + return JsonConvert.DeserializeObject>(jsonString, settings); + } + public static IEnumerable ToEnumerable(dynamic enumerable) { Debug.Assert(enumerable is not null); diff --git a/src/chia-dotnet/DIDWallet.cs b/src/chia-dotnet/DIDWallet.cs index 04bf6474..0c112d9e 100644 --- a/src/chia-dotnet/DIDWallet.cs +++ b/src/chia-dotnet/DIDWallet.cs @@ -94,7 +94,7 @@ public async Task Spend(string puzzlehash, CancellationToken cancellationToken = /// /// A token to allow the call to be cancelled /// A DID and optional CoinID - public async Task<(string MyDID, string? CoinID)> GetDID(CancellationToken cancellationToken = default) + public async Task<(string MyDid, string? CoinID)> GetDid(CancellationToken cancellationToken = default) { var response = await WalletProxy.SendMessage("did_get_did", CreateWalletDataObject(), cancellationToken).ConfigureAwait(false); diff --git a/src/chia-dotnet/NFTWallet.cs b/src/chia-dotnet/NFTWallet.cs index f2ecdc5d..07452bf5 100644 --- a/src/chia-dotnet/NFTWallet.cs +++ b/src/chia-dotnet/NFTWallet.cs @@ -34,30 +34,59 @@ public override async Task Validate(CancellationToken cancellationToken = defaul /// Adds an Uri to an NFT /// /// The uri - /// The uri key + /// The type of uri: + /// * u Uri for the NFT data + /// * mu Uri for NFT metadata + /// * lu Uri for the NFT license /// The nft coin id + /// /// Transaction fee /// A token to allow the call to be cancelled /// An - public async Task AddUri(string uri, string key, string nftCoinId, ulong fee = 0, CancellationToken cancellationToken = default) + public async Task AddUri(string uri, string key, string nftCoinId, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default) { dynamic data = CreateWalletDataObject(); data.uri = uri; data.key = key; data.nft_coin_id = nftCoinId; + data.reuse_puzhash = reusePuzhash; data.fee = fee; return await WalletProxy.SendMessage("nft_add_uri", "spend_bundle", data, cancellationToken).ConfigureAwait(false); } + /// + /// Transfers an NFT to another address. + /// + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task>> CalculateRoyalties(IEnumerable fungibleAssets, IEnumerable royaltyAssets, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.royalty_assets = royaltyAssets.ToList(); + data.fungible_assets = fungibleAssets.ToList(); + var response = await WalletProxy.SendMessage("nft_calculate_royalties", data, cancellationToken).ConfigureAwait(false); + return Converters.ToDictionary>(response); + } + /// /// Gets NFTs from a wallet /// + /// + /// + /// /// A token to allow the call to be cancelled - /// The DID id - public async Task> GetNFTs(CancellationToken cancellationToken = default) + /// A list of + public async Task> GetNFTs(int startIndex = 0, int num = 0, bool ignoreSizeLimit = false, CancellationToken cancellationToken = default) { - var response = await WalletProxy.SendMessage("nft_get_nfts", CreateWalletDataObject(), cancellationToken).ConfigureAwait(false); + dynamic data = CreateWalletDataObject(); + data.start_index = startIndex; + data.num = num; + data.ignore_size_limit = ignoreSizeLimit; + + var response = await WalletProxy.SendMessage("nft_get_nfts", data, cancellationToken).ConfigureAwait(false); return Converters.ToObject>(response, "nft_list"); } @@ -66,8 +95,8 @@ public async Task> GetNFTs(CancellationToken cancellationTo /// Gets the DID /// /// A token to allow the call to be cancelled - /// The list of NFTs - public async Task GetDID(CancellationToken cancellationToken = default) + /// The Did + public async Task GetDid(CancellationToken cancellationToken = default) { var response = await WalletProxy.SendMessage("nft_get_wallet_did", CreateWalletDataObject(), cancellationToken).ConfigureAwait(false); @@ -78,6 +107,7 @@ public async Task GetDID(CancellationToken cancellationToken = default) /// Mints an NFT /// /// Info about the NFT to be minted + /// /// Transaction fee /// A token to allow the call to be cancelled /// A @@ -119,10 +149,11 @@ public async Task GetDID(CancellationToken cancellationToken = default) } /// - /// - /// A list of dicts containing the metadata for each NFT to be minted + /// A list of dicts containing the metadata for each NFT to be minted + /// /// A token to allow the call to be cancelled - /// + /// Transaction fee + /// and a list of public async Task<(SpendBundle SpendBundle, IEnumerable NftIdList)> NftMintBulk(NFTBulkMintingInfo info, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default) { dynamic data = CreateWalletDataObject(); @@ -181,12 +212,14 @@ public async Task GetDID(CancellationToken cancellationToken = default) /// Sets the DID for an NFT /// /// The DID ID + /// /// A token to allow the call to be cancelled /// A - public async Task SetDID(string didId, CancellationToken cancellationToken = default) + public async Task SetDID(string didId, bool reusePuzhash = false, CancellationToken cancellationToken = default) { dynamic data = CreateWalletDataObject(); data.did_id = didId; + data.reuse_puzhash = reusePuzhash; return await WalletProxy.SendMessage("nft_set_nft_did", "spend_bundle", data, cancellationToken).ConfigureAwait(false); } @@ -212,14 +245,16 @@ public async Task SetStatus(string coinId, bool inTransaction = true, Cancellati /// /// The target address /// The coin ID + /// /// Transaction fee /// A token to allow the call to be cancelled /// A - public async Task Transfer(string targetAddress, string coinId, ulong fee = 0, CancellationToken cancellationToken = default) + public async Task Transfer(string targetAddress, string coinId, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default) { dynamic data = CreateWalletDataObject(); data.target_address = targetAddress; data.nft_coin_id = coinId; + data.reuse_puzhash = reusePuzhash; data.fee = fee; return await WalletProxy.SendMessage("nft_transfer_nft", "spend_bundle", data, cancellationToken).ConfigureAwait(false); diff --git a/src/chia-dotnet/WalletProxy.cs b/src/chia-dotnet/WalletProxy.cs index 710e7b09..781601f2 100644 --- a/src/chia-dotnet/WalletProxy.cs +++ b/src/chia-dotnet/WalletProxy.cs @@ -423,13 +423,17 @@ public async Task GetNFTByDID(string didId, CancellationToken cancellation /// /// The coin id /// Get latest NFT + /// + /// /// A token to allow the call to be cancelled /// The wallet id - public async Task GetNFTInfo(string coinId, bool latest = true, CancellationToken cancellationToken = default) + public async Task GetNFTInfo(string coinId, bool latest = true, bool ignoreSizeLimit = false, bool reusePuzhash = false, CancellationToken cancellationToken = default) { dynamic data = new ExpandoObject(); data.coin_id = coinId; data.latest = latest; + data.ignore_size_limit = ignoreSizeLimit; + data.reuse_puzhash = reusePuzhash; return await SendMessage("nft_get_info", data, "nft_info", cancellationToken).ConfigureAwait(false); } From 922f64749e5a562d8d001c64695b2faa36852c65 Mon Sep 17 00:00:00 2001 From: Don Kackman Date: Sat, 5 Aug 2023 09:35:11 -0500 Subject: [PATCH 5/5] more nft stuffs --- src/chia-dotnet/ChiaTypes/NftCoinInfo.cs | 10 +++++ src/chia-dotnet/NFTWallet.cs | 14 ++---- src/chia-dotnet/WalletProxy.cs | 56 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 src/chia-dotnet/ChiaTypes/NftCoinInfo.cs diff --git a/src/chia-dotnet/ChiaTypes/NftCoinInfo.cs b/src/chia-dotnet/ChiaTypes/NftCoinInfo.cs new file mode 100644 index 00000000..448449c5 --- /dev/null +++ b/src/chia-dotnet/ChiaTypes/NftCoinInfo.cs @@ -0,0 +1,10 @@ +namespace chia.dotnet +{ + public record NftCoinInfo + { + + public string NftCoinId { get; init; } = string.Empty; + + public int WalletId { get; init; } + } +} diff --git a/src/chia-dotnet/NFTWallet.cs b/src/chia-dotnet/NFTWallet.cs index 07452bf5..700ad714 100644 --- a/src/chia-dotnet/NFTWallet.cs +++ b/src/chia-dotnet/NFTWallet.cs @@ -56,19 +56,13 @@ public async Task AddUri(string uri, string key, string nftCoinId, } /// - /// Transfers an NFT to another address. + /// Retrieves the number of NFTs in a wallet. /// - /// - /// /// A token to allow the call to be cancelled - /// - public async Task>> CalculateRoyalties(IEnumerable fungibleAssets, IEnumerable royaltyAssets, CancellationToken cancellationToken = default) + /// The number of NFTs in the wallet + public async Task NftCountNfts(CancellationToken cancellationToken = default) { - dynamic data = new ExpandoObject(); - data.royalty_assets = royaltyAssets.ToList(); - data.fungible_assets = fungibleAssets.ToList(); - var response = await WalletProxy.SendMessage("nft_calculate_royalties", data, cancellationToken).ConfigureAwait(false); - return Converters.ToDictionary>(response); + return await WalletProxy.SendMessage("nft_count_nfts", CreateWalletDataObject(), "count", cancellationToken).ConfigureAwait(false); } /// diff --git a/src/chia-dotnet/WalletProxy.cs b/src/chia-dotnet/WalletProxy.cs index 781601f2..63a357af 100644 --- a/src/chia-dotnet/WalletProxy.cs +++ b/src/chia-dotnet/WalletProxy.cs @@ -716,5 +716,61 @@ public async Task> GetCoinRecordsByNames(IEnumerable(response.transactions), response.launcher_id); } + + /// + /// Transfers an NFT to another address. + /// + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task>> CalculateRoyalties(IEnumerable fungibleAssets, IEnumerable royaltyAssets, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.royalty_assets = royaltyAssets.ToList(); + data.fungible_assets = fungibleAssets.ToList(); + var response = await SendMessage("nft_calculate_royalties", data, cancellationToken).ConfigureAwait(false); + return Converters.ToDictionary>(response); + } + + /// + /// Bulk set DID for NFTs across different wallets. + /// + /// + /// + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task<(int TxNum, SpendBundle SpendBundle)> NftSetDidBulk(string didId, IEnumerable nftCoinList, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.nft_coin_list = nftCoinList.ToList(); + data.did_id = didId; + data.fee = fee; + data.reuse_puzhash = reusePuzhash; + var response = await SendMessage("nft_set_did_bulk", data, cancellationToken).ConfigureAwait(false); + return (response.tx_num, Converters.ToObject(response.spend_bundle)); + } + + /// + /// Bulk transfer NFTs to an address. + /// + /// + /// + /// + /// + /// A token to allow the call to be cancelled + /// + public async Task<(int TxNum, SpendBundle SpendBundle)> NftTransferBulk(string targetAddress, IEnumerable nftCoinList, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default) + { + dynamic data = new ExpandoObject(); + data.nft_coin_list = nftCoinList.ToList(); + data.target_address = targetAddress; + data.fee = fee; + data.reuse_puzhash = reusePuzhash; + var response = await SendMessage("nft_transfer_bulk", data, cancellationToken).ConfigureAwait(false); + return (response.tx_num, Converters.ToObject(response.spend_bundle)); + } } }