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/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/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/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/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..700ad714 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;
@@ -32,30 +34,53 @@ 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);
}
+ ///
+ /// Retrieves the number of NFTs in a wallet.
+ ///
+ /// A token to allow the call to be cancelled
+ /// The number of NFTs in the wallet
+ public async Task NftCountNfts(CancellationToken cancellationToken = default)
+ {
+ return await WalletProxy.SendMessage("nft_count_nfts", CreateWalletDataObject(), "count", cancellationToken).ConfigureAwait(false);
+ }
+
///
/// 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");
}
@@ -64,8 +89,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);
@@ -76,39 +101,119 @@ 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
- 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
+ /// 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();
+
+ 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));
}
///
/// 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);
}
@@ -134,14 +239,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 eb007831..63a357af 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);
}
@@ -696,5 +700,77 @@ 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);
+ }
+
+ ///
+ /// 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));
+ }
}
}