diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_Helper.cs b/contract/AElf.Contracts.MultiToken/TokenContract_Helper.cs index 3a78c60cbe..47c199c30a 100644 --- a/contract/AElf.Contracts.MultiToken/TokenContract_Helper.cs +++ b/contract/AElf.Contracts.MultiToken/TokenContract_Helper.cs @@ -55,24 +55,28 @@ private void AssertApproveToken(string symbol) { Assert(!string.IsNullOrEmpty(symbol), "Symbol can not be null."); var words = symbol.Split(TokenContractConstants.NFTSymbolSeparator); - var symbolPrefix = words[0]; - var allSymbolIdentifier = GetAllSymbolIdentifier(); - Assert(symbolPrefix.Length > 0 && (IsValidCreateSymbol(symbolPrefix) || symbolPrefix.Equals(allSymbolIdentifier)), "Invalid symbol."); + if (words.Length == 1) { - if (!symbolPrefix.Equals(allSymbolIdentifier)) - { - ValidTokenExists(symbolPrefix); - } + ValidTokenExists(words[0]); return; } + + // The length of words should be either 1 or 2. Assert(words.Length == 2, "Invalid symbol length."); + + var symbolPrefix = words[0]; var itemId = words[1]; + + var allSymbolIdentifier = GetAllSymbolIdentifier(); + Assert(symbolPrefix.Length > 0 && IsValidCreateSymbol(symbolPrefix), "Invalid symbol."); + + // Symbol's format can either be ABC-123 or ABC-*. Assert(itemId.Length > 0 && (IsValidItemId(itemId) || itemId.Equals(allSymbolIdentifier)), "Invalid NFT Symbol."); var nftSymbol = itemId.Equals(allSymbolIdentifier) ? GetCollectionSymbol(symbolPrefix) : symbol; ValidTokenExists(nftSymbol); } - + private string GetCollectionSymbol(string symbolPrefix) { return $"{symbolPrefix}-{TokenContractConstants.CollectionSymbolSuffix}"; diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs b/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs index 93d54ec7b3..21f18cdbe3 100644 --- a/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs +++ b/contract/AElf.Contracts.MultiToken/TokenContract_NFT_Actions.cs @@ -101,26 +101,10 @@ private long GetAllowance(Address from, Address spender, string sourceSymbol, lo var allowance = State.Allowances[from][spender][sourceSymbol]; if (allowance >= amount) return allowance; var tokenType = GetSymbolType(sourceSymbol); - if (tokenType == SymbolType.Token) - { - allowance = GetAllSymbolAllowance(from, spender, out allowanceSymbol); - } - else - { - allowance = GetNftCollectionAllSymbolAllowance(from, spender, sourceSymbol, out allowanceSymbol); - if (allowance >= amount) return allowance; - allowance = GetAllSymbolAllowance(from, spender, out allowanceSymbol); - } - + if (tokenType == SymbolType.Token) return allowance; + allowance = GetNftCollectionAllSymbolAllowance(from, spender, sourceSymbol, out allowanceSymbol); return allowance; } - - - private long GetAllSymbolAllowance(Address from, Address spender, out string allowanceSymbol) - { - allowanceSymbol = GetAllSymbolIdentifier(); - return State.Allowances[from][spender][allowanceSymbol]; - } private long GetNftCollectionAllSymbolAllowance(Address from, Address spender, string sourceSymbol, out string allowanceSymbol) diff --git a/contract/AElf.Contracts.MultiToken/TokenContract_Views.cs b/contract/AElf.Contracts.MultiToken/TokenContract_Views.cs index 01eb2bd7be..35e1f82edf 100644 --- a/contract/AElf.Contracts.MultiToken/TokenContract_Views.cs +++ b/contract/AElf.Contracts.MultiToken/TokenContract_Views.cs @@ -76,12 +76,14 @@ public override GetAllowanceOutput GetAvailableAllowance(GetAllowanceInput input result.Allowance = allowance; return result; } + var symbolType = GetSymbolType(symbol); - allowance = Math.Max(allowance, GetAllSymbolAllowance(input.Owner,input.Spender,out _)); if (symbolType == SymbolType.Nft || symbolType == SymbolType.NftCollection) { - allowance = Math.Max(allowance, GetNftCollectionAllSymbolAllowance(input.Owner, input.Spender, symbol, out _)); + allowance = Math.Max(allowance, + GetNftCollectionAllSymbolAllowance(input.Owner, input.Spender, symbol, out _)); } + result.Allowance = allowance; return result; } @@ -90,7 +92,7 @@ private bool CheckSymbolIdentifier(string symbol) { var words = symbol.Split(TokenContractConstants.NFTSymbolSeparator); var allSymbolIdentifier = GetAllSymbolIdentifier(); - return words[0].Equals(allSymbolIdentifier) || (words.Length > 1 && words[1].Equals(allSymbolIdentifier)); + return words.Length > 1 && words[1].Equals(allSymbolIdentifier); } public override BoolValue IsInWhiteList(IsInWhiteListInput input) diff --git a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs index 201e56d6e6..d6a6aae570 100644 --- a/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs +++ b/test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -527,6 +528,7 @@ await TokenContractStub.Create.SendAsync(new CreateInput Symbol = "ABC-1" }); } + [Fact] public async Task MultiTokenContract_TransferFrom_Nft_Global_Test() { @@ -557,92 +559,84 @@ await TokenContractStub.Issue.SendAsync(new IssueInput Symbol = "ABC-1" }); balance.Balance.ShouldBe(200); - await TokenContractStub.Approve.SendAsync(new ApproveInput + { - Amount = 1000, - Symbol = "*", - Spender = User1Address - }); - + var executionResult = await TokenContractStub.Approve.SendWithExceptionAsync(new ApproveInput + { + Amount = 1000, + Symbol = "*", + Spender = User1Address + }); + executionResult.TransactionResult.Error.ShouldContain("Token is not found."); + } + await TokenContractStub.Approve.SendAsync(new ApproveInput { Amount = 1, Symbol = "ABC-*", Spender = User1Address }); - var allowance = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ABC-1" - }); - allowance.Allowance.ShouldBe(0); - allowance = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ELF" - }); - allowance.Allowance.ShouldBe(0); - { - var realAllowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ABC-1" - }); - realAllowance.Allowance.ShouldBe(1000); - } - { - var realAllowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ELF" - }); - realAllowance.Allowance.ShouldBe(1000); - } + + await CheckAllowance("ABC-1", 0); + await CheckAllowance("ELF", 0); + await CheckAvailableAllowance("ABC-1", 1); + await CheckAvailableAllowance("ELF", 0); + var user1Stub = GetTester(TokenContractAddress, User1KeyPair); - var result2 = await user1Stub.TransferFrom.SendAsync(new TransferFromInput - { - Amount = 50, - From = DefaultAddress, - Memo = "test", - Symbol = "ABC-1", - To = User1Address - }); - result2.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined); + { - var realAllowance = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput + var executionResult = await user1Stub.TransferFrom.SendWithExceptionAsync(new TransferFromInput { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ABC-1" + Amount = 50, + From = DefaultAddress, + Memo = "test", + Symbol = "ABC-1", + To = User1Address }); - realAllowance.Allowance.ShouldBe(0); + executionResult.TransactionResult.Error.ShouldContain("Insufficient allowance."); } - allowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ABC-1" - }); - allowance.Allowance.ShouldBe(1000-50); + + await CheckAllowance("ABC-1", 0); + await CheckAvailableAllowance("ABC-1", 1); + + // Not changed actually. balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput { Owner = DefaultAddress, Symbol = "ABC-1" }); - balance.Balance.ShouldBe(50); + balance.Balance.ShouldBe(100); balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput { Owner = User1Address, Symbol = "ABC-1" }); - balance.Balance.ShouldBe(250); + balance.Balance.ShouldBe(200); } - + + private async Task CheckAllowance(string symbol, long shouldBeAllowance) + { + var allowance = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput + { + Owner = DefaultAddress, + Spender = User1Address, + Symbol = symbol + }); + allowance.Allowance.ShouldBe(shouldBeAllowance); + } + + private async Task CheckAvailableAllowance(string symbol, long shouldBeAllowance) + { + var allowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput + { + Owner = DefaultAddress, + Spender = User1Address, + Symbol = symbol + }); + allowance.Allowance.ShouldBe(shouldBeAllowance); + } + [Fact] public async Task MultiTokenContract_TransferFrom_Nft_Collection_Test() { @@ -661,42 +655,18 @@ await TokenContractStub.Issue.SendAsync(new IssueInput To = User1Address, Memo = "test" }); - await TokenContractStub.Approve.SendAsync(new ApproveInput - { - Amount = 20, - Symbol = "*", - Spender = User1Address - }); - + await TokenContractStub.Approve.SendAsync(new ApproveInput { Amount = 1000, Symbol = "ABC-*", Spender = User1Address }); - { - var realAllowance = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ABC-1" - }); - realAllowance.Allowance.ShouldBe(0); - } - var allowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ABC-1" - }); - allowance.Allowance.ShouldBe(1000); - allowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ELF" - }); - allowance.Allowance.ShouldBe(20); + + await CheckAllowance("ABC-1", 0); + await CheckAvailableAllowance("ABC-1", 1000); + await CheckAvailableAllowance("ELF", 0); + var user1Stub = GetTester(TokenContractAddress, User1KeyPair); var result2 = await user1Stub.TransferFrom.SendAsync(new TransferFromInput @@ -708,23 +678,9 @@ await TokenContractStub.Approve.SendAsync(new ApproveInput To = User1Address }); result2.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined); - allowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ABC-1" - }); - allowance.Allowance.ShouldBe(1000-50); - allowance = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "*" - }); - allowance.Allowance.ShouldBe(20); - + await CheckAvailableAllowance("ABC-1", 1000 - 50); } - + [Fact] public async Task MultiTokenContract_TransferFrom_Token_Test() { @@ -732,41 +688,13 @@ public async Task MultiTokenContract_TransferFrom_Token_Test() await TokenContractStub.Approve.SendAsync(new ApproveInput { Amount = 100_00000000, - Symbol = "*", + Symbol = "SSS", Spender = User1Address }); - var allowance = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "SSS" - }); - allowance.Allowance.ShouldBe(0); - { - var realAllowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "SSS" - }); - realAllowance.Allowance.ShouldBe(100_00000000); - } - allowance = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "ELF" - }); - allowance.Allowance.ShouldBe(0); - { - var realAllowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "SSS" - }); - realAllowance.Allowance.ShouldBe(100_00000000); - } + await CheckAllowance("SSS", 100_00000000); + await CheckAvailableAllowance("SSS", 100_00000000); + await CheckAllowance("ELF", 0); + var user1Stub = GetTester(TokenContractAddress, User1KeyPair); var result2 = await user1Stub.TransferFrom.SendAsync(new TransferFromInput @@ -776,15 +704,10 @@ await TokenContractStub.Approve.SendAsync(new ApproveInput Memo = "test", Symbol = "SSS", To = User1Address - }); - result2.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined); - allowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "SSS" }); - allowance.Allowance.ShouldBe(100_00000000-50_00000000); + result2.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined); + await CheckAvailableAllowance("SSS", 100_00000000 - 50_00000000); + var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput { Owner = DefaultAddress, @@ -825,6 +748,7 @@ await TokenContractStub.Issue.SendAsync(new IssueInput }); balance.Balance.ShouldBe(TotalSupply); } + [Fact] public async Task MultiTokenContract_Approve_Test_New() { @@ -842,50 +766,19 @@ await TokenContractStub.Approve.SendAsync(new ApproveInput Symbol = "SSS" }); allowance.Allowance.ShouldBe(100_000000000); - await TokenContractStub.Approve.SendAsync(new ApproveInput - { - Spender = User1Address, - Symbol = "*", - Amount = 200_000000000 - }); - { - var realAllowance = await TokenContractStub.GetAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "SSS" - }); - realAllowance.Allowance.ShouldBe(100_000000000); - } - allowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "SSS" - }); - allowance.Allowance.ShouldBe(200_000000000); - allowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "*" - }); - allowance.Allowance.ShouldBe(200_000000000); + + await CheckAllowance("SSS", 100_000000000); + await CheckAvailableAllowance("SSS", 100_000000000); + await TokenContractStub.UnApprove.SendAsync(new UnApproveInput { Spender = User1Address, - Symbol = "*", + Symbol = "SSS", Amount = 20_000000000 }); - allowance = await TokenContractStub.GetAvailableAllowance.CallAsync(new GetAllowanceInput - { - Owner = DefaultAddress, - Spender = User1Address, - Symbol = "*" - }); - allowance.Allowance.ShouldBe(200_000000000-20_000000000); + await CheckAvailableAllowance("SSS", 100_000000000 - 20_000000000); } - + [Fact] public async Task MultiTokenContract_Approve_Test_New_Fail() { @@ -897,7 +790,7 @@ public async Task MultiTokenContract_Approve_Test_New_Fail() Symbol = "SSS*", Amount = 100_000000000 }); - executionResult.TransactionResult.Error.ShouldContain("Invalid symbol."); + executionResult.TransactionResult.Error.ShouldContain("Token is not found."); } { var executionResult = await TokenContractStub.Approve.SendWithExceptionAsync(new ApproveInput @@ -906,7 +799,7 @@ public async Task MultiTokenContract_Approve_Test_New_Fail() Symbol = "SSS**", Amount = 100_000000000 }); - executionResult.TransactionResult.Error.ShouldContain("Invalid symbol."); + executionResult.TransactionResult.Error.ShouldContain("Token is not found."); } { var executionResult = await TokenContractStub.Approve.SendWithExceptionAsync(new ApproveInput @@ -915,7 +808,7 @@ public async Task MultiTokenContract_Approve_Test_New_Fail() Symbol = "*-*", Amount = 100_000000000 }); - executionResult.TransactionResult.Error.ShouldContain("Token is not found"); + executionResult.TransactionResult.Error.ShouldContain("Invalid symbol."); } }