diff --git a/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj b/contract/Forest.Contracts.SymbolRegistrar/Forest.Contracts.SymbolRegistrar.csproj
index fe15d2b..5d7acf8 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,6 +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/SymbolRegistrarContractConstants.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractConstants.cs
index ad43c93..82a5e11 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/SymbolRegistrarContractReferenceState.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractReferenceState.cs
index 652caae..b323b29 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/SymbolRegistrarContractState.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContractState.cs
index fb8e9c4..f4ce56d 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 a83450d..f92b593 100644
--- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs
+++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Action.cs
@@ -124,6 +124,28 @@ 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.ProxyAccountContract.ForwardCall.Send(
+ new ForwardCallInput
+ {
+ ContractAddress = State.TokenContract.Value,
+ MethodName = nameof(State.TokenImplContract.ExtendSeedExpirationTime),
+ ProxyAccountHash = GetProxyAccountHash(),
+ Args = renewInput.ToByteString()
+ });
+ }
private bool CreateSeedToken(Address issuer, string symbol, long expireTime = 0)
{
@@ -213,5 +235,161 @@ private Hash GetProxyAccountHash()
State.ProxyAccountHash.Value = proxyAccount.ProxyAccountHash;
return proxyAccount.ProxyAccountHash;
}
+
+ public override Empty RegularSeedRenew(RegularSeedRenewInput 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()
+ {
+ 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,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);
+ 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);
+ 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.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 Set SeedRenewHashVerifyKey");
+ var requestHash = HashHelper.ComputeFrom(string.Concat(request, key));
+ Assert(hash.Equals(requestHash.ToHex()), "Unverified requests");
+ }
+
}
+
+
}
\ No newline at end of file
diff --git a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Admin.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Admin.cs
index 380fe28..1b11fd0 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/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs
index ca74340..67a4b46 100644
--- a/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs
+++ b/contract/Forest.Contracts.SymbolRegistrar/SymbolRegistrarContract_Helper.cs
@@ -55,6 +55,16 @@ 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.");
+ }
+
private void AssertPriceListLength(PriceList priceList)
{
Assert(priceList?.Value?.Count == SymbolRegistrarContractConstants.MaxSymbolLength,
@@ -155,5 +165,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 2b711d6..25aee1f 100644
--- a/protobuf/symbol_registrar_contract.proto
+++ b/protobuf/symbol_registrar_contract.proto
@@ -32,6 +32,15 @@ service SymbolRegistrarContract {
rpc Buy(BuyInput) 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
@@ -88,7 +97,8 @@ service SymbolRegistrarContract {
rpc RemoveIssueChain(IssueChainList) returns (google.protobuf.Empty) {
}
-
+ rpc SetSeedRenewHashVerifyKey(google.protobuf.StringValue)returns (google.protobuf.Empty){
+ }
// View
@@ -250,6 +260,11 @@ enum SeedType {
REGULAR = 4;
}
+enum RenewType {
+ SELF = 0;
+ BID = 1;
+}
+
message SpecialSeed {
// special seed
SeedType seed_type = 1;
@@ -269,13 +284,33 @@ message SpecialSeed {
map external_info = 8;
}
-
message BuyInput{
// the symbol to buy
string symbol = 1;
// which address to issue
aelf.Address issue_to = 2;
}
+//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;
+ int64 bid_finish_time = 2;
+ int64 op_time = 3;
+ string request_hash = 4;
+}
message ControllerList{
repeated aelf.Address controllers = 1;
@@ -354,6 +389,19 @@ 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;
+ int64 original_exp_time =6;
+ SeedType seed_type=7;
+ RenewType renew_type=8;
+ int32 chain_id = 9;
+}
+
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 5885914..fbccc19 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
diff --git a/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Admin.cs b/test/Forest.Contracts.SymbolRegistrar.Tests/SymbolRegistrarContractTests_Admin.cs
index 4215cf0..5c5419a 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 a3e4212..d1b2983 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;
@@ -313,6 +314,35 @@ 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
+ }
+ });
+ }
+
+ [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