Skip to content

Commit

Permalink
Offer stuffs (#100)
Browse files Browse the repository at this point in the history
* through dl_owned_singletons

* DL methods

* nft_mint_bulk

* nft updates

* more nft stuffs

* DID stuffs

* remove using

* oofer updates
  • Loading branch information
dkackman authored Aug 5, 2023
1 parent 8523957 commit 1b3990e
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 35 deletions.
20 changes: 10 additions & 10 deletions src/chia-dotnet.tests/TradeManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ public async Task AssetIdToName()
var name = await wallet.GetName(cts.Token);
var assetId = await wallet.GetAssetId(cts.Token);

var id = await _theTradeManager.AssetIdToName(assetId, cancellationToken: cts.Token);
Assert.AreEqual(name, id.Name);
var (WalletId, Name) = await _theTradeManager.AssetIdToName(assetId, cancellationToken: cts.Token);
Assert.AreEqual(name, Name);
}

[TestMethod()]
Expand Down Expand Up @@ -100,7 +100,7 @@ public async Task CreateOfferForIdsInvalidZeroBalance()
{ takerCoinWalletId, -1 }
};

var offer = await _theTradeManager.CreateOffer(idsAndAmounts, 1, true, null, cts.Token);
var offer = await _theTradeManager.CreateOffer(idsAndAmounts, cancellationToken: cts.Token);
}

[TestMethod()]
Expand All @@ -118,7 +118,7 @@ public async Task CreateOfferForIdsValidateOnly()
{ takerCoinWalletId, -1 }
};

var offer = await _theTradeManager.CreateOffer(idsAndAmounts, 1, true, null, cts.Token);
var offer = await _theTradeManager.CreateOffer(idsAndAmounts, validateOnly: true, cancellationToken: cts.Token);

Assert.IsNotNull(offer);
}
Expand All @@ -137,7 +137,7 @@ public async Task CreateOfferForIds()
};

using var cts = new CancellationTokenSource(15000);
var offer = await _theTradeManager.CreateOffer(idsAndAmounts, 1, false, null, cts.Token);
var offer = await _theTradeManager.CreateOffer(idsAndAmounts, fee: 1, cancellationToken: cts.Token);

Assert.IsNotNull(offer);
}
Expand Down Expand Up @@ -168,9 +168,9 @@ public async Task CheckOfferValidity()
// a valid offer requires the actual coins used to create the offer to be un-spent on the blockchain
var validOffer = "offer1qqp83w76wzru6cmqvpsxygqqwc7hynr6hum6e0mnf72sn7uvvkpt68eyumkhelprk0adeg42nlelk2mpafrgx923m0l47yqsaxujnj67dj4d4xhf0dv5fx4uyw6zxasykmyde0v4a9t096w2f4sdn08qc54gum80kkw9wxuh4mwl5a7et253f0ul0k8r8hryflzkawulhqhy0urlr0pck26tq5vvpahyrslmgj67hhq76shmkc37rjja6u9408mdvnyhe7ha7a3m7wdxqkrjvnpg9r2fh73e404q4j6v8claxnm9r27l002hecyn7uyvklvdq3vjvvtr3zscmvtvqcnfks6c9xsygedj8gadj8gadjrgdvz9uykj456sythkzc2d6wus6nh88e0j4gwex9jvfr443wxw2xdezuuxnmu0fpg9ddhhfhaeqd2av70t3fxl5j63kmf44tzlm6e0z07lv7u0dshw6n72juc0jnm67hdruvpj63y3p0u7rh9tqcdmccgm6whn266lelufcunt78xk0d3mz3jrs0eted585lpl22lnrqdrg5avd39jveacfpxq9mwkj09t9320amvqjc0xqscmypke8lctpq6h8l3hxxllsn6cr8yyegrfxcxh54u6p060vtn5372m88as5kx906knga262kvmkcys50mck34wd98lekxy6wuqffklutucz0arrftavw6r39ch0u70lvl9xuxlalyevzudculm067uvqmt26dgx235l0lsha3ua7l056ydazeex0qj7kp0wwazd6h9wwmjsnnlxgt78muc8a48s2zjpz0cl7p822ttnltvf0065uf0ezfh0rrvte5xcua4f4ufn39pydzc8gakxmlv4mlskr4fnj479v9jxpvllrahapj70rwjgrt0jjkkkeh6t0l78rj6l9pvlll8lzl443z37xh797uvzuwql8uu6nkn0veykz7t8zerv6afamutn8dmwt406aflp3knmhv9szmpz654l305p2zaqgxg3ds9p4zpj9w6yt3j47t4n4rse6a3s5h4n4zkhh27lvphzdl3cxl3et7wr5hfpn89pg6qq8gnrdm4e083054n9fnd3tl6e3d8r74le9gjtdjfvh7mvd2p25dj8gml4adzxvddlv668y40sdmxg5nk2yhd0fq0xt957mxchhvm4mwa94uc2k6nzenj4wraekvt6mu0m4naapkqtx8m7ha6yfewavhjlv3hn5audclkuqqqyh2km7gxmzur4";
using var cts = new CancellationTokenSource(2000);
var isValid = await _theTradeManager.CheckOfferValidity(validOffer, cts.Token);
var (Valid, Id) = await _theTradeManager.CheckOfferValidity(validOffer, cts.Token);

