diff --git a/contract/AElf.Contracts.MultiToken/TokenContractConstants.cs b/contract/AElf.Contracts.MultiToken/TokenContractConstants.cs
index a14a4e9496..8a41b78140 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContractConstants.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContractConstants.cs
@@ -22,4 +22,6 @@ public static class TokenContractConstants
public const string SeedCollectionSymbol = "SEED-0";
public const string SeedOwnedSymbolExternalInfoKey = "__seed_owned_symbol";
public const string SeedExpireTimeExternalInfoKey = "__seed_exp_time";
+ public const string NftCreateChainIdExternalInfoKey = "__nft_create_chain_id";
+ public const int DefaultMaxBatchApproveCount = 100;
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.MultiToken/TokenContractState.cs b/contract/AElf.Contracts.MultiToken/TokenContractState.cs
index c32b0ea62f..b687cf1598 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContractState.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContractState.cs
@@ -65,4 +65,6 @@ public partial class TokenContractState : ContractState
public SingletonState
VoteContractAddress { get; set; }
public SingletonState TokenIssuerAndOwnerModificationDisabled { get; set; }
+
+ public SingletonState MaxBatchApproveCount { get; set; }
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_Actions.cs b/contract/AElf.Contracts.MultiToken/TokenContract_Actions.cs
index 249afc33ea..f7ff4e2812 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_Actions.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_Actions.cs
@@ -32,8 +32,6 @@ public override Empty InitializeFromParentChain(InitializeFromParentChainInput i
///
public override Empty Create(CreateInput input)
{
- // can not call create on side chain
- Assert(State.SideChainCreator.Value == null, "Failed to create token if side chain creator already set.");
var inputSymbolType = GetCreateInputSymbolType(input.Symbol);
if (input.Owner == null)
{
@@ -52,6 +50,9 @@ private Empty CreateToken(CreateInput input, SymbolType symbolType = SymbolType.
AssertValidCreateInput(input, symbolType);
if (symbolType == SymbolType.Token || symbolType == SymbolType.NftCollection)
{
+ // can not call create on side chain
+ Assert(State.SideChainCreator.Value == null,
+ "Failed to create token if side chain creator already set.");
if (!IsAddressInCreateWhiteList(Context.Sender) &&
input.Symbol != TokenContractConstants.SeedCollectionSymbol)
{
@@ -253,14 +254,35 @@ public override Empty Approve(ApproveInput input)
{
AssertValidInputAddress(input.Spender);
AssertValidToken(input.Symbol, input.Amount);
- State.Allowances[Context.Sender][input.Spender][input.Symbol] = input.Amount;
+ Approve(input.Spender, input.Symbol, input.Amount);
+ return new Empty();
+ }
+
+ private void Approve(Address spender, string symbol, long amount)
+ {
+ State.Allowances[Context.Sender][spender][symbol] = amount;
Context.Fire(new Approved
{
Owner = Context.Sender,
- Spender = input.Spender,
- Symbol = input.Symbol,
- Amount = input.Amount
+ Spender = spender,
+ Symbol = symbol,
+ Amount = amount
});
+ }
+
+ public override Empty BatchApprove(BatchApproveInput input)
+ {
+ Assert(input != null && input.Value != null && input.Value.Count > 0, "Invalid input .");
+ Assert(input.Value.Count <= GetMaxBatchApproveCount(), "Exceeds the max batch approve count.");
+ foreach (var approve in input.Value)
+ {
+ AssertValidInputAddress(approve.Spender);
+ AssertValidToken(approve.Symbol, approve.Amount);
+ }
+ var approveInputList = input.Value.GroupBy(approve => approve.Symbol + approve.Spender, approve => approve)
+ .Select(approve => approve.Last()).ToList();
+ foreach (var approve in approveInputList)
+ Approve(approve.Spender, approve.Symbol, approve.Amount);
return new Empty();
}
@@ -468,7 +490,6 @@ public override Empty CrossChainCreateToken(CrossChainCreateTokenInput input)
Owner = validateTokenInfoExistsInput.Owner ?? validateTokenInfoExistsInput.Issuer
};
RegisterTokenInfo(tokenInfo);
-
Context.Fire(new TokenCreated
{
Symbol = validateTokenInfoExistsInput.Symbol,
@@ -626,4 +647,27 @@ public override BoolValue GetTokenIssuerAndOwnerModificationEnabled(Empty input)
Value = !State.TokenIssuerAndOwnerModificationDisabled.Value
};
}
+
+ public override Empty SetMaxBatchApproveCount(Int32Value input)
+ {
+ Assert(input.Value > 0, "Invalid input.");
+ AssertSenderAddressWith(GetDefaultParliamentController().OwnerAddress);
+ State.MaxBatchApproveCount.Value = input.Value;
+ return new Empty();
+ }
+
+ public override Int32Value GetMaxBatchApproveCount(Empty input)
+ {
+ return new Int32Value
+ {
+ Value = GetMaxBatchApproveCount()
+ };
+ }
+
+ private int GetMaxBatchApproveCount()
+ {
+ return State.MaxBatchApproveCount.Value == 0
+ ? TokenContractConstants.DefaultMaxBatchApproveCount
+ : State.MaxBatchApproveCount.Value;
+ }
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_NFTHelper.cs b/contract/AElf.Contracts.MultiToken/TokenContract_NFTHelper.cs
index bddfb444bf..4c3efdf6a3 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_NFTHelper.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_NFTHelper.cs
@@ -13,8 +13,4 @@ private SymbolType GetCreateInputSymbolType(string symbol)
return words[1] == TokenContractConstants.CollectionSymbolSuffix ? SymbolType.NftCollection : SymbolType.Nft;
}
- private void AssertNFTCreateInput(CreateInput input)
- {
- Assert(input.Decimals == 0, "NFT's decimals must be 0");
- }
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs b/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs
index 1926727e68..124d1dac73 100644
--- a/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs
+++ b/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs
@@ -9,23 +9,34 @@ public partial class TokenContract
{
private Empty CreateNFTCollection(CreateInput input)
{
- AssertNFTCreateInput(input);
return CreateToken(input, SymbolType.NftCollection);
}
private Empty CreateNFTInfo(CreateInput input)
{
- AssertNFTCreateInput(input);
var nftCollectionInfo = AssertNftCollectionExist(input.Symbol);
input.IssueChainId = input.IssueChainId == 0 ? nftCollectionInfo.IssueChainId : input.IssueChainId;
- Assert(input.IssueChainId == nftCollectionInfo.IssueChainId,
- "NFT create ChainId must be collection's issue chainId");
-
+ Assert(
+ input.IssueChainId == nftCollectionInfo.IssueChainId,
+ "NFT issue ChainId must be collection's issue chainId");
+ if (nftCollectionInfo.ExternalInfo != null && nftCollectionInfo.ExternalInfo.Value.TryGetValue(
+ TokenContractConstants.NftCreateChainIdExternalInfoKey,
+ out var nftCreateChainId) && long.TryParse(nftCreateChainId, out var nftCreateChainIdLong))
+ {
+ Assert(nftCreateChainIdLong == Context.ChainId,
+ "NFT create ChainId must be collection's NFT create chainId");
+ }
+ else
+ {
+ Assert(State.SideChainCreator.Value == null,
+ "Failed to create token if side chain creator already set.");
+ }
+
var owner = nftCollectionInfo.Owner ?? nftCollectionInfo.Issuer;
Assert(Context.Sender == owner && owner == input.Owner, "NFT owner must be collection's owner");
-
if (nftCollectionInfo.Symbol == TokenContractConstants.SeedCollectionSymbol)
{
+ Assert(input.Decimals == 0 && input.TotalSupply == 1, "SEED must be unique.");
Assert(input.ExternalInfo.Value.TryGetValue(TokenContractConstants.SeedOwnedSymbolExternalInfoKey,
out var ownedSymbol), "OwnedSymbol does not exist.");
Assert(input.ExternalInfo.Value.TryGetValue(TokenContractConstants.SeedExpireTimeExternalInfoKey,
diff --git a/contract/AElf.Contracts.Profit/ProfitContract.cs b/contract/AElf.Contracts.Profit/ProfitContract.cs
index c3c09b3aba..a1f43d1af4 100644
--- a/contract/AElf.Contracts.Profit/ProfitContract.cs
+++ b/contract/AElf.Contracts.Profit/ProfitContract.cs
@@ -769,18 +769,19 @@ public override Empty ClaimProfits(ClaimProfitsInput input)
Context.LogDebug(() =>
$"Profitable details: {profitableDetails.Aggregate("\n", (profit1, profit2) => profit1.ToString() + "\n" + profit2)}");
+ var profitableDetailCount =
+ Math.Min(ProfitContractConstants.ProfitReceivingLimitForEachTime, profitableDetails.Count);
+ var maxProfitReceivingPeriodCount = GetMaximumPeriodCountForProfitableDetail(profitableDetailCount);
// Only can get profit from last profit period to actual last period (profit.CurrentPeriod - 1),
// because current period not released yet.
- for (var i = 0;
- i < Math.Min(ProfitContractConstants.ProfitReceivingLimitForEachTime, profitableDetails.Count);
- i++)
+ for (var i = 0; i < profitableDetailCount; i++)
{
var profitDetail = profitableDetails[i];
if (profitDetail.LastProfitPeriod == 0)
// This detail never performed profit before.
profitDetail.LastProfitPeriod = profitDetail.StartPeriod;
- ProfitAllPeriods(scheme, profitDetail, beneficiary);
+ ProfitAllPeriods(scheme, profitDetail, beneficiary, maxProfitReceivingPeriodCount);
}
var profitDetailsToRemove = profitableDetails
@@ -807,7 +808,41 @@ public override Empty ClaimProfits(ClaimProfitsInput input)
return new Empty();
}
- private Dictionary ProfitAllPeriods(Scheme scheme, ProfitDetail profitDetail, Address beneficiary,
+ ///
+ /// This method calculates the maximum period count for a profitable detail
+ /// based on the number of profitable details and the maximum profit receiving period
+ /// For example:
+ /// If the number of profitable detail is 10 and the maximum profit receiving period is 100,
+ /// the maximum period count for a profitable detail will be 10.
+ /// If the number of profitable detail is 10 and the maximum profit receiving period is 5,
+ /// the maximum period count for a profitable detail will be 1.
+ ///
+ /// The number of profitable details
+ ///
+ private int GetMaximumPeriodCountForProfitableDetail(int profitableDetailCount)
+ {
+ // Get the maximum profit receiving period count
+ var maxPeriodCount = GetMaximumProfitReceivingPeriodCount();
+ // Check if the maximum period count is greater than the profitable detail count
+ // and if the profitable detail count is greater than 0
+ return maxPeriodCount > profitableDetailCount && profitableDetailCount > 0
+ // Divide the maximum period count by the profitable detail count
+ ? maxPeriodCount.Div(profitableDetailCount)
+ // If the conditions are not met, return 1 as the maximum period count
+ : 1;
+ }
+
+ public override Empty SetMaximumProfitReceivingPeriodCount(Int32Value input)
+ {
+ ValidateContractState(State.ParliamentContract, SmartContractConstants.ParliamentContractSystemName);
+ Assert(Context.Sender == State.ParliamentContract.GetDefaultOrganizationAddress.Call(new Empty()),
+ "No permission.");
+ Assert(input.Value > 0, "Invalid maximum profit receiving period count.");
+ State.MaximumProfitReceivingPeriodCount.Value = input.Value;
+ return new Empty();
+ }
+
+ private Dictionary ProfitAllPeriods(Scheme scheme, ProfitDetail profitDetail, Address beneficiary, long maxProfitReceivingPeriodCount,
bool isView = false, string targetSymbol = null)
{
var profitsMap = new Dictionary();
@@ -818,13 +853,11 @@ private Dictionary ProfitAllPeriods(Scheme scheme, ProfitDetail pr
foreach (var symbol in symbols)
{
var totalAmount = 0L;
- for (var period = profitDetail.LastProfitPeriod;
- period <= (profitDetail.EndPeriod == long.MaxValue
- ? Math.Min(scheme.CurrentPeriod - 1,
- profitDetail.LastProfitPeriod.Add(ProfitContractConstants
- .MaximumProfitReceivingPeriodCountOfOneTime))
- : Math.Min(scheme.CurrentPeriod - 1, profitDetail.EndPeriod));
- period++)
+ var targetPeriod = Math.Min(scheme.CurrentPeriod - 1, profitDetail.EndPeriod);
+ var maxProfitPeriod = profitDetail.EndPeriod == long.MaxValue
+ ? Math.Min(scheme.CurrentPeriod - 1, profitDetail.LastProfitPeriod.Add(maxProfitReceivingPeriodCount))
+ : Math.Min(targetPeriod, profitDetail.LastProfitPeriod.Add(maxProfitReceivingPeriodCount));
+ for (var period = profitDetail.LastProfitPeriod; period <= maxProfitPeriod; period++)
{
var periodToPrint = period;
var detailToPrint = profitDetail;
@@ -885,6 +918,15 @@ private Dictionary ProfitAllPeriods(Scheme scheme, ProfitDetail pr
return profitsMap;
}
+
+ private int GetMaximumProfitReceivingPeriodCount()
+ {
+ var maxPeriodCount = State.MaximumProfitReceivingPeriodCount.Value;
+ maxPeriodCount = maxPeriodCount == 0
+ ? ProfitContractConstants.DefaultMaximumProfitReceivingPeriodCountOfOneTime
+ : maxPeriodCount;
+ return maxPeriodCount;
+ }
private void ValidateContractState(ContractReferenceState state, string contractSystemName)
{
diff --git a/contract/AElf.Contracts.Profit/ProfitContractConstants.cs b/contract/AElf.Contracts.Profit/ProfitContractConstants.cs
index 59b80b971f..0aaf080aa5 100644
--- a/contract/AElf.Contracts.Profit/ProfitContractConstants.cs
+++ b/contract/AElf.Contracts.Profit/ProfitContractConstants.cs
@@ -6,5 +6,5 @@ public class ProfitContractConstants
public const int DefaultProfitReceivingDuePeriodCount = 10;
public const int MaximumProfitReceivingDuePeriodCount = 1024;
public const int TokenAmountLimit = 5;
- public const int MaximumProfitReceivingPeriodCountOfOneTime = 100;
+ public const int DefaultMaximumProfitReceivingPeriodCountOfOneTime = 100;
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.Profit/ProfitContractState.cs b/contract/AElf.Contracts.Profit/ProfitContractState.cs
index 7a525e3ff6..b0046830e0 100644
--- a/contract/AElf.Contracts.Profit/ProfitContractState.cs
+++ b/contract/AElf.Contracts.Profit/ProfitContractState.cs
@@ -17,4 +17,6 @@ public partial class ProfitContractState : ContractState
public MappedState TransactionFees { get; set; }
public SingletonState MethodFeeController { get; set; }
+
+ public SingletonState MaximumProfitReceivingPeriodCount { get; set; }
}
\ No newline at end of file
diff --git a/contract/AElf.Contracts.Profit/ViewMethods.cs b/contract/AElf.Contracts.Profit/ViewMethods.cs
index 31d8c0d4d6..190204c3c5 100644
--- a/contract/AElf.Contracts.Profit/ViewMethods.cs
+++ b/contract/AElf.Contracts.Profit/ViewMethods.cs
@@ -61,49 +61,53 @@ private Hash GeneratePeriodVirtualAddressFromHash(Hash schemeId, long period)
public override Int64Value GetProfitAmount(GetProfitAmountInput input)
{
- var profitItem = State.SchemeInfos[input.SchemeId];
- Assert(profitItem != null, "Scheme not found.");
- var beneficiary = input.Beneficiary ?? Context.Sender;
- var profitDetails = State.ProfitDetailsMap[input.SchemeId][beneficiary];
+ var allProfitsMapResult = GetAllProfitsMap(input.SchemeId, input.Beneficiary, input.Symbol);
- if (profitDetails == null) return new Int64Value { Value = 0 };
-
- var profitVirtualAddress = Context.ConvertVirtualAddressToContractAddress(input.SchemeId);
+ return new Int64Value
+ {
+ Value = allProfitsMapResult.AllProfitsMap.TryGetValue(input.Symbol, out var value) ? value : 0
+ };
+ }
- // ReSharper disable once PossibleNullReferenceException
- var availableDetails = profitDetails.Details.Where(d =>
- d.LastProfitPeriod < profitItem.CurrentPeriod && (d.LastProfitPeriod == 0
- ? d.EndPeriod >= d.StartPeriod
- : d.EndPeriod >= d.LastProfitPeriod)
- ).ToList();
+ public override GetAllProfitAmountOutput GetAllProfitAmount(GetAllProfitAmountInput input)
+ {
+ var allProfitsMapResult = GetAllProfitsMap(input.SchemeId, input.Beneficiary, input.Symbol);
+ return new GetAllProfitAmountOutput
+ {
+ AllProfitAmount = allProfitsMapResult.AllProfitsMap.TryGetValue(input.Symbol, out var allProfitAmount)
+ ? allProfitAmount
+ : 0,
+ OneTimeClaimableProfitAmount =
+ allProfitsMapResult.OneTimeClaimableProfitsMap.TryGetValue(input.Symbol,
+ out var oneTimeClaimableProfitAmount)
+ ? oneTimeClaimableProfitAmount
+ : 0
+ };
+ }
- var amount = 0L;
+ public override ReceivedProfitsMap GetProfitsMap(ClaimProfitsInput input)
+ {
+ var allProfitsMapResult = GetAllProfitsMap(input.SchemeId, input.Beneficiary);
- for (var i = 0;
- i < Math.Min(ProfitContractConstants.ProfitReceivingLimitForEachTime, availableDetails.Count);
- i++)
+ return new ReceivedProfitsMap
{
- var profitDetail = availableDetails[i];
- if (profitDetail.LastProfitPeriod == 0) profitDetail.LastProfitPeriod = profitDetail.StartPeriod;
-
- var profitsDict = ProfitAllPeriods(profitItem, profitDetail, beneficiary, true,
- input.Symbol);
- amount = amount.Add(profitsDict[input.Symbol]);
- }
+ Value = { allProfitsMapResult.AllProfitsMap }
+ };
+ }
- return new Int64Value { Value = amount };
+ public override GetAllProfitsMapOutput GetAllProfitsMap(GetAllProfitsMapInput input)
+ {
+ return GetAllProfitsMap(input.SchemeId, input.Beneficiary);
}
- public override ReceivedProfitsMap GetProfitsMap(ClaimProfitsInput input)
+ private GetAllProfitsMapOutput GetAllProfitsMap(Hash schemeId, Address beneficiary, string symbol = null)
{
- var scheme = State.SchemeInfos[input.SchemeId];
+ var scheme = State.SchemeInfos[schemeId];
Assert(scheme != null, "Scheme not found.");
- var beneficiary = input.Beneficiary ?? Context.Sender;
- var profitDetails = State.ProfitDetailsMap[input.SchemeId][beneficiary];
-
- if (profitDetails == null) return new ReceivedProfitsMap();
+ beneficiary = beneficiary ?? Context.Sender;
+ var profitDetails = State.ProfitDetailsMap[schemeId][beneficiary];
- var profitVirtualAddress = Context.ConvertVirtualAddressToContractAddress(input.SchemeId);
+ if (profitDetails == null) return new GetAllProfitsMapOutput();
// ReSharper disable once PossibleNullReferenceException
var availableDetails = profitDetails.Details.Where(d =>
@@ -111,26 +115,46 @@ public override ReceivedProfitsMap GetProfitsMap(ClaimProfitsInput input)
? d.EndPeriod >= d.StartPeriod
: d.EndPeriod >= d.LastProfitPeriod)
).ToList();
-
- var profitsDict = new Dictionary();
- for (var i = 0;
- i < Math.Min(ProfitContractConstants.ProfitReceivingLimitForEachTime, availableDetails.Count);
- i++)
+
+ var profitableDetailCount =
+ Math.Min(ProfitContractConstants.ProfitReceivingLimitForEachTime, availableDetails.Count);
+ var maxProfitReceivingPeriodCount = GetMaximumPeriodCountForProfitableDetail(profitableDetailCount);
+
+ var allProfitsDict = new Dictionary();
+ var claimableProfitsDict = new Dictionary();
+ for (var i = 0; i < availableDetails.Count; i++)
{
var profitDetail = availableDetails[i];
if (profitDetail.LastProfitPeriod == 0) profitDetail.LastProfitPeriod = profitDetail.StartPeriod;
-
- var profitsDictForEachProfitDetail = ProfitAllPeriods(scheme, profitDetail, beneficiary, true);
- foreach (var kv in profitsDictForEachProfitDetail)
- if (profitsDict.ContainsKey(kv.Key))
- profitsDict[kv.Key] = profitsDict[kv.Key].Add(kv.Value);
- else
- profitsDict[kv.Key] = kv.Value;
+
+ var totalProfitsDictForEachProfitDetail = ProfitAllPeriods(scheme, profitDetail, beneficiary, profitDetail.EndPeriod.Sub(profitDetail.LastProfitPeriod),true, symbol);
+ AddProfitToDict(allProfitsDict, totalProfitsDictForEachProfitDetail);
+ if(i >= profitableDetailCount) continue;
+ var claimableProfitsDictForEachProfitDetail = ProfitAllPeriods(scheme, profitDetail, beneficiary, maxProfitReceivingPeriodCount,true, symbol);
+ AddProfitToDict(claimableProfitsDict, claimableProfitsDictForEachProfitDetail);
}
- return new ReceivedProfitsMap
+ return new GetAllProfitsMapOutput
+ {
+ AllProfitsMap = { allProfitsDict },
+ OneTimeClaimableProfitsMap = { claimableProfitsDict }
+ };
+ }
+
+ private void AddProfitToDict(Dictionary profitsDict, Dictionary profitsToAdd)
+ {
+ foreach (var kv in profitsToAdd)
+ if (profitsDict.ContainsKey(kv.Key))
+ profitsDict[kv.Key] = profitsDict[kv.Key].Add(kv.Value);
+ else
+ profitsDict[kv.Key] = kv.Value;
+ }
+
+ public override Int32Value GetMaximumProfitReceivingPeriodCount(Empty input)
+ {
+ return new Int32Value
{
- Value = { profitsDict }
+ Value = GetMaximumProfitReceivingPeriodCount()
};
}
}
\ No newline at end of file
diff --git a/protobuf/profit_contract.proto b/protobuf/profit_contract.proto
index 1326da62ff..aac44f2d6a 100644
--- a/protobuf/profit_contract.proto
+++ b/protobuf/profit_contract.proto
@@ -63,6 +63,9 @@ service ProfitContract {
// Reset the manager of a scheme.
rpc ResetManager (ResetManagerInput) returns (google.protobuf.Empty) {
}
+
+ rpc SetMaximumProfitReceivingPeriodCount(google.protobuf.Int32Value) returns (google.protobuf.Empty) {
+ }
// Get all schemes managed by the specified manager.
rpc GetManagingSchemeIds (GetManagingSchemeIdsInput) returns (CreatedSchemeIds) {
@@ -93,11 +96,25 @@ service ProfitContract {
rpc GetProfitAmount (GetProfitAmountInput) returns (google.protobuf.Int64Value) {
option (aelf.is_view) = true;
}
+
+ // Query the amount of profit according to token symbol.
+ rpc GetAllProfitAmount (GetAllProfitAmountInput) returns (GetAllProfitAmountOutput) {
+ option (aelf.is_view) = true;
+ }
// Query all profit (up to 10 periods).
rpc GetProfitsMap (ClaimProfitsInput) returns (ReceivedProfitsMap) {
option (aelf.is_view) = true;
}
+
+ // Query all profit.
+ rpc GetAllProfitsMap (GetAllProfitsMapInput) returns (GetAllProfitsMapOutput) {
+ option (aelf.is_view) = true;
+ }
+
+ rpc GetMaximumProfitReceivingPeriodCount(google.protobuf.Empty) returns (google.protobuf.Int32Value) {
+ option (aelf.is_view) = true;
+ }
}
message CreateSchemeInput {
@@ -308,11 +325,39 @@ message GetProfitAmountInput {
aelf.Address beneficiary = 3;
}
+message GetAllProfitAmountInput {
+ // The scheme id.
+ aelf.Hash scheme_id = 1;
+ // The token symbol.
+ string symbol = 2;
+ // The beneficiary's address.
+ aelf.Address beneficiary = 3;
+}
+
+message GetAllProfitAmountOutput{
+ int64 all_profit_amount = 1;
+ int64 one_time_claimable_profit_amount = 2;
+}
+
message ReceivedProfitsMap {
// The collection of profits received, token symbol -> amount.
map value = 1;
}
+message GetAllProfitsMapInput {
+ // The scheme id.
+ aelf.Hash scheme_id = 1;
+ // The address of beneficiary.
+ aelf.Address beneficiary = 2;
+}
+
+message GetAllProfitsMapOutput {
+ // The collection of all profits received, token symbol -> amount.
+ map all_profits_map = 1;
+ // The collection of claimable profits received, token symbol -> amount.
+ map one_time_claimable_profits_map = 2;
+}
+
message SchemeCreated {
option (aelf.is_event) = true;
// The virtual address of the created scheme.
diff --git a/protobuf/token_contract.proto b/protobuf/token_contract.proto
index d858bf5f1d..e1174b8b45 100644
--- a/protobuf/token_contract.proto
+++ b/protobuf/token_contract.proto
@@ -40,7 +40,10 @@ service TokenContract {
// enabling the Spender to call TransferFrom.
rpc Approve (ApproveInput) returns (google.protobuf.Empty) {
}
-
+
+ rpc BatchApprove (BatchApproveInput) returns (google.protobuf.Empty) {
+ }
+
// This is the reverse operation for Approve, it will decrease the allowance.
rpc UnApprove (UnApproveInput) returns (google.protobuf.Empty) {
}
@@ -354,6 +357,9 @@ message ApproveInput {
// The amount of token to approve.
int64 amount = 3;
}
+message BatchApproveInput {
+ repeated ApproveInput value = 1;
+}
message UnApproveInput {
// The address that allowance will be decreased.
diff --git a/protobuf/token_contract_impl.proto b/protobuf/token_contract_impl.proto
index 9a7779ec45..5885914e80 100644
--- a/protobuf/token_contract_impl.proto
+++ b/protobuf/token_contract_impl.proto
@@ -83,6 +83,11 @@ service TokenContractImpl {
rpc RemoveTransactionFeeFreeAllowancesConfig (RemoveTransactionFeeFreeAllowancesConfigInput) returns (google.protobuf.Empty) {
}
+ 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){
}
@@ -173,6 +178,10 @@ service TokenContractImpl {
rpc GetTokenIssuerAndOwnerModificationEnabled(google.protobuf.Empty) returns (google.protobuf.BoolValue) {
option (aelf.is_view) = true;
}
+
+ rpc GetMaxBatchApproveCount (google.protobuf.Empty) returns (google.protobuf.Int32Value) {
+
+ }
}
message AdvanceResourceTokenInput {
diff --git a/src/AElf.Kernel.FeeCalculation/Extensions/TransactionResultExtensions.cs b/src/AElf.Kernel.FeeCalculation/Extensions/TransactionResultExtensions.cs
index ff1233b211..138d7853f3 100644
--- a/src/AElf.Kernel.FeeCalculation/Extensions/TransactionResultExtensions.cs
+++ b/src/AElf.Kernel.FeeCalculation/Extensions/TransactionResultExtensions.cs
@@ -8,21 +8,30 @@ namespace AElf.Kernel.FeeCalculation.Extensions;
public static class TransactionResultExtensions
{
- public static Dictionary GetChargedTransactionFees(this TransactionResult transactionResult)
+ public static Dictionary> GetChargedTransactionFees(
+ this TransactionResult transactionResult)
{
return transactionResult.Logs
.Where(l => l.Name == nameof(TransactionFeeCharged))
- .Select(l => TransactionFeeCharged.Parser.ParseFrom(l.NonIndexed))
- .GroupBy(fee => fee.Symbol, fee => fee.Amount)
- .ToDictionary(g => g.Key, g => g.Sum());
+ .GroupBy(
+ log => TransactionFeeCharged.Parser.ParseFrom(log.Indexed[0]).ChargingAddress,
+ log => TransactionFeeCharged.Parser.ParseFrom(log.NonIndexed))
+ .ToDictionary(e => e.Key,
+ e => e
+ .GroupBy(fee => fee.Symbol, fee => fee.Amount)
+ .ToDictionary(g => g.Key, g => g.Sum()));
}
- public static Dictionary GetConsumedResourceTokens(this TransactionResult transactionResult)
+ public static Dictionary> GetConsumedResourceTokens(this TransactionResult transactionResult)
{
var relatedLogs = transactionResult.Logs.Where(l => l.Name == nameof(ResourceTokenCharged)).ToList();
- if (!relatedLogs.Any()) return new Dictionary();
+ if (!relatedLogs.Any()) return new Dictionary>();
return relatedLogs.Select(l => ResourceTokenCharged.Parser.ParseFrom(l.NonIndexed))
- .ToDictionary(e => e.Symbol, e => e.Amount);
+ .GroupBy(g => g.ContractAddress)
+ .ToDictionary(e => e.Key,
+ e => e
+ .GroupBy(fee => fee.Symbol, fee => fee.Amount)
+ .ToDictionary(g => g.Key, g => g.Sum()));
}
public static Dictionary GetOwningResourceTokens(this TransactionResult transactionResult)
diff --git a/src/AElf.WebApp.Application.Chain/Dto/CalculateTransactionFeeOutput.cs b/src/AElf.WebApp.Application.Chain/Dto/CalculateTransactionFeeOutput.cs
index bbba632175..1446177873 100644
--- a/src/AElf.WebApp.Application.Chain/Dto/CalculateTransactionFeeOutput.cs
+++ b/src/AElf.WebApp.Application.Chain/Dto/CalculateTransactionFeeOutput.cs
@@ -1,4 +1,6 @@
+using System;
using System.Collections.Generic;
+using AElf.Types;
namespace AElf.WebApp.Application.Chain.Dto;
@@ -6,7 +8,21 @@ public class CalculateTransactionFeeOutput
{
public bool Success { get; set; }
+ [Obsolete("This property is deprecated and will be removed in the next version. Use the TransactionFees instead.")]
public Dictionary TransactionFee { get; set; }
-
+
+ [Obsolete("This property is deprecated and will be removed in the next version. Use the ResourceFees instead.")]
public Dictionary ResourceFee { get; set; }
+
+ public FeeDto TransactionFees { get; set; }
+
+ public FeeDto ResourceFees { get; set; }
+
+ public string Error { get; set; }
+}
+
+public class FeeDto
+{
+ public string ChargingAddress { get; set; }
+ public Dictionary Fee { get; set; }
}
\ No newline at end of file
diff --git a/src/AElf.WebApp.Application.Chain/Services/TransactionAppService.cs b/src/AElf.WebApp.Application.Chain/Services/TransactionAppService.cs
index 2c6702ee8d..8d365d88d1 100644
--- a/src/AElf.WebApp.Application.Chain/Services/TransactionAppService.cs
+++ b/src/AElf.WebApp.Application.Chain/Services/TransactionAppService.cs
@@ -17,6 +17,7 @@
using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.EventBus.Local;
using Volo.Abp.ObjectMapping;
@@ -47,17 +48,21 @@ public class TransactionAppService : AElfAppService, ITransactionAppService
private readonly ITransactionReadOnlyExecutionService _transactionReadOnlyExecutionService;
private readonly ITransactionResultStatusCacheProvider _transactionResultStatusCacheProvider;
private readonly IPlainTransactionExecutingService _plainTransactionExecutingService;
+ private readonly WebAppOptions _webAppOptions;
+
public TransactionAppService(ITransactionReadOnlyExecutionService transactionReadOnlyExecutionService,
IBlockchainService blockchainService, IObjectMapper objectMapper,
ITransactionResultStatusCacheProvider transactionResultStatusCacheProvider,
- IPlainTransactionExecutingService plainTransactionExecutingService)
+ IPlainTransactionExecutingService plainTransactionExecutingService,
+ IOptionsMonitor webAppOptions)
{
_transactionReadOnlyExecutionService = transactionReadOnlyExecutionService;
_blockchainService = blockchainService;
_objectMapper = objectMapper;
_transactionResultStatusCacheProvider = transactionResultStatusCacheProvider;
_plainTransactionExecutingService = plainTransactionExecutingService;
+ _webAppOptions = webAppOptions.CurrentValue;
LocalEventBus = NullLocalEventBus.Instance;
Logger = NullLogger.Instance;
@@ -293,17 +298,39 @@ private async Task EstimateTransactionFee(Transac
executionReturnSets.FirstOrDefault()?.TransactionResult.GetChargedTransactionFees();
var resourceFees = executionReturnSets.FirstOrDefault()?.TransactionResult.GetConsumedResourceTokens();
result.Success = true;
- result.TransactionFee = transactionFees;
- result.ResourceFee = resourceFees;
+ result.TransactionFee = GetFeeValue(transactionFees);
+ result.ResourceFee = GetFeeValue(resourceFees);
+ result.TransactionFees = GetFee(transactionFees);
+ result.ResourceFees = GetFee(resourceFees);
}
else
{
result.Success = false;
+ result.Error = TransactionErrorResolver.TakeErrorMessage(
+ executionReturnSets.FirstOrDefault()?.TransactionResult.Error, _webAppOptions.IsDebugMode);
}
return result;
}
+ private Dictionary GetFeeValue(Dictionary> feeMap)
+ {
+ return feeMap?.SelectMany(pair => pair.Value)
+ .GroupBy(p => p.Key)
+ .ToDictionary(g => g.Key, g => g.Sum(pair => pair.Value));
+ }
+
+ private FeeDto GetFee(Dictionary> feeMap)
+ {
+ var fee = feeMap?.Select(f => new FeeDto
+ {
+ ChargingAddress = f.Key.ToBase58(),
+ Fee = f.Value
+ }).FirstOrDefault();
+
+ return fee;
+ }
+
private async Task PublishTransactionsAsync(string[] rawTransactions)
{
var txIds = new string[rawTransactions.Length];
diff --git a/test/AElf.Contracts.Election.Tests/Full/ReleaseProfitsFromTreasury.cs b/test/AElf.Contracts.Election.Tests/Full/ReleaseProfitsFromTreasury.cs
index cbe677415b..96657c3cd2 100644
--- a/test/AElf.Contracts.Election.Tests/Full/ReleaseProfitsFromTreasury.cs
+++ b/test/AElf.Contracts.Election.Tests/Full/ReleaseProfitsFromTreasury.cs
@@ -383,11 +383,11 @@ public async Task CheckTreasuryProfitsDistribution_Test()
})).Balance;
var profitTester = GetProfitContractTester(VoterKeyPairs[0]);
- var profitAmount = (await profitTester.GetProfitAmount.CallAsync(new GetProfitAmountInput
+ var profitAmount = (await profitTester.GetAllProfitAmount.CallAsync(new GetAllProfitAmountInput
{
SchemeId = ProfitItemsIds[ProfitType.CitizenWelfare],
Symbol = EconomicContractsTestConstants.NativeTokenSymbol
- })).Value;
+ })).OneTimeClaimableProfitAmount;
profitAmount.ShouldBeGreaterThan(0);
var profitResult = await profitTester.ClaimProfits.SendAsync(new ClaimProfitsInput
@@ -636,11 +636,11 @@ private async Task GetProfitAmount(ProfitType type)
break;
}
- return (await stub.GetProfitAmount.CallAsync(new GetProfitAmountInput
+ return (await stub.GetAllProfitAmount.CallAsync(new GetAllProfitAmountInput
{
SchemeId = ProfitItemsIds[type],
Symbol = EconomicContractsTestConstants.NativeTokenSymbol
- })).Value;
+ })).OneTimeClaimableProfitAmount;
}
private async Task GetReleasedAmount()
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/NftApplicationTests.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/NftApplicationTests.cs
index 9733a8952a..6187172a80 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/NftApplicationTests.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/NftApplicationTests.cs
@@ -15,6 +15,7 @@ public static class NftCollectionMetaFields
public static string BaseUriKey = "__nft_base_uri";
public static string NftType = "__nft_type";
public const string IsItemIdReuseKey = "__nft_is_item_id_reuse";
+ public const string NftCreateChainIdExternalInfoKey = "__nft_create_chain_id";
}
public static class NftInfoMetaFields
@@ -182,6 +183,47 @@ private async Task> CreateNftCollectionAndNft(bool reuseItemId = tr
return symbols;
}
+ private async Task CreateNftFailed()
+ {
+ var collectionInfo = new TokenInfo
+ {
+ Symbol = NftCollection1155Info.Symbol,
+ TokenName = NftCollection1155Info.TokenName,
+ TotalSupply = NftCollection1155Info.TotalSupply,
+ Decimals = NftCollection1155Info.Decimals,
+ Issuer = NftCollection1155Info.Issuer,
+ IssueChainId = NftCollection1155Info.IssueChainId,
+ ExternalInfo = new ExternalInfo()
+ {
+ Value =
+ {
+ {
+ NftCollectionMetaFields.NftCreateChainIdExternalInfoKey,
+ "1234"
+ }
+ }
+ },
+ Owner = NftCollection1155Info.Issuer
+ };
+ var createCollectionRes = await CreateNftCollectionAsync(collectionInfo);
+ createCollectionRes.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ var createNft2Res = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
+ {
+ Symbol = $"{collectionInfo.Symbol}{Nft1155Info.Symbol}",
+ TokenName = Nft1155Info.TokenName,
+ TotalSupply = Nft1155Info.TotalSupply,
+ Decimals = Nft1155Info.Decimals,
+ Issuer = Nft1155Info.Issuer,
+ IsBurnable = Nft1155Info.IsBurnable,
+ IssueChainId = Nft1155Info.IssueChainId,
+ ExternalInfo = Nft1155Info.ExternalInfo,
+ Owner = Nft1155Info.Issuer
+ });
+ createNft2Res.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ createNft2Res.TransactionResult.Error.Contains("NFT create ChainId must be collection's NFT create chainId")
+ .ShouldBeTrue();
+ }
+
private void AssertTokenEqual(TokenCreated log, TokenInfo input)
{
Assert.Equal(log.TokenName, input.TokenName);
@@ -202,6 +244,12 @@ public async Task MultiTokenContract_Create_1155Nft_Test()
await CreateNftCollectionAndNft();
}
+ [Fact(DisplayName = "[MultiToken_Nft] Create 1155 nfts failed.")]
+ public async Task MultiTokenContract_Create_1155Nft_failed_Test()
+ {
+ await CreateNftFailed();
+ }
+
[Fact(DisplayName = "[MultiToken_Nft] Create 721 nfts.")]
public async Task MultiTokenContract_Create_721Nft_Test()
{
@@ -212,22 +260,6 @@ public async Task MultiTokenContract_Create_721Nft_Test()
public async Task MultiTokenContract_Create_NFTCollection_Input_Check_Test()
{
var input = NftCollection721Info;
- // Decimals check
- {
- var result = await CreateMutiTokenWithExceptionAsync(TokenContractStub, new CreateInput
- {
- Symbol = $"{input.Symbol}0",
- TokenName = input.TokenName,
- TotalSupply = input.TotalSupply,
- Decimals = 8,
- Issuer = input.Issuer,
- IssueChainId = input.IssueChainId,
- ExternalInfo = input.ExternalInfo,
- Owner = input.Owner
- });
- result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
- result.TransactionResult.Error.ShouldContain("NFT's decimals must be 0");
- }
// Symbol check
{
var seedInput = BuildSeedCreateInput( new CreateInput
@@ -287,21 +319,6 @@ public async Task MultiTokenContract_Create_NFT_Input_Check_Test()
await CreateNftCollectionAsync(NftCollection721Info);
var input = Nft721Info;
- // Decimals check
- {
- var result = await CreateMutiTokenWithExceptionAsync(TokenContractStub, new CreateInput
- {
- Symbol = "GHJ-0",
- TokenName = input.TokenName,
- TotalSupply = input.TotalSupply,
- Decimals = 8,
- Issuer = input.Issuer,
- IssueChainId = input.IssueChainId,
- ExternalInfo = input.ExternalInfo
- });
- result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
- result.TransactionResult.Error.ShouldContain("NFT's decimals must be 0");
- }
// Symbol check
{
var result = await CreateSeedNftWithExceptionAsync(TokenContractStub, new CreateInput
@@ -376,7 +393,7 @@ public async Task MultiTokenContract_Create_NFT_Input_Check_Test()
Owner = input.Owner
});
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
- result.TransactionResult.Error.ShouldContain("NFT create ChainId must be collection's issue chainId");
+ result.TransactionResult.Error.ShouldContain("NFT issue ChainId must be collection's issue chainId");
}
}
diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs
index dba96e1023..49642bae3a 100644
--- a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs
+++ b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs
@@ -171,6 +171,145 @@ public async Task MultiTokenContract_Approve_ContractAddress_Test()
basicAllowanceOutput.Allowance.ShouldBe(2000L);
}
+ [Fact(DisplayName = "[MultiToken] BatchApprove token to Contract")]
+ public async Task MultiTokenContract_BatchApprove_ContractAddress_Test()
+ {
+ await CreateTokenAndIssue();
+ var approveBasisResult = (await TokenContractStub.BatchApprove.SendAsync(new BatchApproveInput
+ {
+ Value =
+ {
+ new ApproveInput
+ {
+ Symbol = SymbolForTest,
+ Amount = 2000L,
+ Spender = BasicFunctionContractAddress
+ },
+ new ApproveInput
+ {
+ Symbol = SymbolForTest,
+ Amount = 1000L,
+ Spender = OtherBasicFunctionContractAddress
+ },
+ new ApproveInput
+ {
+ Symbol = SymbolForTest,
+ Amount = 5000L,
+ Spender = TreasuryContractAddress
+ }
+ }
+ })).TransactionResult;
+ approveBasisResult.Status.ShouldBe(TransactionResultStatus.Mined);
+
+ var basicAllowanceOutput = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput
+ {
+ Owner = DefaultAddress,
+ Spender = BasicFunctionContractAddress,
+ Symbol = SymbolForTest
+ });
+ basicAllowanceOutput.Allowance.ShouldBe(2000L);
+ var otherBasicAllowanceOutput = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput
+ {
+ Owner = DefaultAddress,
+ Spender = OtherBasicFunctionContractAddress,
+ Symbol = SymbolForTest
+ });
+ otherBasicAllowanceOutput.Allowance.ShouldBe(1000L);
+ var treasuryAllowanceOutput = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput
+ {
+ Owner = DefaultAddress,
+ Spender = TreasuryContractAddress,
+ Symbol = SymbolForTest
+ });
+ treasuryAllowanceOutput.Allowance.ShouldBe(5000L);
+
+ approveBasisResult = (await TokenContractStub.BatchApprove.SendAsync(new BatchApproveInput
+ {
+ Value =
+ {
+ new ApproveInput
+ {
+ Symbol = SymbolForTest,
+ Amount = 1000L,
+ Spender = BasicFunctionContractAddress
+ },
+ new ApproveInput
+ {
+ Symbol = SymbolForTest,
+ Amount = 3000L,
+ Spender = BasicFunctionContractAddress
+ },
+ new ApproveInput
+ {
+ Symbol = SymbolForTest,
+ Amount = 3000L,
+ Spender = TreasuryContractAddress
+ }
+ }
+ })).TransactionResult;
+ approveBasisResult.Status.ShouldBe(TransactionResultStatus.Mined);
+ basicAllowanceOutput = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput
+ {
+ Owner = DefaultAddress,
+ Spender = BasicFunctionContractAddress,
+ Symbol = SymbolForTest
+ });
+ basicAllowanceOutput.Allowance.ShouldBe(3000L);
+
+ treasuryAllowanceOutput = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput
+ {
+ Owner = DefaultAddress,
+ Spender = TreasuryContractAddress,
+ Symbol = SymbolForTest
+ });
+ treasuryAllowanceOutput.Allowance.ShouldBe(3000L);
+ }
+
+ [Fact]
+ public async Task MultiTokenContract_SetMaximumBatchApproveCount_Test()
+ {
+ var result = await TokenContractStub.SetMaxBatchApproveCount.SendWithExceptionAsync(new Int32Value
+ {
+ Value = 1
+ });
+ result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ result.TransactionResult.Error.ShouldContain("Unauthorized behavior");
+ var maximumBatchApproveCountOutput = await TokenContractStub.GetMaxBatchApproveCount.CallAsync(new Empty());
+ maximumBatchApproveCountOutput.Value.ShouldBe(100);
+ var defaultParliament = await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ var proposalId = await CreateProposalAsync(TokenContractAddress,
+ defaultParliament, nameof(TokenContractStub.SetMaxBatchApproveCount),
+ new Int32Value
+ {
+ Value = 1
+ });
+ await ApproveWithMinersAsync(proposalId);
+ await ParliamentContractStub.Release.SendAsync(proposalId);
+ maximumBatchApproveCountOutput = await TokenContractStub.GetMaxBatchApproveCount.CallAsync(new Empty());
+ maximumBatchApproveCountOutput.Value.ShouldBe(1);
+ await CreateTokenAndIssue();
+ var approveBasisResult = (await TokenContractStub.BatchApprove.SendWithExceptionAsync(new BatchApproveInput
+ {
+ Value =
+ {
+ new ApproveInput
+ {
+ Symbol = SymbolForTest,
+ Amount = 2000L,
+ Spender = BasicFunctionContractAddress
+ },
+ new ApproveInput
+ {
+ Symbol = SymbolForTest,
+ Amount = 1000L,
+ Spender = OtherBasicFunctionContractAddress
+ }
+ }
+ })).TransactionResult;
+ approveBasisResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ approveBasisResult.Error.ShouldContain("Exceeds the max batch approve count");
+ }
+
[Fact(DisplayName = "[MultiToken] Approve token out of owner's balance")]
public async Task MultiTokenContract_Approve_OutOfAmount_Test()
{
@@ -999,16 +1138,21 @@ public async Task Side_Chain_Creat_Token_Test()
});
await ApproveWithMinersAsync(proposalId);
await ParliamentContractStub.Release.SendAsync(proposalId);
- var createTokenRet = await TokenContractStub.Create.SendWithExceptionAsync(new CreateInput
- {
- Symbol = "ALI",
- TokenName = "Ali",
- Decimals = 4,
- TotalSupply = 100_000,
- Issuer = DefaultAddress,
- Owner = DefaultAddress
- });
- createTokenRet.TransactionResult.Error.ShouldContain(
+
+ proposalId = await CreateProposalAsync(TokenContractAddress,
+ defaultParliament, nameof(TokenContractStub.Create),
+ new CreateInput
+ {
+ Symbol = "ALI",
+ TokenName = "Ali",
+ Decimals = 4,
+ TotalSupply = 100_000,
+ Issuer = DefaultAddress,
+ Owner = DefaultAddress
+ });
+ await ApproveWithMinersAsync(proposalId);
+ var createTokenRe = await ParliamentContractStub.Release.SendWithExceptionAsync(proposalId);
+ createTokenRe.TransactionResult.Error.ShouldContain(
"Failed to create token if side chain creator already set.");
}
diff --git a/test/AElf.Contracts.Profit.Tests/ProfitContractTestConstants.cs b/test/AElf.Contracts.Profit.Tests/ProfitContractTestConstants.cs
index d4f937117a..bda82297c0 100644
--- a/test/AElf.Contracts.Profit.Tests/ProfitContractTestConstants.cs
+++ b/test/AElf.Contracts.Profit.Tests/ProfitContractTestConstants.cs
@@ -5,4 +5,5 @@ public class ProfitContractTestConstants
public const string NativeTokenSymbol = "ELF";
public const long NativeTokenTotalSupply = 1_000_000_000_00000000;
public const int MaximumProfitReceivingDuePeriodCount = 1024;
+ public const int DefaultMaximumProfitReceivingPeriodCountOfOneTime = 100;
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.Profit.Tests/ProfitTests.cs b/test/AElf.Contracts.Profit.Tests/ProfitTests.cs
index 34979069da..601fd7ccf6 100644
--- a/test/AElf.Contracts.Profit.Tests/ProfitTests.cs
+++ b/test/AElf.Contracts.Profit.Tests/ProfitTests.cs
@@ -3,6 +3,7 @@
using AElf.Contracts.MultiToken;
using AElf.CSharp.Core;
using AElf.Types;
+using Google.Protobuf.WellKnownTypes;
using Shouldly;
using Xunit;
@@ -1604,13 +1605,32 @@ await creator.DistributeProfits.SendAsync(new DistributeProfitsInput
Symbol = tokenSymbol,
SchemeId = schemeId
});
+
profitAmount.Value.ShouldBe(amount);
+
+ var allProfitAmount = await ProfitContractStub.GetAllProfitAmount.CallAsync(new GetAllProfitAmountInput
+ {
+ Beneficiary = receiver,
+ Symbol = tokenSymbol,
+ SchemeId = schemeId
+ });
+ allProfitAmount.AllProfitAmount.ShouldBe(amount);
+ allProfitAmount.OneTimeClaimableProfitAmount.ShouldBe(amount);
var profitMap = await ProfitContractStub.GetProfitsMap.CallAsync(new ClaimProfitsInput
{
SchemeId = schemeId,
Beneficiary = receiver
});
+
profitMap.Value[tokenSymbol].ShouldBe(amount);
+
+ var allProfitMap = await ProfitContractStub.GetAllProfitsMap.CallAsync(new GetAllProfitsMapInput
+ {
+ SchemeId = schemeId,
+ Beneficiary = receiver
+ });
+ allProfitMap.AllProfitsMap[tokenSymbol].ShouldBe(amount);
+ allProfitMap.OneTimeClaimableProfitsMap[tokenSymbol].ShouldBe(amount);
}
// after claim
@@ -1633,12 +1653,30 @@ await ProfitContractStub.ClaimProfits.SendAsync(new ClaimProfitsInput
SchemeId = schemeId
});
profitAmount.Value.ShouldBe(0);
+
+ var allProfitAmount = await ProfitContractStub.GetAllProfitAmount.CallAsync(new GetAllProfitAmountInput
+ {
+ Beneficiary = receiver,
+ Symbol = tokenSymbol,
+ SchemeId = schemeId
+ });
+ allProfitAmount.AllProfitAmount.ShouldBe(0);
+ allProfitAmount.OneTimeClaimableProfitAmount.ShouldBe(0);
+
var profitMap = await ProfitContractStub.GetProfitsMap.CallAsync(new ClaimProfitsInput
{
SchemeId = schemeId,
Beneficiary = receiver
});
profitMap.Value.ShouldNotContainKey(tokenSymbol);
+
+ var allProfitMap = await ProfitContractStub.GetAllProfitsMap.CallAsync(new GetAllProfitsMapInput
+ {
+ SchemeId = schemeId,
+ Beneficiary = receiver
+ });
+ allProfitMap.AllProfitsMap.ShouldNotContainKey(tokenSymbol);
+ allProfitMap.OneTimeClaimableProfitsMap.ShouldNotContainKey(tokenSymbol);
}
//second time
@@ -1659,12 +1697,28 @@ await creator.DistributeProfits.SendAsync(new DistributeProfitsInput
SchemeId = schemeId
});
profitAmount.Value.ShouldBe(amount);
+ var allProfitAmount = await ProfitContractStub.GetAllProfitAmount.CallAsync(new GetAllProfitAmountInput
+ {
+ Beneficiary = receiver,
+ Symbol = tokenSymbol,
+ SchemeId = schemeId
+ });
+ allProfitAmount.AllProfitAmount.ShouldBe(amount);
+ allProfitAmount.OneTimeClaimableProfitAmount.ShouldBe(amount);
var profitMap = await ProfitContractStub.GetProfitsMap.CallAsync(new ClaimProfitsInput
{
SchemeId = schemeId,
Beneficiary = receiver
});
profitMap.Value[tokenSymbol].ShouldBe(amount);
+
+ var allProfitMap = await ProfitContractStub.GetAllProfitsMap.CallAsync(new GetAllProfitsMapInput
+ {
+ SchemeId = schemeId,
+ Beneficiary = receiver
+ });
+ allProfitMap.AllProfitsMap[tokenSymbol].ShouldBe(amount);
+ allProfitMap.OneTimeClaimableProfitsMap[tokenSymbol].ShouldBe(amount);
await ProfitContractStub.ClaimProfits.SendAsync(new ClaimProfitsInput
{
@@ -1680,6 +1734,47 @@ await ProfitContractStub.ClaimProfits.SendAsync(new ClaimProfitsInput
}
}
+
+ [Fact]
+ public async Task MaximumProfitReceivingPeriodCount_Test()
+ {
+ var maximumProfitReceivingPeriodCount =
+ await ProfitContractStub.GetMaximumProfitReceivingPeriodCount.CallAsync(new Empty());
+ maximumProfitReceivingPeriodCount.Value.ShouldBe(ProfitContractTestConstants
+ .DefaultMaximumProfitReceivingPeriodCountOfOneTime);
+ var maxPeriodCount = 10;
+ var result = await ProfitContractStub.SetMaximumProfitReceivingPeriodCount.SendWithExceptionAsync(new Int32Value
+ {
+ Value = maxPeriodCount
+ });
+ result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ result.TransactionResult.Error.ShouldContain("No permission");
+
+ var defaultOrganizationAddress =
+ await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
+ var proposalId = await CreateProposalAsync(ProfitContractAddress,
+ defaultOrganizationAddress, nameof(ProfitContractStub.SetMaximumProfitReceivingPeriodCount), new Int32Value
+ {
+ Value = 0
+ });
+ await ApproveWithMinersAsync(proposalId);
+ result = await ParliamentContractStub.Release.SendWithExceptionAsync(proposalId);
+ result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ result.TransactionResult.Error.ShouldContain("Invalid maximum profit receiving period count");
+
+ proposalId = await CreateProposalAsync(ProfitContractAddress,
+ defaultOrganizationAddress, nameof(ProfitContractStub.SetMaximumProfitReceivingPeriodCount), new Int32Value
+ {
+ Value = maxPeriodCount
+ });
+ await ApproveWithMinersAsync(proposalId);
+ await ParliamentContractStub.Release.SendAsync(proposalId);
+
+ maximumProfitReceivingPeriodCount =
+ await ProfitContractStub.GetMaximumProfitReceivingPeriodCount.CallAsync(new Empty());
+ maximumProfitReceivingPeriodCount.Value.ShouldBe(maxPeriodCount);
+ }
+
private async Task ContributeProfits(Hash schemeId, long amount = 100)
{
await ProfitContractStub.ContributeProfits.SendAsync(new ContributeProfitsInput
diff --git a/test/AElf.Kernel.FeeCalculation.Tests/Infrastructure/CalculateFunctionTest.cs b/test/AElf.Kernel.FeeCalculation.Tests/Infrastructure/CalculateFunctionTest.cs
index 2e8484cd82..211d309fb0 100644
--- a/test/AElf.Kernel.FeeCalculation.Tests/Infrastructure/CalculateFunctionTest.cs
+++ b/test/AElf.Kernel.FeeCalculation.Tests/Infrastructure/CalculateFunctionTest.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using AElf.Contracts.MultiToken;
using AElf.CSharp.Core.Extension;
@@ -65,30 +66,47 @@ public void GetChargedTransactionFees_Test()
var transactionResult = new TransactionResult();
transactionResult.Logs.Add(new TransactionFeeCharged
{
+ ChargingAddress = SampleAddress.AddressList[0],
Amount = 1,
Symbol = "ELF"
}.ToLogEvent());
transactionResult.Logs.Add(new TransactionFeeCharged
{
+ ChargingAddress = SampleAddress.AddressList[0],
Amount = 2,
Symbol = "ELF"
}.ToLogEvent());
transactionResult.Logs.Add(new TransactionFeeCharged
{
+ ChargingAddress = SampleAddress.AddressList[0],
+ Amount = 3,
+ Symbol = "USDT"
+ }.ToLogEvent());
+ transactionResult.Logs.Add(new TransactionFeeCharged
+ {
+ ChargingAddress = SampleAddress.AddressList[0],
+ Amount = 4,
+ Symbol = "USDT"
+ }.ToLogEvent());
+ transactionResult.Logs.Add(new TransactionFeeCharged
+ {
+ ChargingAddress = SampleAddress.AddressList[1],
Amount = 3,
Symbol = "TEST"
}.ToLogEvent());
transactionResult.Logs.Add(new TransactionFeeCharged
{
+ ChargingAddress = SampleAddress.AddressList[1],
Amount = 4,
Symbol = "TEST"
}.ToLogEvent());
var feeDic = transactionResult.GetChargedTransactionFees();
feeDic.Count.ShouldBe(2);
- feeDic.Keys.First().ShouldBe("ELF");
- feeDic.Values.First().ShouldBe(3);
- feeDic.Keys.Last().ShouldBe("TEST");
- feeDic.Values.Last().ShouldBe(7);
+ feeDic.Keys.First().ShouldBe(SampleAddress.AddressList[0]);
+ feeDic.Values.First()["ELF"].ShouldBe(3);
+ feeDic.Values.First()["USDT"].ShouldBe(7);
+ feeDic.Keys.Last().ShouldBe(SampleAddress.AddressList[1]);
+ feeDic.Values.Last()["TEST"].ShouldBe(7);
}
[Fact]
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTest.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTest.cs
index b265f1cca9..1264e6fb14 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTest.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeTest.cs
@@ -268,14 +268,14 @@ public async Task ChargeFee_SuccessfulTest()
chargingAddress.ShouldContain(dummy.Transaction.From);
var transactionFeeDic = dummy.TransactionResult.GetChargedTransactionFees();
- await CheckTransactionFeesMapAsync(transactionFeeDic);
+ await CheckTransactionFeesMapAsync(DefaultSender,transactionFeeDic);
var after = await tokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
Owner = DefaultSender,
Symbol = "ELF"
});
- after.Balance.ShouldBe(before.Balance - transactionFeeDic[before.Symbol]);
+ after.Balance.ShouldBe(before.Balance - transactionFeeDic[DefaultAddress][before.Symbol]);
}
private static List GetChargingAddress(TransactionResult transactionResult)
@@ -284,7 +284,7 @@ private static List GetChargingAddress(TransactionResult transactionRes
return relatedLogs.Select(l => TransactionFeeCharged.Parser.ParseFrom(l.Indexed[0]).ChargingAddress).ToList();
}
- private async Task CheckTransactionFeesMapAsync(Dictionary transactionFeeDic)
+ private async Task CheckTransactionFeesMapAsync(Address chargingAddress, Dictionary> transactionFeeDic)
{
var chain = await _blockchainService.GetChainAsync();
var transactionFeesMap = await _totalTransactionFeesMapProvider.GetTotalTransactionFeesMapAsync(new ChainContext
@@ -293,7 +293,13 @@ private async Task CheckTransactionFeesMapAsync(Dictionary transac
BlockHeight = chain.BestChainHeight
});
foreach (var transactionFee in transactionFeeDic)
- transactionFeesMap.Value[transactionFee.Key].ShouldBe(transactionFee.Value);
+ {
+ transactionFee.Key.ShouldBe(chargingAddress);
+ foreach (var value in transactionFee.Value)
+ {
+ transactionFeesMap.Value[value.Key].ShouldBe(value.Value);
+ }
+ }
}
[Fact]
@@ -324,7 +330,7 @@ await tokenContractStub.Transfer.SendAsync(new TransferInput
dummy.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
dummy.TransactionResult.Error.ShouldBe("Pre-Error: Transaction fee not enough.");
var transactionFeeDic = dummy.TransactionResult.GetChargedTransactionFees();
- await CheckTransactionFeesMapAsync(transactionFeeDic);
+ await CheckTransactionFeesMapAsync(Accounts[1].Address,transactionFeeDic);
var afterFee = (await tokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
@@ -332,7 +338,7 @@ await tokenContractStub.Transfer.SendAsync(new TransferInput
Symbol = "ELF"
})).Balance;
afterFee.ShouldBe(0);
- transactionFeeDic["ELF"].ShouldBe(issueAmount);
+ transactionFeeDic[Accounts[1].Address]["ELF"].ShouldBe(issueAmount);
}
[Theory]
@@ -378,7 +384,7 @@ await tokenContractStub.Transfer.SendAsync(new TransferInput
Symbol = chargedSymbol ?? "ELF"
})).Balance;
- Dictionary transactionFeeDic;
+ Dictionary> transactionFeeDic;
var userTestContractStub =
GetTester(_testContractAddress, Accounts[1].KeyPair);
if (isChargingSuccessful)
@@ -387,8 +393,9 @@ await tokenContractStub.Transfer.SendAsync(new TransferInput
dummyResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
if (chargedSymbol != null)
{
- dummyResult.TransactionResult.GetChargedTransactionFees().Keys.ShouldContain(chargedSymbol);
- dummyResult.TransactionResult.GetChargedTransactionFees().Values.ShouldContain(chargedAmount);
+ dummyResult.TransactionResult.GetChargedTransactionFees().Keys.ShouldContain(Accounts[1].Address);
+ dummyResult.TransactionResult.GetChargedTransactionFees()[Accounts[1].Address].Keys.ShouldContain(chargedSymbol);
+ dummyResult.TransactionResult.GetChargedTransactionFees()[Accounts[1].Address].Values.ShouldContain(chargedAmount);
}
transactionFeeDic = dummyResult.TransactionResult.GetChargedTransactionFees();
@@ -399,13 +406,13 @@ await tokenContractStub.Transfer.SendAsync(new TransferInput
dummyResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
dummyResult.TransactionResult.Error.ShouldBe("Pre-Error: Transaction fee not enough.");
if (chargedSymbol != null)
- dummyResult.TransactionResult.GetChargedTransactionFees().Keys.ShouldContain(chargedSymbol);
+ dummyResult.TransactionResult.GetChargedTransactionFees()[Accounts[1].Address].Keys.ShouldContain(chargedSymbol);
transactionFeeDic = dummyResult.TransactionResult.GetChargedTransactionFees();
}
- await CheckTransactionFeesMapAsync(transactionFeeDic);
+ await CheckTransactionFeesMapAsync(Accounts[1].Address,transactionFeeDic);
if (chargedSymbol != null)
- transactionFeeDic[chargedSymbol].ShouldBe(chargedAmount);
+ transactionFeeDic[Accounts[1].Address][chargedSymbol].ShouldBe(chargedAmount);
var finalBalance = (await tokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeWithForkTest.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeWithForkTest.cs
index 6a6ffe5a73..02aebc36aa 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeWithForkTest.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForMethodFeeWithForkTest.cs
@@ -55,8 +55,9 @@ await SetMethodFeeWithProposalAsync(new MethodFees
Memo = Guid.NewGuid().ToString(),
To = SampleAddress.AddressList[0]
});
+ var fromAddress = Address.FromPublicKey(Tester.KeyPair.PublicKey);
var transactionResult = await Tester.GetTransactionResultAsync(result.Item2.GetHash());
- var targetFee = transactionResult.GetChargedTransactionFees().First().Value;
+ var targetFee = transactionResult.GetChargedTransactionFees()[fromAddress].First().Value;
var transactionFeesMap = await GetTransactionFeesMapAsync(new ChainContext
{
@@ -97,7 +98,7 @@ await SetMethodFeeWithProposalAsync(new MethodFees
To = SampleAddress.AddressList[0]
});
transactionResult = await Tester.GetTransactionResultAsync(result.Item2.GetHash());
- var fee = transactionResult.GetChargedTransactionFees().First().Value;
+ var fee = transactionResult.GetChargedTransactionFees()[fromAddress].First().Value;
transactionFeesMap = await GetTransactionFeesMapAsync(new ChainContext
{
BlockHash = result.Item1.GetHash(), BlockHeight = result.Item1.Height
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForUserContractMethodFeeTest.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForUserContractMethodFeeTest.cs
index 25e8daa5f4..688abbd017 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForUserContractMethodFeeTest.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForMethodFee.Tests/ExecutionPluginForUserContractMethodFeeTest.cs
@@ -75,14 +75,14 @@ public async Task ChargeUserContractFeeTest_Success()
var result = await _testContractStub.TestMethod.SendAsync(new Empty());
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
var transactionFeeDic = result.TransactionResult.GetChargedTransactionFees();
- await CheckTransactionFeesMapAsync(transactionFeeDic);
+ await CheckTransactionFeesMapAsync(DefaultAddress,transactionFeeDic);
var after = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
Owner = DefaultAddress,
Symbol = "ELF"
});
- after.Balance.ShouldBe(beforeBalance.Balance - transactionFeeDic[beforeBalance.Symbol]);
+ after.Balance.ShouldBe(beforeBalance.Balance - transactionFeeDic[DefaultAddress][beforeBalance.Symbol]);
}
[Fact]
@@ -97,7 +97,7 @@ public async Task ChargeUserContractFeeTest_Success_BaseFeeIsFree()
var result = await _testContractStub.TestMethod.SendAsync(new Empty());
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
var transactionFeeDic = result.TransactionResult.GetChargedTransactionFees();
- await CheckTransactionFeesMapAsync(transactionFeeDic);
+ await CheckTransactionFeesMapAsync(DefaultAddress,transactionFeeDic);
var after = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
@@ -193,7 +193,7 @@ await TokenContractStub.Transfer.SendAsync(new TransferInput
Symbol = chargedSymbol ?? "ELF"
})).Balance;
- Dictionary transactionFeeDic;
+ Dictionary> transactionFeeDic;
var userTestContractStub =
GetTester(_testContractAddress, Accounts[1].KeyPair);
if (isChargingSuccessful)
@@ -202,8 +202,13 @@ await TokenContractStub.Transfer.SendAsync(new TransferInput
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
if (chargedSymbol != null)
{
- result.TransactionResult.GetChargedTransactionFees().Keys.ShouldContain(chargedSymbol);
- result.TransactionResult.GetChargedTransactionFees().Values.ShouldContain(chargedAmount);
+ var token = new Dictionary
+ {
+ [chargedSymbol] = chargedAmount
+ };
+ result.TransactionResult.GetChargedTransactionFees().Keys.ShouldContain(Accounts[1].Address);
+ var fee = result.TransactionResult.GetChargedTransactionFees()[Accounts[1].Address];
+ fee.ShouldContainKeyAndValue(chargedSymbol,chargedAmount);
}
transactionFeeDic = result.TransactionResult.GetChargedTransactionFees();
@@ -214,13 +219,21 @@ await TokenContractStub.Transfer.SendAsync(new TransferInput
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
result.TransactionResult.Error.ShouldBe("Pre-Error: Transaction fee not enough.");
if (chargedSymbol != null)
- result.TransactionResult.GetChargedTransactionFees().Keys.ShouldContain(chargedSymbol);
+ {
+ var token = new Dictionary
+ {
+ [chargedSymbol] = chargedAmount
+ };
+ result.TransactionResult.GetChargedTransactionFees().Keys.ShouldContain(Accounts[1].Address);
+ var fee = result.TransactionResult.GetChargedTransactionFees()[Accounts[1].Address];
+ fee.ShouldContainKeyAndValue(chargedSymbol,chargedAmount);
+ }
transactionFeeDic = result.TransactionResult.GetChargedTransactionFees();
}
- await CheckTransactionFeesMapAsync(transactionFeeDic);
+ await CheckTransactionFeesMapAsync(Accounts[1].Address,transactionFeeDic);
if (chargedSymbol != null)
- transactionFeeDic[chargedSymbol].ShouldBe(chargedAmount);
+ transactionFeeDic[Accounts[1].Address][chargedSymbol].ShouldBe(chargedAmount);
var finalBalance = (await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
@@ -253,7 +266,7 @@ public async Task ChargeFee_SizeFeeIsFree()
var result = await _testContractStub.TestMethod.SendAsync(new Empty());
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
var transactionFeeDic = result.TransactionResult.GetChargedTransactionFees();
- await CheckTransactionFeesMapAsync(transactionFeeDic);
+ await CheckTransactionFeesMapAsync(DefaultAddress, transactionFeeDic);
var after = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
@@ -294,7 +307,7 @@ public async Task ChargeFee_SpecConfigurationFee()
var result = await _testContractStub.TestMethod.SendAsync(new Empty());
result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
var transactionFeeDic = result.TransactionResult.GetChargedTransactionFees();
- await CheckTransactionFeesMapAsync(transactionFeeDic);
+ await CheckTransactionFeesMapAsync(DefaultAddress, transactionFeeDic);
var after = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
{
@@ -356,7 +369,7 @@ private async Task Initialize()
}
}
- private async Task CheckTransactionFeesMapAsync(Dictionary transactionFeeDic)
+ private async Task CheckTransactionFeesMapAsync(Address chargingAddress, Dictionary> transactionFeeDic)
{
var chain = await _blockchainService.GetChainAsync();
var transactionFeesMap = await _totalTransactionFeesMapProvider.GetTotalTransactionFeesMapAsync(new ChainContext
@@ -365,7 +378,14 @@ private async Task CheckTransactionFeesMapAsync(Dictionary transac
BlockHeight = chain.BestChainHeight
});
foreach (var transactionFee in transactionFeeDic)
- transactionFeesMap.Value[transactionFee.Key].ShouldBe(transactionFee.Value);
+ {
+ transactionFee.Key.ShouldBe(chargingAddress);
+ foreach (var value in transactionFee.Value)
+ {
+ transactionFeesMap.Value[value.Key].ShouldBe(value.Value);
+ }
+ }
+
}
private async Task SetUserContractFeeAsync(int amount)
diff --git a/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTest.cs b/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTest.cs
index 6a47875b59..08d30b7593 100644
--- a/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTest.cs
+++ b/test/AElf.Kernel.SmartContract.ExecutionPluginForResourceFee.Tests/ExecutionPluginForResourceFeeTest.cs
@@ -258,8 +258,8 @@ public async Task CompareConsumptions()
write.ShouldBeGreaterThan(write1);
traffic.ShouldBe(traffic1);
- var consumedTokens1 = txResult1.GetConsumedResourceTokens();
- var consumedTokens2 = txResult2.GetConsumedResourceTokens();
+ var consumedTokens1 = txResult1.GetConsumedResourceTokens()[DefaultSender];
+ var consumedTokens2 = txResult2.GetConsumedResourceTokens()[DefaultSender];
consumedTokens1["READ"].ShouldBeGreaterThan(consumedTokens2["READ"]);
consumedTokens1["WRITE"].ShouldBeGreaterThan(consumedTokens2["WRITE"]);
consumedTokens1["TRAFFIC"].ShouldBe(consumedTokens2["TRAFFIC"]);
diff --git a/test/AElf.WebApp.Application.Chain.Tests/BlockChainAppServiceTest.cs b/test/AElf.WebApp.Application.Chain.Tests/BlockChainAppServiceTest.cs
index 7aec5b5cfd..67e9db0b83 100644
--- a/test/AElf.WebApp.Application.Chain.Tests/BlockChainAppServiceTest.cs
+++ b/test/AElf.WebApp.Application.Chain.Tests/BlockChainAppServiceTest.cs
@@ -1688,6 +1688,12 @@ public async Task CalculateTransactionFee_Success_Test()
};
var response = await PostResponseAsObjectAsync("/api/blockChain/CalculateTransactionFee", parameters);
response.Success.ShouldBe(true);
+ response.TransactionFees.ChargingAddress.ShouldBe(transaction.From.ToBase58());
+ response.TransactionFees.Fee.First().Key.ShouldBe("ELF");
+ response.TransactionFees.Fee.First().Value.ShouldBeGreaterThan(10000000L);
+ response.TransactionFee.First().Key.ShouldBe("ELF");
+ response.TransactionFee.First().Value.ShouldBeGreaterThan(10000000L);
+
}
[Fact]