From 964363049556c82f53d5c6505f6ac4a0fc360dde Mon Sep 17 00:00:00 2001 From: Jecket1 <134037206+Jecket1@users.noreply.github.com> Date: Fri, 19 Jul 2024 16:20:17 +0800 Subject: [PATCH 1/5] Collection approve (#168) * feat: add ListedNFTTotalAmountMap * ut: fix ut * feat: modify GetTotalEffectiveListedNFTAmount --- contract/Forest/ForestContractConstants.cs | 2 + contract/Forest/ForestContractState.cs | 5 +++ contract/Forest/ForestContract_Buyers.cs | 28 ++++++++++++ contract/Forest/ForestContract_Helpers.cs | 25 +++++++++++ contract/Forest/ForestContract_Sellers.cs | 44 +++++++++++++++++++ contract/Forest/ForestContract_Views.cs | 17 ++++++- .../InscriptionContractTests.cs | 2 +- .../Forest.Tests/ForestContractTests_Views.cs | 6 +-- 8 files changed, 124 insertions(+), 5 deletions(-) diff --git a/contract/Forest/ForestContractConstants.cs b/contract/Forest/ForestContractConstants.cs index 561026f1..db5de96e 100644 --- a/contract/Forest/ForestContractConstants.cs +++ b/contract/Forest/ForestContractConstants.cs @@ -24,5 +24,7 @@ public partial class ForestContract public const string DefaultAIImageSize256 = "256x256"; public const int DefaultMaxBatchCancelOfferCount= 20; public const int DefaultMaxBatchCancelListCount= 20; + public const string CollectionSymbolSuffix = "0"; + public const string SymbolSeparator = "-"; } \ No newline at end of file diff --git a/contract/Forest/ForestContractState.cs b/contract/Forest/ForestContractState.cs index c21a6ff0..6e598787 100755 --- a/contract/Forest/ForestContractState.cs +++ b/contract/Forest/ForestContractState.cs @@ -53,6 +53,11 @@ public partial class ForestContractState : ContractState /// public MappedState OfferTotalAmountMap { get; set; } + /// + /// Collection Symbol -> User Address -> Listing Amount * decimal + /// + public MappedState ListedNFTTotalAmountMap { get; set; } + public SingletonState AIServiceFeeConfig { get; set; } public SingletonState
AIServiceFeeReceiver { get; set; } diff --git a/contract/Forest/ForestContract_Buyers.cs b/contract/Forest/ForestContract_Buyers.cs index dd167c35..9a3ab4ab 100644 --- a/contract/Forest/ForestContract_Buyers.cs +++ b/contract/Forest/ForestContract_Buyers.cs @@ -346,6 +346,20 @@ private void SingleMakeOfferForBatchBuyNow(string symbol, FixPrice inputFixPrice Quantity = listedNftInfo.Quantity, Price = listedNftInfo.Price, }); + + var collectionSymbol = TransferCollectionSymbol(listedNftInfo.Symbol); + var collectionAllowance = State.ListedNFTTotalAmountMap[collectionSymbol][listedNftInfo.Owner]; + if (collectionAllowance == null || collectionAllowance == "") + { + State.ListedNFTTotalAmountMap[collectionSymbol][listedNftInfo.Owner] = ""; + } + else + { + var originQuantity = long.Parse(collectionAllowance); + var resultQuantity = originQuantity - dealQuantity; + State.ListedNFTTotalAmountMap[collectionSymbol][listedNftInfo.Owner] = + (resultQuantity >= 0 ? resultQuantity : 0).ToString(); + } } } @@ -361,6 +375,20 @@ private void SingleMakeOfferForBatchBuyNow(string symbol, FixPrice inputFixPrice Owner = info.Owner, Price = info.Price }); + var collectionSymbol = TransferCollectionSymbol(info.Symbol); + var collectionAllowance = State.ListedNFTTotalAmountMap[collectionSymbol][info.Owner]; + if (collectionAllowance == null || collectionAllowance == "") + { + State.ListedNFTTotalAmountMap[collectionSymbol][info.Owner] = ""; + } + else + { + var originQuantity = long.Parse(collectionAllowance); + var resultQuantity = originQuantity - info.Quantity; + State.ListedNFTTotalAmountMap[collectionSymbol][info.Owner] = + (resultQuantity >= 0 ? resultQuantity : 0).ToString(); + } + } } diff --git a/contract/Forest/ForestContract_Helpers.cs b/contract/Forest/ForestContract_Helpers.cs index a6955b1f..fe5dc3cc 100644 --- a/contract/Forest/ForestContract_Helpers.cs +++ b/contract/Forest/ForestContract_Helpers.cs @@ -54,6 +54,7 @@ private void PerformDeal(PerformDealInput performDealInput) PurchaseSymbol = performDealInput.PurchaseSymbol, PurchaseAmount = performDealInput.PurchaseAmount }); + } private struct PerformDealInput @@ -309,6 +310,30 @@ private long GetAllowance(Address address, string symbol) }); return allowance?.Allowance ?? 0; } + + public static string TransferCollectionSymbol(string symbol) + { + if (string.IsNullOrEmpty(symbol)) + return symbol; + + var parts = symbol.Split($"{SymbolSeparator}"); + + if (parts.Length == 1) + { + return parts[0]; + } + + if (parts.Length == 2) + { + var baseString = parts[0]; + if (int.TryParse(parts[1], out int number)) + { + return $"{baseString}{SymbolSeparator}{CollectionSymbolSuffix}"; + } + } + + return symbol; + } private void RequireContractAIServiceFeeConfigSet() { diff --git a/contract/Forest/ForestContract_Sellers.cs b/contract/Forest/ForestContract_Sellers.cs index d816d548..e9904e6c 100644 --- a/contract/Forest/ForestContract_Sellers.cs +++ b/contract/Forest/ForestContract_Sellers.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using AElf; using AElf.Contracts.MultiToken; @@ -120,6 +121,20 @@ public override Empty ListWithFixedPrice(ListWithFixedPriceInput input) Quantity = input.Quantity, WhitelistId = whitelistId }); + var allowance = GetAllowance(Context.Sender, input.Symbol); + var collectionSymbol = TransferCollectionSymbol(input.Symbol); + var collectionAllowance = State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender]; + if (collectionAllowance == null || collectionAllowance == "") + { + State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = + Math.Max(allowance, input.Quantity).ToString(); + } + else + { + var originQuantity = long.Parse(collectionAllowance); + State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = + (input.Quantity + originQuantity).ToString(); + } State.ListedNFTInfoListMap[input.Symbol][Context.Sender] = listedNftInfoList; @@ -211,6 +226,20 @@ private Empty SingleDelist(DelistInput input) Owner = Context.Sender, Quantity = input.Quantity }); + + var collectionSymbol = TransferCollectionSymbol(input.Symbol); + var collectionAllowance = State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender]; + if (collectionAllowance == null || collectionAllowance == "") + { + State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = ""; + } + else + { + var originQuantity = long.Parse(collectionAllowance); + var resultQuantity = originQuantity - input.Quantity; + State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = + (resultQuantity >= 0 ? resultQuantity.ToString() : ""); + } return new Empty(); } @@ -275,6 +304,9 @@ public override Empty BatchDeList(BatchDeListInput input) return new Empty(); } + var collectionSymbol = TransferCollectionSymbol(input.Symbol); + var collectionAllowance = State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender]; + foreach (var listedNftInfo in fixedPriceListedNftInfoList) { var projectId = CalculateProjectId(input.Symbol, Context.Sender); @@ -287,6 +319,18 @@ public override Empty BatchDeList(BatchDeListInput input) Owner = listedNftInfo.Owner, Price = listedNftInfo.Price }); + + if (collectionAllowance == null || collectionAllowance == "" || collectionAllowance == "0") + { + continue; + } + + var originQuantity = long.Parse(collectionAllowance); + var resultQuantity = originQuantity - listedNftInfo.Quantity; + State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = + (resultQuantity >= 0 ? resultQuantity : 0).ToString(); + collectionAllowance = State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender]; + } return new Empty(); diff --git a/contract/Forest/ForestContract_Views.cs b/contract/Forest/ForestContract_Views.cs index e947dfc9..383756f6 100644 --- a/contract/Forest/ForestContract_Views.cs +++ b/contract/Forest/ForestContract_Views.cs @@ -1,3 +1,4 @@ +using System; using AElf.Types; using Google.Protobuf.WellKnownTypes; @@ -117,12 +118,26 @@ public override GetTotalOfferAmountOutput GetTotalOfferAmount(GetTotalOfferAmoun public override GetTotalEffectiveListedNFTAmountOutput GetTotalEffectiveListedNFTAmount(GetTotalEffectiveListedNFTAmountInput input) { var totalAmount = GetEffectiveListedNFTTotalAmount(input.Address, input.Symbol); + + var collectionSymbol = TransferCollectionSymbol(input.Symbol); + var collectionAllowance = State.ListedNFTTotalAmountMap[collectionSymbol][input.Address]; var allowance = GetAllowance(input.Address, input.Symbol); + + if (collectionAllowance == null || collectionAllowance == "") + { + return new GetTotalEffectiveListedNFTAmountOutput() + { + Symbol = input.Symbol, + Allowance = allowance, + TotalAmount = Math.Max(allowance,totalAmount) + }; + } + var getTotalEffectiveListedNftAmountOutput = new GetTotalEffectiveListedNFTAmountOutput() { Symbol = input.Symbol, Allowance = allowance, - TotalAmount = totalAmount + TotalAmount = long.Parse(collectionAllowance) }; return getTotalEffectiveListedNftAmountOutput; diff --git a/test/Forest.Contracts.Inscription.Tests/InscriptionContractTests.cs b/test/Forest.Contracts.Inscription.Tests/InscriptionContractTests.cs index 0a2b1d6d..dd9da133 100644 --- a/test/Forest.Contracts.Inscription.Tests/InscriptionContractTests.cs +++ b/test/Forest.Contracts.Inscription.Tests/InscriptionContractTests.cs @@ -1620,7 +1620,7 @@ await TokenContractStub.Create.SendAsync(new CreateInput }); var seedOwnedSymbol = "ELFS" + "-0"; - var seedExpTime = "1720590467"; + var seedExpTime = "1752076800"; await TokenContractStub.Create.SendAsync(new CreateInput { Symbol = "SEED-1", diff --git a/test/Forest.Tests/ForestContractTests_Views.cs b/test/Forest.Tests/ForestContractTests_Views.cs index 6417a2d0..a9d62136 100644 --- a/test/Forest.Tests/ForestContractTests_Views.cs +++ b/test/Forest.Tests/ForestContractTests_Views.cs @@ -375,8 +375,8 @@ await UserTokenContractStub.Approve.SendAsync(new ApproveInput() Symbol = NftSymbol, Address = User1Address })); - getTotalEffectiveListedNftAmount.Allowance.ShouldBe(allowanceQuanlity); - getTotalEffectiveListedNftAmount.TotalAmount.ShouldBe(0); + getTotalEffectiveListedNftAmount.Allowance.ShouldBe(1); + getTotalEffectiveListedNftAmount.TotalAmount.ShouldBe(1); } #endregion @@ -1185,7 +1185,7 @@ await BuyerForestContractStub.MakeOffer.SendAsync(new MakeOfferInput() Address = User1Address })); getTotalEffectiveListedNftAmount.Allowance.ShouldBe(0); - getTotalEffectiveListedNftAmount.TotalAmount.ShouldBe(sellQuantity); + getTotalEffectiveListedNftAmount.TotalAmount.ShouldBe(sellQuantity*2); } #endregion From b101522277acceb853c77d5d6eb572513970e784 Mon Sep 17 00:00:00 2001 From: Jecket1 <134037206+Jecket1@users.noreply.github.com> Date: Fri, 19 Jul 2024 18:24:43 +0800 Subject: [PATCH 2/5] Collection approve (#168) (#170) (#171) * feat: add ListedNFTTotalAmountMap * ut: fix ut * feat: modify GetTotalEffectiveListedNFTAmount From f819a1a2407b90824f42b71a25ecfa9345f972fe Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 24 Jul 2024 17:48:38 +0800 Subject: [PATCH 3/5] optimize max approve --- contract/Forest/ForestContractConstants.cs | 2 ++ contract/Forest/ForestContract_Sellers.cs | 10 ++++++---- contract/Forest/ForestContract_Views.cs | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/contract/Forest/ForestContractConstants.cs b/contract/Forest/ForestContractConstants.cs index db5de96e..28871187 100644 --- a/contract/Forest/ForestContractConstants.cs +++ b/contract/Forest/ForestContractConstants.cs @@ -26,5 +26,7 @@ public partial class ForestContract public const int DefaultMaxBatchCancelListCount= 20; public const string CollectionSymbolSuffix = "0"; public const string SymbolSeparator = "-"; + public const long DefaultApproveAllowance = 10000; + public const long MaxApproveAllowance = 9223372036854775000; } \ No newline at end of file diff --git a/contract/Forest/ForestContract_Sellers.cs b/contract/Forest/ForestContract_Sellers.cs index e9904e6c..bf58488c 100644 --- a/contract/Forest/ForestContract_Sellers.cs +++ b/contract/Forest/ForestContract_Sellers.cs @@ -126,12 +126,14 @@ public override Empty ListWithFixedPrice(ListWithFixedPriceInput input) var collectionAllowance = State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender]; if (collectionAllowance == null || collectionAllowance == "") { - State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = - Math.Max(allowance, input.Quantity).ToString(); + var listedNFTTotalAmount = (allowance == MaxApproveAllowance) ? input.Quantity : Math.Max(allowance, input.Quantity); + State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = listedNFTTotalAmount.ToString(); } else { - var originQuantity = long.Parse(collectionAllowance); + var originQuantity = (long.Parse(collectionAllowance) == MaxApproveAllowance) + ? DefaultApproveAllowance + : long.Parse(collectionAllowance); State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = (input.Quantity + originQuantity).ToString(); } @@ -238,7 +240,7 @@ private Empty SingleDelist(DelistInput input) var originQuantity = long.Parse(collectionAllowance); var resultQuantity = originQuantity - input.Quantity; State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = - (resultQuantity >= 0 ? resultQuantity.ToString() : ""); + (resultQuantity >= 0 ? resultQuantity.ToString() : "0"); } return new Empty(); diff --git a/contract/Forest/ForestContract_Views.cs b/contract/Forest/ForestContract_Views.cs index 383756f6..02a474bd 100644 --- a/contract/Forest/ForestContract_Views.cs +++ b/contract/Forest/ForestContract_Views.cs @@ -129,7 +129,7 @@ public override GetTotalEffectiveListedNFTAmountOutput GetTotalEffectiveListedNF { Symbol = input.Symbol, Allowance = allowance, - TotalAmount = Math.Max(allowance,totalAmount) + TotalAmount = (allowance == MaxApproveAllowance) ? totalAmount : Math.Max(allowance,totalAmount) }; } @@ -137,7 +137,7 @@ public override GetTotalEffectiveListedNFTAmountOutput GetTotalEffectiveListedNF { Symbol = input.Symbol, Allowance = allowance, - TotalAmount = long.Parse(collectionAllowance) + TotalAmount = (long.Parse(collectionAllowance) == MaxApproveAllowance) ? DefaultApproveAllowance : long.Parse(collectionAllowance) }; return getTotalEffectiveListedNftAmountOutput; From 1d09f65b87a7b75af54eedbdf9cc26cf47e01f17 Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 24 Jul 2024 19:51:22 +0800 Subject: [PATCH 4/5] fix issue --- contract/Forest/ForestContractConstants.cs | 5 +++-- contract/Forest/ForestContract_Sellers.cs | 4 ++-- contract/Forest/ForestContract_Views.cs | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/contract/Forest/ForestContractConstants.cs b/contract/Forest/ForestContractConstants.cs index 28871187..c92dc0bf 100644 --- a/contract/Forest/ForestContractConstants.cs +++ b/contract/Forest/ForestContractConstants.cs @@ -27,6 +27,7 @@ public partial class ForestContract public const string CollectionSymbolSuffix = "0"; public const string SymbolSeparator = "-"; public const long DefaultApproveAllowance = 10000; - public const long MaxApproveAllowance = 9223372036854775000; - + public const long MaxApproveAllowance = 9223372036854770000; + + } \ No newline at end of file diff --git a/contract/Forest/ForestContract_Sellers.cs b/contract/Forest/ForestContract_Sellers.cs index bf58488c..3e5cd019 100644 --- a/contract/Forest/ForestContract_Sellers.cs +++ b/contract/Forest/ForestContract_Sellers.cs @@ -126,12 +126,12 @@ public override Empty ListWithFixedPrice(ListWithFixedPriceInput input) var collectionAllowance = State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender]; if (collectionAllowance == null || collectionAllowance == "") { - var listedNFTTotalAmount = (allowance == MaxApproveAllowance) ? input.Quantity : Math.Max(allowance, input.Quantity); + var listedNFTTotalAmount = (allowance >= MaxApproveAllowance) ? input.Quantity : Math.Max(allowance, input.Quantity); State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = listedNFTTotalAmount.ToString(); } else { - var originQuantity = (long.Parse(collectionAllowance) == MaxApproveAllowance) + var originQuantity = (long.Parse(collectionAllowance) >= MaxApproveAllowance) ? DefaultApproveAllowance : long.Parse(collectionAllowance); State.ListedNFTTotalAmountMap[collectionSymbol][Context.Sender] = diff --git a/contract/Forest/ForestContract_Views.cs b/contract/Forest/ForestContract_Views.cs index 02a474bd..31a6089e 100644 --- a/contract/Forest/ForestContract_Views.cs +++ b/contract/Forest/ForestContract_Views.cs @@ -129,7 +129,7 @@ public override GetTotalEffectiveListedNFTAmountOutput GetTotalEffectiveListedNF { Symbol = input.Symbol, Allowance = allowance, - TotalAmount = (allowance == MaxApproveAllowance) ? totalAmount : Math.Max(allowance,totalAmount) + TotalAmount = (allowance >= MaxApproveAllowance) ? totalAmount : Math.Max(allowance,totalAmount) }; } @@ -137,7 +137,7 @@ public override GetTotalEffectiveListedNFTAmountOutput GetTotalEffectiveListedNF { Symbol = input.Symbol, Allowance = allowance, - TotalAmount = (long.Parse(collectionAllowance) == MaxApproveAllowance) ? DefaultApproveAllowance : long.Parse(collectionAllowance) + TotalAmount = (long.Parse(collectionAllowance) >= MaxApproveAllowance) ? DefaultApproveAllowance : long.Parse(collectionAllowance) }; return getTotalEffectiveListedNftAmountOutput; From d4cf510100ef8d585e8c237fb35f583733e7c23e Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 25 Jul 2024 14:12:15 +0800 Subject: [PATCH 5/5] modify max value --- contract/Forest/ForestContractConstants.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/Forest/ForestContractConstants.cs b/contract/Forest/ForestContractConstants.cs index c92dc0bf..fa17ac75 100644 --- a/contract/Forest/ForestContractConstants.cs +++ b/contract/Forest/ForestContractConstants.cs @@ -27,7 +27,7 @@ public partial class ForestContract public const string CollectionSymbolSuffix = "0"; public const string SymbolSeparator = "-"; public const long DefaultApproveAllowance = 10000; - public const long MaxApproveAllowance = 9223372036854770000; + public const long MaxApproveAllowance = 9223372000000000000; } \ No newline at end of file