Assert.IsTrue(isValid);
Assert.IsTrue(Valid);
}

[TestMethod()]
Expand All @@ -191,7 +191,7 @@ public async Task GetOfferSummary()
// a valid offer requires the actual coins used to create the offer to be un-spent on the blockchain
var validOffer = "offer1qqp83w76wzru6cmqvpsxygqqwc7hynr6hum6e0mnf72sn7uvvkpt68eyumkhelprk0adeg42nlelk2mpafrgx923m0l47yqsaxujnj67dj4d4xhf0dv5fx4uyw6zxasykmyde0v4a9t096w2f4sdn08qc54gum80kkw9wxuh4mwl5a7et253f0ul0k8r8hryflzkawulhqhy0urlr0pck26tq5vvpahyrslmgj67hhq76shmkc37rjja6u9408mdvnyhe7ha7a3m7wdxqkrjvnpg9r2fh73e404q4j6v8claxnm9r27l002hecyn7uyvklvdq3vjvvtr3zscmvtvqcnfks6c9xsygedj8gadj8gadjrgdvz9uykj456sythkzc2d6wus6nh88e0j4gwex9jvfr443wxw2xdezuuxnmu0fpg9ddhhfhaeqd2av70t3fxl5j63kmf44tzlm6e0z07lv7u0dshw6n72juc0jnm67hdruvpj63y3p0u7rh9tqcdmccgm6whn266lelufcunt78xk0d3mz3jrs0eted585lpl22lnrqdrg5avd39jveacfpxq9mwkj09t9320amvqjc0xqscmypke8lctpq6h8l3hxxllsn6cr8yyegrfxcxh54u6p060vtn5372m88as5kx906knga262kvmkcys50mck34wd98lekxy6wuqffklutucz0arrftavw6r39ch0u70lvl9xuxlalyevzudculm067uvqmt26dgx235l0lsha3ua7l056ydazeex0qj7kp0wwazd6h9wwmjsnnlxgt78muc8a48s2zjpz0cl7p822ttnltvf0065uf0ezfh0rrvte5xcua4f4ufn39pydzc8gakxmlv4mlskr4fnj479v9jxpvllrahapj70rwjgrt0jjkkkeh6t0l78rj6l9pvlll8lzl443z37xh797uvzuwql8uu6nkn0veykz7t8zerv6afamutn8dmwt406aflp3knmhv9szmpz654l305p2zaqgxg3ds9p4zpj9w6yt3j47t4n4rse6a3s5h4n4zkhh27lvphzdl3cxl3et7wr5hfpn89pg6qq8gnrdm4e083054n9fnd3tl6e3d8r74le9gjtdjfvh7mvd2p25dj8gml4adzxvddlv668y40sdmxg5nk2yhd0fq0xt957mxchhvm4mwa94uc2k6nzenj4wraekvt6mu0m4naapkqtx8m7ha6yfewavhjlv3hn5audclkuqqqyh2km7gxmzur4";
using var cts = new CancellationTokenSource(10000);
var offerSummary = await _theTradeManager.GetOfferSummary(validOffer, cts.Token);
var offerSummary = await _theTradeManager.GetOfferSummary(validOffer, false, cts.Token);

