From b7fa1bfe33b264278278bdb682fb6676687ca05b Mon Sep 17 00:00:00 2001 From: suerlych <19871208@lhcyf> Date: Mon, 2 Dec 2024 21:39:55 +0800 Subject: [PATCH 1/9] add normal seed renew --- .../Forest.Contracts.SymbolRegistrar.csproj | 3 + .../SymbolRegistrarContractConstants.cs | 2 + .../SymbolRegistrarContract_Action.cs | 52 ++++++++++++++ .../SymbolRegistrarContract_Helper.cs | 25 +++++++ protobuf/symbol_registrar_contract.proto | 27 ++++++- protobuf/token_contract_impl.proto | 70 ++++++++++++------- 6 files changed, 151 insertions(+), 28 deletions(-) diff --git a/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj b/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj index fe15d2b9..76490d11 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj +++ b/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj @@ -40,6 +40,9 @@ Protobuf\Proto\reference\token_contract.proto + + Protobuf\Proto\token_contract_impl.proto + diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractConstants.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractConstants.cs index ad43c930..82a5e115 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractConstants.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractConstants.cs @@ -16,6 +16,8 @@ public class SymbolRegistrarContractConstants public const int MaxAddSpecialSeedCount = 500; public const int MaxSymbolLength = 30; public const string SeedPrefix = "SEED-"; + public const string SeedPrefixPart = "SEED"; + public const int MaxCycleCount = 30; public const string CollectionSymbolSuffix = "0"; public const string SeedOwnedSymbolExternalInfoKey = "__seed_owned_symbol"; diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs index a83450d3..f9930d2e 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs @@ -124,6 +124,11 @@ private void DoCreateSeed(Address to, string symbol, long expireTime = 0) ImageUrl = seedInfo.ImageUrl }); } + + private void DoRenewSeed(string seedSymbol, long expireTime = 0) + { + //State.TokenContract + } private bool CreateSeedToken(Address issuer, string symbol, long expireTime = 0) { @@ -213,5 +218,52 @@ private Hash GetProxyAccountHash() State.ProxyAccountHash.Value = proxyAccount.ProxyAccountHash; return proxyAccount.ProxyAccountHash; } + + public override Empty GeneralSeedRenew(GeneralSeedRenewInput input) + { + AssertContractInitialize(); + AssertSeedSymbolPattern(input.SeedSymbol); + CheckSeedBalanceExisted(input.SeedSymbol); + var seedTokenInfo = GetTokenInfo(input.SeedSymbol); + Assert(seedTokenInfo.Symbol.Length > 1, "Seed Symbol not exists"); + var seedOwnedSymbol = seedTokenInfo.ExternalInfo.Value[SymbolRegistrarContractConstants.SeedOwnedSymbolExternalInfoKey]; + var seedExpTime = long.Parse(seedTokenInfo.ExternalInfo.Value[SymbolRegistrarContractConstants.SeedExpireTimeExternalInfoKey]); + Assert(!string.IsNullOrWhiteSpace(seedOwnedSymbol) && seedExpTime > Context.CurrentBlockTime.Seconds, "symbol seed not existed or expired"); + + var specialSeed = State.SpecialSeedMap[seedOwnedSymbol]; + Assert(specialSeed == null, "Special seed " + input.SeedSymbol + " not support renew."); + + var price = GetDealPrice(seedOwnedSymbol); + Assert(price != null, "Symbol price not exits"); + Assert(price.Symbol == input.Price.Symbol && price.Amount == input.Price.Amount, "input symbol price not correct"); + + State.TokenContract.TransferFrom.Send(new TransferFromInput() + { + From = Context.Sender, + To = State.ReceivingAccount.Value, + Symbol = price.Symbol, + Amount = price.Amount, + }); + + var nextExpTime = seedExpTime + State.SeedExpirationConfig.Value; + DoRenewSeed(input.SeedSymbol, nextExpTime); + + Context.Fire(new SeedRenewed() + { + Buyer = Context.Sender, + Symbol = seedOwnedSymbol, + SeedSymbol = input.SeedSymbol, + ExpTime = nextExpTime, + Price = new Price + { + Symbol = input.Price.Symbol, + Amount = input.Price.Amount + } + }); + + return new Empty(); + } } + + } \ No newline at end of file diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs index ca74340c..9c0e839e 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs @@ -55,6 +55,21 @@ private void AssertSymbolPattern(string symbol) } } + private void AssertSeedSymbolPattern(string symbol) + { + Assert(symbol.Length > 0 && symbol.Length <= SymbolRegistrarContractConstants.MaxSymbolLength, + "Invalid symbol length."); + + var symbolPartition = symbol.Split(SymbolRegistrarContractConstants.NFTSymbolSeparator); + Assert(symbolPartition.Length == 2, "Invalid symbol."); + Assert(symbolPartition[0] == SymbolRegistrarContractConstants.SeedPrefixPart, "Invalid seed symbol prefix."); + + foreach (var c in symbolPartition[1]) + { + Assert(c >= 1 && c <= 9, "Invalid seed symbol suffix."); + } + } + private void AssertPriceListLength(PriceList priceList) { Assert(priceList?.Value?.Count == SymbolRegistrarContractConstants.MaxSymbolLength, @@ -155,5 +170,15 @@ private void CheckSymbolExisted(string symbol) var collectionSeed = State.SymbolSeedMap[collectionSymbol]; Assert(string.IsNullOrWhiteSpace(collectionSeed) || State.SeedInfoMap[collectionSeed].ExpireTime < Context.CurrentBlockTime.Seconds, "symbol seed existed"); } + + private void CheckSeedBalanceExisted(string symbol) + { + var balance = State.TokenContract.GetBalance.Call(new GetBalanceInput + { + Symbol = symbol, + Owner = Context.Sender + }); + Assert(balance.Balance == 1, $"you don't have enough {symbol}"); + } } } \ No newline at end of file diff --git a/protobuf/symbol_registrar_contract.proto b/protobuf/symbol_registrar_contract.proto index 2b711d6e..c63f614a 100644 --- a/protobuf/symbol_registrar_contract.proto +++ b/protobuf/symbol_registrar_contract.proto @@ -32,6 +32,12 @@ service SymbolRegistrarContract { rpc Buy(BuyInput) returns (google.protobuf.Empty){ } + + rpc GeneralSeedRenew(GeneralSeedRenewInput) returns (google.protobuf.Empty){ + } + + rpc SpecialSeedRenew(SpecialSeedRenewInput) returns (google.protobuf.Empty){ + } // for Parliament contract // when proposal has been approved special-seeds will be add @@ -269,7 +275,6 @@ message SpecialSeed { map external_info = 8; } - message BuyInput{ // the symbol to buy string symbol = 1; @@ -277,6 +282,17 @@ message BuyInput{ aelf.Address issue_to = 2; } +message GeneralSeedRenewInput{ + //seedSymbol + string seed_symbol = 1; + Price price = 2; +} + +message SpecialSeedRenewInput{ + string seed_symbol = 1; + Price price = 2; +} + message ControllerList{ repeated aelf.Address controllers = 1; } @@ -354,6 +370,15 @@ message Bought { Price price = 4; } +message SeedRenewed { + option (aelf.is_event) = true; + aelf.Address buyer = 1; + string symbol = 2; + string seed_symbol = 3; + int64 exp_time = 4; + Price price = 5; +} + message SaleControllerAdded { option (aelf.is_event) = true; ControllerList addresses = 1; diff --git a/protobuf/token_contract_impl.proto b/protobuf/token_contract_impl.proto index 5885914e..fbccc194 100644 --- a/protobuf/token_contract_impl.proto +++ b/protobuf/token_contract_impl.proto @@ -24,11 +24,11 @@ service TokenContractImpl { option (aelf.base) = "acs1.proto"; option (aelf.base) = "acs2.proto"; option (aelf.base) = "token_contract.proto"; - + // Transfer resource tokens to designated contract address. rpc AdvanceResourceToken (AdvanceResourceTokenInput) returns (google.protobuf.Empty) { } - + // Take token from contract address. rpc TakeResourceTokenBack (TakeResourceTokenBackInput) returns (google.protobuf.Empty) { } @@ -36,15 +36,15 @@ service TokenContractImpl { // Register the token contract address for cross chain. rpc RegisterCrossChainTokenContractAddress (RegisterCrossChainTokenContractAddressInput) returns (google.protobuf.Empty) { } - + // Set the receiver address of the side chain transaction fee. rpc SetFeeReceiver (aelf.Address) returns (google.protobuf.Empty) { } - + // Validates if the token exist. rpc ValidateTokenInfoExists(ValidateTokenInfoExistsInput) returns (google.protobuf.Empty){ } - + // Update the rental unit price of the side chain. rpc UpdateRental (UpdateRentalInput) returns (google.protobuf.Empty) { } @@ -56,23 +56,23 @@ service TokenContractImpl { // Transfer Token to the specified contract. rpc TransferToContract (TransferToContractInput) returns (google.protobuf.Empty) { } - + // Change the governance organization of side chain rental. rpc ChangeSideChainRentalController (AuthorityInfo) returns (google.protobuf.Empty) { } - + // Change the governance organization for tokens to pay transaction fees. rpc ChangeSymbolsToPayTXSizeFeeController(AuthorityInfo) returns (google.protobuf.Empty){ } - + // Change the governance organization for cross-chain token contract address registration. rpc ChangeCrossChainTokenContractRegistrationController (AuthorityInfo) returns (google.protobuf.Empty) { } - + // Change the governance organization of the coefficient of the user transaction fee calculation formula. rpc ChangeUserFeeController (AuthorityInfo) returns (google.protobuf.Empty) { } - + // Change the governance organization of the coefficient of the developer's transaction resource fee calculation formula. rpc ChangeDeveloperController (AuthorityInfo) returns (google.protobuf.Empty) { } @@ -84,18 +84,18 @@ service TokenContractImpl { } rpc SetMaxBatchApproveCount (google.protobuf.Int32Value) returns (google.protobuf.Empty) { - + } - + // Delegatee sets the delegation and related information of the delegator based on a transaction. rpc SetTransactionFeeDelegateInfos (SetTransactionFeeDelegateInfosInput) returns (google.protobuf.Empty){ } - + // Delegatee remove delegator info based on a transaction. rpc RemoveTransactionFeeDelegatorInfos (RemoveTransactionFeeDelegatorInfosInput) returns (google.protobuf.Empty){ } - + // Delegator remove delegatee info based on a transaction. rpc RemoveTransactionFeeDelegateeInfos (RemoveTransactionFeeDelegateeInfosInput) returns (google.protobuf.Empty){ } @@ -104,48 +104,48 @@ service TokenContractImpl { rpc GetFeeReceiver (google.protobuf.Empty) returns (aelf.Address){ option (aelf.is_view) = true; } - + // Query the amount of resources usage currently. rpc GetResourceUsage (google.protobuf.Empty) returns (ResourceUsage) { option (aelf.is_view) = true; } - + // Query the governance organization for tokens to pay transaction fees. rpc GetSymbolsToPayTXSizeFeeController(google.protobuf.Empty) returns (AuthorityInfo){ option (aelf.is_view) = true; } - + // Query the governance organization of the rpc GetCrossChainTokenContractRegistrationController (google.protobuf.Empty) returns (AuthorityInfo) { option (aelf.is_view) = true; } - + // Query the governance organization that calculates the formula coefficient // for the transaction cost the user sends the contract. rpc GetUserFeeController(google.protobuf.Empty) returns (UserFeeController){ option (aelf.is_view) = true; } - + // Query the governing organization of the formula coefficients for calculating developer contract transaction fee. rpc GetDeveloperFeeController (google.protobuf.Empty) returns (DeveloperFeeController) { option (aelf.is_view) = true; } - + // Query the organization that governs the side chain rental fee. rpc GetSideChainRentalControllerCreateInfo (google.protobuf.Empty) returns (AuthorityInfo) { option (aelf.is_view) = true; } - + // Compute the virtual address for locking. rpc GetVirtualAddressForLocking (GetVirtualAddressForLockingInput) returns (aelf.Address) { option (aelf.is_view) = true; } - + // Query how much resource tokens should be paid currently. rpc GetOwningRental (google.protobuf.Empty) returns (OwningRental) { option (aelf.is_view) = true; } - + // Query the unit price of the side chain resource cost, resource cost = unit price * quantity, // the quantity can be queried through GetResourceUsage. rpc GetOwningRentalUnitValue (google.protobuf.Empty) returns (OwningRentalUnitValue) { @@ -159,7 +159,7 @@ service TokenContractImpl { rpc GetTransactionFeeFreeAllowancesConfig (google.protobuf.Empty) returns (GetTransactionFeeFreeAllowancesConfigOutput) { option (aelf.is_view) = true; } - + // Get delegatee info list according to the delegator and transaction. rpc GetTransactionFeeDelegateeList (GetTransactionFeeDelegateeListInput) returns (GetTransactionFeeDelegateeListOutput) { option (aelf.is_view) = true; @@ -168,13 +168,13 @@ service TokenContractImpl { rpc GetTransactionFeeDelegateInfo(GetTransactionFeeDelegateInfoInput) returns (token.TransactionFeeDelegations){ option (aelf.is_view) = true; } - + rpc ModifyTokenIssuerAndOwner(ModifyTokenIssuerAndOwnerInput) returns (google.protobuf.Empty) { } - + rpc SetTokenIssuerAndOwnerModificationEnabled(SetTokenIssuerAndOwnerModificationEnabledInput) returns (google.protobuf.Empty) { } - + rpc GetTokenIssuerAndOwnerModificationEnabled(google.protobuf.Empty) returns (google.protobuf.BoolValue) { option (aelf.is_view) = true; } @@ -182,6 +182,9 @@ service TokenContractImpl { rpc GetMaxBatchApproveCount (google.protobuf.Empty) returns (google.protobuf.Int32Value) { } + + rpc ExtendSeedExpirationTime (ExtendSeedExpirationTimeInput) returns (google.protobuf.Empty) { + } } message AdvanceResourceTokenInput { @@ -444,4 +447,17 @@ message ModifyTokenIssuerAndOwnerInput { message SetTokenIssuerAndOwnerModificationEnabledInput{ bool enabled = 1; +} + +message ExtendSeedExpirationTimeInput { + string symbol = 1; + int64 expiration_time = 2; +} + +message SeedExpirationTimeUpdated { + option (aelf.is_event) = true; + int32 chain_id = 1; + string symbol = 2; + int64 old_expiration_time = 3; + int64 new_expiration_time = 4; } \ No newline at end of file From f562d9f2b21371ae9fe42ab773d06fa22284d8b0 Mon Sep 17 00:00:00 2001 From: suerlych <19871208@lhcyf> Date: Mon, 2 Dec 2024 22:03:11 +0800 Subject: [PATCH 2/9] impl DoRenewSeed --- .../SymbolRegistrarContractReferenceState.cs | 2 ++ .../SymbolRegistrarContract_Action.cs | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractReferenceState.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractReferenceState.cs index 652caae8..b323b292 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractReferenceState.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractReferenceState.cs @@ -20,5 +20,7 @@ internal AElf.Contracts.ProxyAccountContract.ProxyAccountContractContainer.Proxy get; set; } + + internal TokenContractImplContainer.TokenContractImplReferenceState TokenImplContract { get; set; } } } \ No newline at end of file diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs index f9930d2e..4b11d437 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs @@ -127,7 +127,13 @@ private void DoCreateSeed(Address to, string symbol, long expireTime = 0) private void DoRenewSeed(string seedSymbol, long expireTime = 0) { - //State.TokenContract + + State.TokenImplContract.ExtendSeedExpirationTime.Send( + new ExtendSeedExpirationTimeInput + { + Symbol = seedSymbol, + ExpirationTime = expireTime + }); } private bool CreateSeedToken(Address issuer, string symbol, long expireTime = 0) From 88945086bd11359cb917a8e3edb3060fec979e4a Mon Sep 17 00:00:00 2001 From: suerlych <19871208@lhcyf> Date: Tue, 3 Dec 2024 14:21:58 +0800 Subject: [PATCH 3/9] add bid seed renew --- .../SymbolRegistrarContractState.cs | 5 + .../SymbolRegistrarContract_Action.cs | 114 +++++++++++++++++- .../SymbolRegistrarContract_Admin.cs | 15 +++ protobuf/symbol_registrar_contract.proto | 33 ++++- 4 files changed, 160 insertions(+), 7 deletions(-) diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractState.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractState.cs index fb8e9c42..f4ce56dd 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractState.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractState.cs @@ -40,5 +40,10 @@ public partial class SymbolRegistrarContractState : ContractState public SingletonState IssueChainList { get; set; } public SingletonState
SeedCollectionOwner { get; set; } public SingletonState ProxyAccountHash { get; set; } + + public SingletonState SeedRenewHashVerifyKey { get; set; } + //seedSymbol -> renewTime + public MappedState SeedRenewTimeMap { get; set; } + } } \ No newline at end of file diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs index 4b11d437..4ff9f0ce 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs @@ -225,7 +225,7 @@ private Hash GetProxyAccountHash() return proxyAccount.ProxyAccountHash; } - public override Empty GeneralSeedRenew(GeneralSeedRenewInput input) + public override Empty RegularSeedRenew(RegularSeedRenewInput input) { AssertContractInitialize(); AssertSeedSymbolPattern(input.SeedSymbol); @@ -256,19 +256,129 @@ public override Empty GeneralSeedRenew(GeneralSeedRenewInput input) Context.Fire(new SeedRenewed() { + ChainId = Context.ChainId, Buyer = Context.Sender, Symbol = seedOwnedSymbol, SeedSymbol = input.SeedSymbol, ExpTime = nextExpTime, + OriginalExpTime = seedExpTime, Price = new Price { Symbol = input.Price.Symbol, Amount = input.Price.Amount - } + }, + SeedType = SeedType.Regular, + RenewType = RenewType.Self }); return new Empty(); } + + public override Empty SpecialSeedRenew(SpecialSeedRenewInput input) + { + AssertContractInitialize(); + AssertSeedSymbolPattern(input.SeedSymbol); + CheckSeedBalanceExisted(input.SeedSymbol); + Assert(Context.Sender == input.Buyer, "param owner not sender"); + var seedTokenInfo = GetTokenInfo(input.SeedSymbol); + Assert(seedTokenInfo.Symbol.Length > 1, "Seed Symbol not exists"); + var seedOwnedSymbol = seedTokenInfo.ExternalInfo.Value[SymbolRegistrarContractConstants.SeedOwnedSymbolExternalInfoKey]; + var seedExpTime = long.Parse(seedTokenInfo.ExternalInfo.Value[SymbolRegistrarContractConstants.SeedExpireTimeExternalInfoKey]); + Assert(!string.IsNullOrWhiteSpace(seedOwnedSymbol) && seedExpTime > Context.CurrentBlockTime.Seconds, "symbol seed not existed or expired"); + + var specialSeed = State.SpecialSeedMap[seedOwnedSymbol]; + Assert(specialSeed != null, "Not Special seed " + input.SeedSymbol + " not support renew."); + var requestStr = string.Concat(input.Buyer.ToBase58(), input.SeedSymbol); + requestStr = string.Concat(requestStr, input.Price.Symbol, input.Price.Amount, input.OpTime); + CheckSeedRenewRequestHash(requestStr, input.RequestHash); + var lastAddTime = State.SeedRenewTimeMap[input.SeedSymbol]; + Assert(input.OpTime > lastAddTime, "Invalid param OpTime"); + State.SeedRenewTimeMap[input.SeedSymbol] = input.OpTime; + + var price = input.Price; + Assert(price != null, "Symbol price not exits"); + var priceTokenInfo = GetTokenInfo(price.Symbol); + Assert(priceTokenInfo != null, "input price symbol not correct"); + Assert(price.Amount > 0, "input price amount not correct"); + + State.TokenContract.TransferFrom.Send(new TransferFromInput() + { + From = Context.Sender, + To = State.ReceivingAccount.Value, + Symbol = price.Symbol, + Amount = price.Amount, + }); + + var nextExpTime = seedExpTime + State.SeedExpirationConfig.Value; + DoRenewSeed(input.SeedSymbol, nextExpTime); + + Context.Fire(new SeedRenewed() + { + ChainId = Context.ChainId, + Buyer = Context.Sender, + Symbol = seedOwnedSymbol, + SeedSymbol = input.SeedSymbol, + ExpTime = nextExpTime, + OriginalExpTime = seedExpTime, + Price = new Price + { + Symbol = input.Price.Symbol, + Amount = input.Price.Amount + }, + SeedType = SeedType.Unique, + RenewType = RenewType.Self + }); + + return new Empty(); + } + + + public override Empty BidFinishSeedRenew(BidFinishSeedRenewInput input) + { + AssertContractInitialize(); + AssertSeedSymbolPattern(input.SeedSymbol); + CheckSeedBalanceExisted(input.SeedSymbol); + var seedTokenInfo = GetTokenInfo(input.SeedSymbol); + Assert(seedTokenInfo.Symbol.Length > 1, "Seed Symbol not exists"); + var seedOwnedSymbol = seedTokenInfo.ExternalInfo.Value[SymbolRegistrarContractConstants.SeedOwnedSymbolExternalInfoKey]; + var seedExpTime = long.Parse(seedTokenInfo.ExternalInfo.Value[SymbolRegistrarContractConstants.SeedExpireTimeExternalInfoKey]); + Assert(!string.IsNullOrWhiteSpace(seedOwnedSymbol) && seedExpTime > Context.CurrentBlockTime.Seconds, "symbol seed not existed or expired"); + Assert(input.BidFinishTime > seedExpTime && input.BidFinishTime < Context.CurrentBlockTime.Seconds, "bid finish time not correct"); + + var specialSeed = State.SpecialSeedMap[seedOwnedSymbol]; + Assert(specialSeed != null, "Not Special seed " + input.SeedSymbol + " not support renew."); + var requestStr = string.Concat(input.SeedSymbol, input.BidFinishTime, input.OpTime); + CheckSeedRenewRequestHash(requestStr, input.RequestHash); + var lastAddTime = State.SeedRenewTimeMap[input.SeedSymbol]; + Assert(input.OpTime > lastAddTime, "Invalid param OpTime"); + State.SeedRenewTimeMap[input.SeedSymbol] = input.OpTime; + + var nextExpTime = input.BidFinishTime + State.SeedExpirationConfig.Value; + DoRenewSeed(input.SeedSymbol, nextExpTime); + + Context.Fire(new SeedRenewed() + { + ChainId = Context.ChainId, + Buyer = Context.Sender, + Symbol = seedOwnedSymbol, + SeedSymbol = input.SeedSymbol, + ExpTime = nextExpTime, + OriginalExpTime = seedExpTime, + SeedType = SeedType.Unique, + RenewType = RenewType.Bid + }); + + return new Empty(); + } + + private void CheckSeedRenewRequestHash(string request, string hash) + { + var key = State.SeedRenewHashVerifyKey.Value; + Assert(!string.IsNullOrEmpty(key), "Need SetTreePointsHashVerifyKey"); + var requestHash = HashHelper.ComputeFrom(string.Concat(request, key)); + Assert(hash.Equals(requestHash.ToHex()), "Unverified requests"); + } + } diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Admin.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Admin.cs index 380fe285..1b11fd0c 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Admin.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Admin.cs @@ -399,5 +399,20 @@ public override Empty RemoveIssueChain(IssueChainList input) return new Empty(); } + + public override Empty SetSeedRenewHashVerifyKey(StringValue input) + { + AssertInitialized(); + Assert(input != null && !string.IsNullOrEmpty(input.Value), "Invalid param key"); + var key = State.SeedRenewHashVerifyKey.Value; + if (string.IsNullOrEmpty(key)) + { + State.SeedRenewHashVerifyKey.Value = input.Value; + return new Empty(); + } + AssertAdmin(); + State.SeedRenewHashVerifyKey.Value = input.Value; + return new Empty(); + } } } \ No newline at end of file diff --git a/protobuf/symbol_registrar_contract.proto b/protobuf/symbol_registrar_contract.proto index c63f614a..25aee1f7 100644 --- a/protobuf/symbol_registrar_contract.proto +++ b/protobuf/symbol_registrar_contract.proto @@ -33,12 +33,15 @@ service SymbolRegistrarContract { rpc Buy(BuyInput) returns (google.protobuf.Empty){ } - rpc GeneralSeedRenew(GeneralSeedRenewInput) returns (google.protobuf.Empty){ + rpc RegularSeedRenew(RegularSeedRenewInput) returns (google.protobuf.Empty){ } rpc SpecialSeedRenew(SpecialSeedRenewInput) returns (google.protobuf.Empty){ } + rpc BidFinishSeedRenew(BidFinishSeedRenewInput) returns (google.protobuf.Empty){ + } + // for Parliament contract // when proposal has been approved special-seeds will be add rpc AddSpecialSeeds(SpecialSeedList) returns (google.protobuf.Empty) { @@ -94,7 +97,8 @@ service SymbolRegistrarContract { rpc RemoveIssueChain(IssueChainList) returns (google.protobuf.Empty) { } - + rpc SetSeedRenewHashVerifyKey(google.protobuf.StringValue)returns (google.protobuf.Empty){ + } // View @@ -256,6 +260,11 @@ enum SeedType { REGULAR = 4; } +enum RenewType { + SELF = 0; + BID = 1; +} + message SpecialSeed { // special seed SeedType seed_type = 1; @@ -281,16 +290,26 @@ message BuyInput{ // which address to issue aelf.Address issue_to = 2; } - -message GeneralSeedRenewInput{ +//REGULAR +message RegularSeedRenewInput{ //seedSymbol string seed_symbol = 1; Price price = 2; } message SpecialSeedRenewInput{ + aelf.Address buyer = 1; + string seed_symbol = 2; + Price price = 3; + int64 op_time = 4; + string request_hash = 5; +} + +message BidFinishSeedRenewInput{ string seed_symbol = 1; - Price price = 2; + int64 bid_finish_time = 2; + int64 op_time = 3; + string request_hash = 4; } message ControllerList{ @@ -377,6 +396,10 @@ message SeedRenewed { string seed_symbol = 3; int64 exp_time = 4; Price price = 5; + int64 original_exp_time =6; + SeedType seed_type=7; + RenewType renew_type=8; + int32 chain_id = 9; } message SaleControllerAdded { From f4ceb21793f878520aaf6bf54b0e2098427d7a5d Mon Sep 17 00:00:00 2001 From: suerlych <19871208@lhcyf> Date: Wed, 4 Dec 2024 14:08:10 +0800 Subject: [PATCH 4/9] fix seed check --- .../SymbolRegistrarContract_Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs index 9c0e839e..c5e5acd6 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs @@ -66,7 +66,7 @@ private void AssertSeedSymbolPattern(string symbol) foreach (var c in symbolPartition[1]) { - Assert(c >= 1 && c <= 9, "Invalid seed symbol suffix."); + Assert(c >= '1' && c <= '9', "Invalid seed symbol suffix."); } } From 2d49b9363c5770f52a5d37bdc39fa52c34bad6c9 Mon Sep 17 00:00:00 2001 From: suerlych <19871208@lhcyf> Date: Wed, 4 Dec 2024 16:14:48 +0800 Subject: [PATCH 5/9] fix seed renew --- .../Forest.Contracts.SymbolRegistrar.csproj | 10 +++++++++ .../SymbolRegistrarContract_Action.cs | 21 ++++++++++++++----- .../SymbolRegistrarContractTests_Buy.cs | 16 +++++++++++++- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj b/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj index 76490d11..5d7acf82 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj +++ b/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj @@ -19,6 +19,12 @@ Protobuf\Proto\acs0.proto + + Protobuf\Proto\reference\acs1.proto + + + Protobuf\Proto\reference\acs2.proto + Protobuf\Proto\acs3.proto @@ -40,9 +46,13 @@ Protobuf\Proto\reference\token_contract.proto + Protobuf\Proto\token_contract_impl.proto + + Protobuf\Proto\reference\transaction_fee.proto + diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs index 4ff9f0ce..d9ddbcee 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs @@ -124,15 +124,26 @@ private void DoCreateSeed(Address to, string symbol, long expireTime = 0) ImageUrl = seedInfo.ImageUrl }); } - private void DoRenewSeed(string seedSymbol, long expireTime = 0) { + if (State.TokenImplContract.Value == null) + { + State.TokenImplContract.Value = State.TokenContract.Value; + } + + var renewInput = new ExtendSeedExpirationTimeInput + { + Symbol = seedSymbol, + ExpirationTime = expireTime + }; - State.TokenImplContract.ExtendSeedExpirationTime.Send( - new ExtendSeedExpirationTimeInput + State.ProxyAccountContract.ForwardCall.Send( + new ForwardCallInput { - Symbol = seedSymbol, - ExpirationTime = expireTime + ContractAddress = State.TokenContract.Value, + MethodName = nameof(State.TokenImplContract.ExtendSeedExpirationTime), + ProxyAccountHash = GetProxyAccountHash(), + Args = renewInput.ToByteString() }); } diff --git a/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Buy.cs b/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Buy.cs index a3e42127..fc23011e 100644 --- a/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Buy.cs +++ b/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Buy.cs @@ -313,6 +313,20 @@ public async Task Buy_existsFT_fail() res.ShouldNotBeNull(); res.Message.ShouldContain("Symbol exists"); } - + + [Fact] + public async Task SeedRenew_Test () + { + await Buy_success(); + await User1SymbolRegistrarContractStub.RegularSeedRenew.SendAsync(new RegularSeedRenewInput() + { + SeedSymbol = "SEED-1", + Price = new Price() + { + Symbol = "ELF", + Amount = 4700000000 + } + }); + } } } \ No newline at end of file From e4b7e9d5e69166ccfc43ac78640ea50c0edb1699 Mon Sep 17 00:00:00 2001 From: suerlych <19871208@lhcyf> Date: Wed, 4 Dec 2024 23:52:21 +0800 Subject: [PATCH 6/9] BidFinishSeedRenew no need check balance --- .../SymbolRegistrarContract_Action.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs index d9ddbcee..4ab2cec8 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs @@ -348,13 +348,11 @@ public override Empty BidFinishSeedRenew(BidFinishSeedRenewInput input) { AssertContractInitialize(); AssertSeedSymbolPattern(input.SeedSymbol); - CheckSeedBalanceExisted(input.SeedSymbol); var seedTokenInfo = GetTokenInfo(input.SeedSymbol); Assert(seedTokenInfo.Symbol.Length > 1, "Seed Symbol not exists"); var seedOwnedSymbol = seedTokenInfo.ExternalInfo.Value[SymbolRegistrarContractConstants.SeedOwnedSymbolExternalInfoKey]; var seedExpTime = long.Parse(seedTokenInfo.ExternalInfo.Value[SymbolRegistrarContractConstants.SeedExpireTimeExternalInfoKey]); Assert(!string.IsNullOrWhiteSpace(seedOwnedSymbol) && seedExpTime > Context.CurrentBlockTime.Seconds, "symbol seed not existed or expired"); - Assert(input.BidFinishTime > seedExpTime && input.BidFinishTime < Context.CurrentBlockTime.Seconds, "bid finish time not correct"); var specialSeed = State.SpecialSeedMap[seedOwnedSymbol]; Assert(specialSeed != null, "Not Special seed " + input.SeedSymbol + " not support renew."); From 50ffd662520a3ae730c915dfdf5b49041f5306b2 Mon Sep 17 00:00:00 2001 From: suerlych <19871208@lhcyf> Date: Thu, 5 Dec 2024 10:54:42 +0800 Subject: [PATCH 7/9] add ut --- .../SymbolRegistrarContract_Action.cs | 2 +- .../SymbolRegistrarContractTests_Admin.cs | 13 +++++++++++++ .../SymbolRegistrarContractTests_Buy.cs | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs index 4ab2cec8..f9daf2aa 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs @@ -383,7 +383,7 @@ public override Empty BidFinishSeedRenew(BidFinishSeedRenewInput input) private void CheckSeedRenewRequestHash(string request, string hash) { var key = State.SeedRenewHashVerifyKey.Value; - Assert(!string.IsNullOrEmpty(key), "Need SetTreePointsHashVerifyKey"); + Assert(!string.IsNullOrEmpty(key), "Need Set SeedRenewHashVerifyKey"); var requestHash = HashHelper.ComputeFrom(string.Concat(request, key)); Assert(hash.Equals(requestHash.ToHex()), "Unverified requests"); } diff --git a/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Admin.cs b/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Admin.cs index 4215cf07..5c5419a2 100644 --- a/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Admin.cs +++ b/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Admin.cs @@ -515,5 +515,18 @@ public async Task IssueChainListTests() } + + [Fact] + public async Task SetSeedRenewHashVerifyKeyTests() + { + await InitializeContract(); + var value = "1a2b3c"; + await AdminSymbolRegistrarContractStub.SetSeedRenewHashVerifyKey.SendAsync(new StringValue() + { + Value = value + }); + var result = AdminSymbolRegistrarContractStub.GetSeedRenewHashVerifyKey.CallAsync(new Empty()); + result.Result.Value.ShouldBe(value); + } } } \ No newline at end of file diff --git a/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Buy.cs b/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Buy.cs index fc23011e..d1b2983c 100644 --- a/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Buy.cs +++ b/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Buy.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using AElf.Contracts.MultiToken; +using Google.Protobuf.WellKnownTypes; using Shouldly; using Xunit; @@ -328,5 +329,20 @@ await User1SymbolRegistrarContractStub.RegularSeedRenew.SendAsync(new RegularSee } }); } + + [Fact] + public async Task BidSeedRenew_Test () + { + await Buy_success(); + await User1SymbolRegistrarContractStub.SetSeedRenewHashVerifyKey.SendAsync(new StringValue{Value = "1a2b3c"}); + await User1SymbolRegistrarContractStub.BidFinishSeedRenew.SendAsync(new BidFinishSeedRenewInput() + { + SeedSymbol = "SEED-1", + BidFinishTime = DateTime.UtcNow.Second, + OpTime = DateTime.UtcNow.Second, + RequestHash = "1234" + }); + + } } } \ No newline at end of file From a4768ab41f875bc19feb3ee8008d49a7a5630e47 Mon Sep 17 00:00:00 2001 From: suerlych <19871208@lhcyf> Date: Sat, 7 Dec 2024 13:58:21 +0800 Subject: [PATCH 8/9] fix seed suffix check --- .../SymbolRegistrarContract_Helper.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs index c5e5acd6..67a4b460 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs @@ -63,11 +63,6 @@ private void AssertSeedSymbolPattern(string symbol) var symbolPartition = symbol.Split(SymbolRegistrarContractConstants.NFTSymbolSeparator); Assert(symbolPartition.Length == 2, "Invalid symbol."); Assert(symbolPartition[0] == SymbolRegistrarContractConstants.SeedPrefixPart, "Invalid seed symbol prefix."); - - foreach (var c in symbolPartition[1]) - { - Assert(c >= '1' && c <= '9', "Invalid seed symbol suffix."); - } } private void AssertPriceListLength(PriceList priceList) From 55800a6ad28e30c5b08dbbd7f702138b550ae1c1 Mon Sep 17 00:00:00 2001 From: suerlych <19871208@lhcyf> Date: Sat, 7 Dec 2024 23:28:21 +0800 Subject: [PATCH 9/9] modify hash seq --- .../SymbolRegistrarContract_Action.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs index f9daf2aa..f92b593d 100644 --- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs +++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs @@ -299,13 +299,14 @@ public override Empty SpecialSeedRenew(SpecialSeedRenewInput input) var specialSeed = State.SpecialSeedMap[seedOwnedSymbol]; Assert(specialSeed != null, "Not Special seed " + input.SeedSymbol + " not support renew."); - var requestStr = string.Concat(input.Buyer.ToBase58(), input.SeedSymbol); - requestStr = string.Concat(requestStr, input.Price.Symbol, input.Price.Amount, input.OpTime); + var requestStr = string.Concat(input.Buyer.ToBase58(), input.SeedSymbol,input.Price.Symbol, input.Price.Amount); + requestStr = string.Concat(requestStr,input.OpTime); CheckSeedRenewRequestHash(requestStr, input.RequestHash); var lastAddTime = State.SeedRenewTimeMap[input.SeedSymbol]; Assert(input.OpTime > lastAddTime, "Invalid param OpTime"); State.SeedRenewTimeMap[input.SeedSymbol] = input.OpTime; + var price = input.Price; Assert(price != null, "Symbol price not exits"); var priceTokenInfo = GetTokenInfo(price.Symbol);