Assert.IsNotNull(offerSummary);
Assert.IsTrue(offerSummary.Offered.Any());
Expand Down Expand Up @@ -227,9 +227,9 @@ public async Task CancelOfferSecure()
Assert.IsFalse(offer.TradeRecord.Status == TradeStatus.CANCELLED);

using var cts2 = new CancellationTokenSource(2000);
var isValidBefore = await _theTradeManager.CheckOfferValidity(offer.Offer, cts2.Token);
var (Valid, Id) = await _theTradeManager.CheckOfferValidity(offer.Offer, cts2.Token);

Assert.IsTrue(isValidBefore);
Assert.IsTrue(Valid);

// WARNING this creates is a secure cancellation transaction on the blockchain
using var cts3 = new CancellationTokenSource(10000);
Expand Down
14 changes: 0 additions & 14 deletions src/chia-dotnet/Converters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,6 @@ internal static class Converters
});
}

public static IDictionary<TKey, TValue> ToDictionary<TKey, TValue>(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<IDictionary<TKey, TValue>>(jsonString, settings);
}

public static IEnumerable<T> ToEnumerable<T>(dynamic enumerable)
{
Debug.Assert(enumerable is not null);
Expand Down
65 changes: 56 additions & 9 deletions src/chia-dotnet/TradeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,40 @@ public async Task<IEnumerable<CATInfo>> GetCATList(CancellationToken cancellatio
);
}

/// <summary>
/// Cancels multiple offers.
/// </summary>
/// <param name="assetId"></param>
/// <param name="cancelAll"></param>
/// <param name="batchSize"></param>
/// <param name="secure"></param>
/// <param name="batchFee"></param>
/// <param name="cancellationToken">A token to allow the call to be cancelled</param>
/// <returns><see cref=""/></returns>
public async Task CancelOffers(bool secure, string assetId = "xch", bool cancelAll = false, int batchSize = 5, ulong batchFee = 0, CancellationToken cancellationToken = default)
{
dynamic data = new ExpandoObject();
data.batch_fee = batchFee;
data.secure = secure;
data.batch_size = batchSize;
data.cancel_all = cancelAll;
data.asset_id = assetId;
await WalletProxy.SendMessage("cancel_offers", data, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Checks the validity of an offer
/// </summary>
/// <param name="offer">The bech32 encoded offer hex</param>
/// <param name="cancellationToken">A token to allow the call to be cancelled</param>
/// <returns>Indicator of the offer's validity</returns>
public async Task<bool> CheckOfferValidity(string offer, CancellationToken cancellationToken = default)
public async Task<(bool Valid, string Id)> CheckOfferValidity(string offer, CancellationToken cancellationToken = default)
{
dynamic data = new ExpandoObject();
data.offer = offer;

return await WalletProxy.SendMessage<bool>("check_offer_validity", data, "valid", cancellationToken).ConfigureAwait(false);
var response = await WalletProxy.SendMessage<bool>("check_offer_validity", data, cancellationToken).ConfigureAwait(false);
return (response.valid, response.id);
}

/// <summary>
Expand Down Expand Up @@ -191,10 +213,17 @@ public async Task CancelOffer(string tradeId, bool secure = false, ulong fee = 0
/// <param name="fee">Transaction fee</param>
/// <param name="cancellationToken">A token to allow the call to be cancelled</param>
/// <returns>The associated trade record</returns>
public async Task<TradeRecord> TakeOffer(string offer, ulong fee = 0, CancellationToken cancellationToken = default)
public async Task<TradeRecord> TakeOffer(string offer, IDictionary<string, object>? solver = null, ulong minCoinAmount = 0, ulong maxCoinAmount = 0, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default)
{
dynamic data = new ExpandoObject();
data.offer = offer;
if (solver is not null)
{
data.solver = solver;
}
data.min_coin_amount = minCoinAmount;
data.max_coin_amount = maxCoinAmount;
data.reuse_puzhash = reusePuzhash;
data.fee = fee;

return await WalletProxy.SendMessage<TradeRecord>("take_offer", data, "trade_record", cancellationToken).ConfigureAwait(false);
Expand All @@ -204,12 +233,14 @@ public async Task<TradeRecord> TakeOffer(string offer, ulong fee = 0, Cancellati
/// Retrieves the summary of an offer
/// </summary>
/// <param name="offer">The bech32 encoded offer hex</param>
/// <param name="advanced"></param>
/// <param name="cancellationToken">A token to allow the call to be cancelled</param>
/// <returns>The summary of the offer</returns>
public async Task<OfferSummary> GetOfferSummary(string offer, CancellationToken cancellationToken = default)
public async Task<OfferSummary> GetOfferSummary(string offer, bool advanced = false, CancellationToken cancellationToken = default)
{
dynamic data = new ExpandoObject();
data.offer = offer;
data.advanced = advanced;

var response = await WalletProxy.SendMessage("get_offer_summary", data, cancellationToken).ConfigureAwait(false);

Expand All @@ -228,11 +259,14 @@ public async Task<OfferSummary> GetOfferSummary(string offer, CancellationToken
/// </summary>
/// <param name="walletIdsAndMojoAmounts">The set of wallet ids and amounts (in mojo) representing the offer</param>
/// <param name="fee">Transaction fee for offer creation</param>
/// <param name="minCoinAmount"></param>
/// <param name="maxCoinAmount"></param>
/// <param name="validateOnly">Only validate the offer contents. Do not create.</param>
/// <param name="solver"></param>
/// <param name="driver">Additional data about the puzzle</param>
/// <param name="cancellationToken">A token to allow the call to be cancelled</param>
/// <returns>An awaitable <see cref="Task"/></returns>
public async Task<OfferRecord> CreateOffer(IDictionary<uint, long> walletIdsAndMojoAmounts, ulong fee = 0, bool validateOnly = false, IDictionary<string, string>? driver = null, CancellationToken cancellationToken = default)
public async Task<OfferRecord> CreateOffer(IDictionary<uint, long> walletIdsAndMojoAmounts, ulong minCoinAmount = 0, ulong maxCoinAmount = 0, bool validateOnly = false, IDictionary<string, string>? driver = null, IDictionary<string, string>? solver = null, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default)
{
if (walletIdsAndMojoAmounts is null)
{
Expand All @@ -243,12 +277,17 @@ public async Task<OfferRecord> CreateOffer(IDictionary<uint, long> walletIdsAndM
data.offer = walletIdsAndMojoAmounts;
data.fee = fee;
data.validate_only = validateOnly;
data.validate_only = validateOnly;
data.min_coin_amount = minCoinAmount;
data.max_coin_amount = maxCoinAmount;
data.reuse_puzhash = reusePuzhash;
if (solver is not null)
{
data.solver = solver;
}
if (driver is not null)
{
data.driver_dict = driver;
}

return await WalletProxy.SendMessage<OfferRecord>("create_offer_for_ids", data, null, cancellationToken).ConfigureAwait(false);
}

Expand All @@ -261,7 +300,7 @@ public async Task<OfferRecord> CreateOffer(IDictionary<uint, long> walletIdsAndM
/// <param name="driver">Additional data about the puzzle</param>
/// <param name="cancellationToken">A token to allow the call to be cancelled</param>
/// <returns>An awaitable <see cref="Task"/></returns>
public async Task<OfferRecord> CreateOffer(OfferSummary offer, ulong fee = 0, bool validateOnly = false, IDictionary<string, string>? driver = null, CancellationToken cancellationToken = default)
public async Task<OfferRecord> CreateOffer(OfferSummary offer, ulong minCoinAmount = 0, ulong maxCoinAmount = 0, bool validateOnly = false, IDictionary<string, string>? driver = null, IDictionary<string, string>? solver = null, bool reusePuzhash = false, ulong fee = 0, CancellationToken cancellationToken = default)
{
var walletIdsAndMojoAmounts = new Dictionary<uint, long>();
foreach (var requested in offer.Requested)
Expand All @@ -284,7 +323,15 @@ public async Task<OfferRecord> CreateOffer(OfferSummary offer, ulong fee = 0, bo
walletIdsAndMojoAmounts.Add(WalletId.Value, (long)offered.Value * -1); // offered value flipped to negative for RPC call
}

return await CreateOffer(walletIdsAndMojoAmounts, fee, validateOnly, driver, cancellationToken).ConfigureAwait(false);
return await CreateOffer(walletIdsAndMojoAmounts,
minCoinAmount: minCoinAmount,
maxCoinAmount: maxCoinAmount,
validateOnly: validateOnly,
driver: driver,
solver: solver,
reusePuzhash: reusePuzhash,
fee: fee,
cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
}
16 changes: 15 additions & 1 deletion src/chia-dotnet/Wallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,26 @@ public async Task<WalletBalance> GetBalance(CancellationToken cancellationToken
/// Returns a set of coins that can be used for generating a new transaction.
/// </summary>
/// <param name="amount">An amount</param>
/// <param name="excludedCoins"></param>
/// <param name="excludedCoinAmounts"></param>
/// <param name="minCoinAmount"></param>
/// <param name="maxCoinAmount"></param>
/// <param name="cancellationToken">A token to allow the call to be cancelled</param>
/// <returns>The list of <see cref="Token"/>s</returns>
public async Task<IEnumerable<Coin>> SelectCoins(ulong amount, CancellationToken cancellationToken = default)
public async Task<IEnumerable<Coin>> SelectCoins(ulong amount, IEnumerable<Coin>? excludedCoins = null, IEnumerable<ulong>? excludedCoinAmounts = null, ulong minCoinAmount = 0, ulong maxCoinAmount = 0, CancellationToken cancellationToken = default)
{
dynamic data = CreateWalletDataObject();
data.amount = amount;
if (excludedCoins is not null)
{
data.amount = excludedCoins.ToList();
}
if (excludedCoinAmounts is not null)
{
data.amount = excludedCoinAmounts.ToList();
}
data.amount = minCoinAmount;
data.amount = maxCoinAmount;

return await WalletProxy.SendMessage<IEnumerable<Coin>>("select_coins", data, "coins", cancellationToken).ConfigureAwait(false);
}
Expand Down
2 changes: 1 addition & 1 deletion src/chia-dotnet/WalletProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ public async Task<IDictionary<string, IEnumerable<AssetInfo>>> CalculateRoyaltie
data.royalty_assets = royaltyAssets.ToList();
data.fungible_assets = fungibleAssets.ToList();
var response = await SendMessage("nft_calculate_royalties", data, cancellationToken).ConfigureAwait(false);
return Converters.ToDictionary<string, IEnumerable<AssetInfo>>(response);
return Converters.ToObject<IDictionary<string, IEnumerable<AssetInfo>>>(response);
}

/// <summary>
Expand Down

0 comments on commit 1b3990e

Please sign in to comment.