Skip to content

Commit 5300a2b

Browse files
committed
Merge branch 'dev'
2 parents 1c65ebd + 2eeeb06 commit 5300a2b

File tree

8 files changed

+213
-1
lines changed

8 files changed

+213
-1
lines changed

contract/AElf.Contracts.MultiToken/TokenContractState.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,6 @@ public partial class TokenContractState : ContractState
7676

7777
// Alias -> Actual Symbol
7878
public MappedState<string, string> SymbolAliasMap { get; set; }
79+
80+
public MappedState<Address, bool> TransferBlackList { get; set; }
7981
}

contract/AElf.Contracts.MultiToken/TokenContract_Actions.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ public override Empty RegisterCrossChainTokenContractAddress(RegisterCrossChainT
559559
/// <returns></returns>
560560
public override Empty CrossChainTransfer(CrossChainTransferInput input)
561561
{
562+
Assert(!IsInTransferBlackListInternal(Context.Sender), "Sender is in transfer blacklist.");
562563
var tokenInfo = AssertValidToken(input.Symbol, input.Amount);
563564
AssertValidMemo(input.Memo);
564565
var issueChainId = GetIssueChainId(tokenInfo.Symbol);
@@ -849,4 +850,20 @@ private void CheckTokenAlias(string alias, string collectionSymbol)
849850
Assert(parts.Last() == TokenContractConstants.CollectionSymbolSuffix, "Incorrect collection symbol suffix.");
850851
Assert(alias == parts.First(), $"Alias for an item of {collectionSymbol} cannot be {alias}.");
851852
}
853+
854+
public override Empty AddToTransferBlackList(Address input)
855+
{
856+
AssertSenderAddressWith(GetDefaultParliamentController().OwnerAddress);
857+
Assert(input != null && !input.Value.IsNullOrEmpty(), "Invalid address.");
858+
State.TransferBlackList[input] = true;
859+
return new Empty();
860+
}
861+
862+
public override Empty RemoveFromTransferBlackList(Address input)
863+
{
864+
AssertSenderAddressWith(GetDefaultParliamentController().OwnerAddress);
865+
Assert(input != null && !input.Value.IsNullOrEmpty(), "Invalid address.");
866+
State.TransferBlackList[input] = false;
867+
return new Empty();
868+
}
852869
}

contract/AElf.Contracts.MultiToken/TokenContract_Fees.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ private void ModifyDelegation(TransactionFeeBill bill, TransactionFreeFeeAllowan
237237
private void ModifyBalance(Address fromAddress, TransactionFeeBill bill,
238238
TransactionFreeFeeAllowanceBill allowanceBill)
239239
{
240+
Assert(!IsInTransferBlackListInternal(fromAddress), "Charge fee address is in transfer blacklist.");
240241
SetOrRefreshTransactionFeeFreeAllowances(fromAddress);
241242
var freeAllowancesMap = CalculateTransactionFeeFreeAllowances(fromAddress);
242243

contract/AElf.Contracts.MultiToken/TokenContract_Helper.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ private void AssertValidInputAddress(Address input)
9898

9999
private void DoTransfer(Address from, Address to, string symbol, long amount, string memo = null)
100100
{
101+
Assert(!IsInTransferBlackListInternal(from), "From address is in transfer blacklist.");
101102
Assert(from != to, "Can't do transfer to sender itself.");
102103
AssertValidMemo(memo);
103104
ModifyBalance(from, symbol, -amount);
@@ -419,4 +420,9 @@ private void SetTokenInfo(TokenInfo tokenInfo)
419420
var symbol = tokenInfo.Symbol;
420421
State.TokenInfos[symbol] = tokenInfo;
421422
}
423+
424+
private bool IsInTransferBlackListInternal(Address address)
425+
{
426+
return State.TransferBlackList[address];
427+
}
422428
}

contract/AElf.Contracts.MultiToken/TokenContract_Views.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,4 +292,10 @@ private string GetActualTokenSymbol(string aliasOrSymbol)
292292

293293
return aliasOrSymbol;
294294
}
295+
296+
[View]
297+
public override BoolValue IsInTransferBlackList(Address input)
298+
{
299+
return new BoolValue { Value = State.TransferBlackList[input] };
300+
}
295301
}

protobuf/token_contract_impl.proto

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,17 @@ service TokenContractImpl {
185185

186186
rpc ExtendSeedExpirationTime (ExtendSeedExpirationTimeInput) returns (google.protobuf.Empty) {
187187
}
188+
189+
// Add an address to the transfer blacklist. Only parliament owner can call this method.
190+
rpc AddToTransferBlackList (aelf.Address) returns (google.protobuf.Empty) {
191+
}
192+
// Remove an address from the transfer blacklist. Only parliament owner can call this method.
193+
rpc RemoveFromTransferBlackList (aelf.Address) returns (google.protobuf.Empty) {
194+
}
195+
// Check if an address is in the transfer blacklist.
196+
rpc IsInTransferBlackList (aelf.Address) returns (google.protobuf.BoolValue) {
197+
option (aelf.is_view) = true;
198+
}
188199
}
189200

190201
message AdvanceResourceTokenInput {

templates/build-template-linux.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
displayName: Build tasks (Linux) [${{ parameters.n }} of ${{ parameters.parts }} parts]
1515
timeoutInMinutes: 120
1616
pool:
17-
vmImage: ubuntu-latest
17+
vmImage: ubuntu-22.04
1818
variables:
1919
CI_TEST: true
2020
steps:

test/AElf.Contracts.MultiToken.Tests/BVT/TokenApplicationTests.cs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,4 +1904,173 @@ public async Task ExtendSeedExpirationTime_Test(string symbol, long expirationTi
19041904

19051905
await TokenContractStub.ExtendSeedExpirationTime.CallAsync(input);
19061906
}
1907+
1908+
[Fact]
1909+
public async Task MultiTokenContract_Transfer_BlackList_Test()
1910+
{
1911+
await MultiTokenContract_Approve_Test();
1912+
1913+
var trafficToken = "TRAFFIC";
1914+
await CreateAndIssueCustomizeTokenAsync(DefaultAddress, trafficToken, 10000, 10000);
1915+
1916+
// 1. Non-owner cannot add to blacklist
1917+
var addBlackListResult = await TokenContractStubUser.AddToTransferBlackList.SendWithExceptionAsync(DefaultAddress);
1918+
addBlackListResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
1919+
addBlackListResult.TransactionResult.Error.ShouldContain("Unauthorized behavior");
1920+
var isInTransferBlackList = await TokenContractStubUser.IsInTransferBlackList.CallAsync(DefaultAddress);
1921+
isInTransferBlackList.Value.ShouldBe(false);
1922+
1923+
// 2. Owner adds DefaultAddress to blacklist via parliament proposal
1924+
var defaultParliament = await ParliamentContractStub.GetDefaultOrganizationAddress.CallAsync(new Empty());
1925+
var proposalId = await CreateProposalAsync(TokenContractAddress, defaultParliament, nameof(TokenContractStub.AddToTransferBlackList), DefaultAddress);
1926+
await ApproveWithMinersAsync(proposalId);
1927+
await ParliamentContractStub.Release.SendAsync(proposalId);
1928+
isInTransferBlackList = await TokenContractStubUser.IsInTransferBlackList.CallAsync(DefaultAddress);
1929+
isInTransferBlackList.Value.ShouldBe(true);
1930+
1931+
// 3. Transfer should fail when sender is in blacklist
1932+
var transferResult = (await TokenContractStub.Transfer.SendWithExceptionAsync(new TransferInput
1933+
{
1934+
Amount = Amount,
1935+
Memo = "blacklist test",
1936+
Symbol = AliceCoinTokenInfo.Symbol,
1937+
To = User1Address
1938+
})).TransactionResult;
1939+
transferResult.Status.ShouldBe(TransactionResultStatus.Failed);
1940+
transferResult.Error.ShouldContain("From address is in transfer blacklist");
1941+
1942+
// 4. TransferFrom should fail when from address is in blacklist
1943+
var user1Stub = GetTester<TokenContractImplContainer.TokenContractImplStub>(TokenContractAddress, User1KeyPair);
1944+
var transferFromResult = (await user1Stub.TransferFrom.SendWithExceptionAsync(new TransferFromInput
1945+
{
1946+
Amount = Amount,
1947+
From = DefaultAddress,
1948+
Memo = "blacklist test",
1949+
Symbol = AliceCoinTokenInfo.Symbol,
1950+
To = User1Address
1951+
})).TransactionResult;
1952+
transferFromResult.Status.ShouldBe(TransactionResultStatus.Failed);
1953+
transferFromResult.Error.ShouldContain("From address is in transfer blacklist");
1954+
1955+
// 5. CrossChainTransfer should fail when sender is in blacklist
1956+
var crossChainTransferResult = (await TokenContractStub.CrossChainTransfer.SendWithExceptionAsync(new CrossChainTransferInput
1957+
{
1958+
Symbol = AliceCoinTokenInfo.Symbol,
1959+
Amount = Amount,
1960+
To = User1Address,
1961+
IssueChainId = 9992731,
1962+
Memo = "blacklist test",
1963+
ToChainId = 9992732
1964+
})).TransactionResult;
1965+
crossChainTransferResult.Status.ShouldBe(TransactionResultStatus.Failed);
1966+
crossChainTransferResult.Error.ShouldContain("Sender is in transfer blacklist");
1967+
1968+
// 6. Lock should fail when sender is in blacklist
1969+
var lockId = HashHelper.ComputeFrom("lockId");
1970+
var lockTokenResult = (await BasicFunctionContractStub.LockToken.SendWithExceptionAsync(new LockTokenInput
1971+
{
1972+
Address = DefaultAddress,
1973+
Amount = Amount,
1974+
Symbol = AliceCoinTokenInfo.Symbol,
1975+
LockId = lockId,
1976+
Usage = "Testing."
1977+
})).TransactionResult;
1978+
lockTokenResult.Status.ShouldBe(TransactionResultStatus.Failed);
1979+
lockTokenResult.Error.ShouldContain("From address is in transfer blacklist");
1980+
1981+
// 7. Transfer to contract should fail when sender is in blacklist
1982+
var transferToContractResult = (await BasicFunctionContractStub.TransferTokenToContract.SendWithExceptionAsync(
1983+
new TransferTokenToContractInput
1984+
{
1985+
Amount = Amount,
1986+
Symbol = AliceCoinTokenInfo.Symbol
1987+
})).TransactionResult;
1988+
transferToContractResult.Status.ShouldBe(TransactionResultStatus.Failed);
1989+
transferToContractResult.Error.ShouldContain("From address is in transfer blacklist");
1990+
1991+
// 8. AdvanceResourceToken should fail when sender is in blacklist
1992+
var advanceRet = await TokenContractStub.AdvanceResourceToken.SendWithExceptionAsync(
1993+
new AdvanceResourceTokenInput
1994+
{
1995+
ContractAddress = BasicFunctionContractAddress,
1996+
Amount = Amount,
1997+
ResourceTokenSymbol = trafficToken
1998+
});
1999+
advanceRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
2000+
advanceRet.TransactionResult.Error.ShouldContain("From address is in transfer blacklist");
2001+
2002+
// 9. Non-owner cannot remove from blacklist
2003+
var removeBlackListResult = await TokenContractStubUser.RemoveFromTransferBlackList.SendWithExceptionAsync(DefaultAddress);
2004+
removeBlackListResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
2005+
removeBlackListResult.TransactionResult.Error.ShouldContain("Unauthorized behavior");
2006+
2007+
// 10. Owner removes DefaultAddress from blacklist via parliament proposal
2008+
var removeProposalId = await CreateProposalAsync(TokenContractAddress, defaultParliament, nameof(TokenContractStub.RemoveFromTransferBlackList), DefaultAddress);
2009+
await ApproveWithMinersAsync(removeProposalId);
2010+
await ParliamentContractStub.Release.SendAsync(removeProposalId);
2011+
isInTransferBlackList = await TokenContractStubUser.IsInTransferBlackList.CallAsync(DefaultAddress);
2012+
isInTransferBlackList.Value.ShouldBe(false);
2013+
2014+
// 11. Transfer should succeed after removing from blacklist
2015+
var transferResult2 = await TokenContractStub.Transfer.SendAsync(new TransferInput
2016+
{
2017+
Amount = Amount,
2018+
Memo = "blacklist test",
2019+
Symbol = AliceCoinTokenInfo.Symbol,
2020+
To = User1Address
2021+
});
2022+
transferResult2.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
2023+
2024+
// 12. TransferFrom should succeed after removing from blacklist
2025+
transferFromResult = (await user1Stub.TransferFrom.SendAsync(new TransferFromInput
2026+
{
2027+
Amount = Amount,
2028+
From = DefaultAddress,
2029+
Memo = "blacklist test",
2030+
Symbol = AliceCoinTokenInfo.Symbol,
2031+
To = User1Address
2032+
})).TransactionResult;
2033+
transferFromResult.Status.ShouldBe(TransactionResultStatus.Mined);
2034+
2035+
// 13. CrossChainTransfer should succeed after removing from blacklist
2036+
crossChainTransferResult = (await TokenContractStub.CrossChainTransfer.SendAsync(new CrossChainTransferInput
2037+
{
2038+
Symbol = AliceCoinTokenInfo.Symbol,
2039+
Amount = Amount,
2040+
To = User1Address,
2041+
IssueChainId = 9992731,
2042+
Memo = "blacklist test",
2043+
ToChainId = 9992732
2044+
})).TransactionResult;
2045+
crossChainTransferResult.Status.ShouldBe(TransactionResultStatus.Mined);
2046+
2047+
// 14. Lock should succeed after removing from blacklist
2048+
lockTokenResult = (await BasicFunctionContractStub.LockToken.SendAsync(new LockTokenInput
2049+
{
2050+
Address = DefaultAddress,
2051+
Amount = Amount,
2052+
Symbol = AliceCoinTokenInfo.Symbol,
2053+
LockId = lockId,
2054+
Usage = "Testing."
2055+
})).TransactionResult;
2056+
lockTokenResult.Status.ShouldBe(TransactionResultStatus.Mined);
2057+
2058+
// 15. Transfer to contract should succeed after removing from blacklist
2059+
transferToContractResult = (await BasicFunctionContractStub.TransferTokenToContract.SendAsync(new TransferTokenToContractInput
2060+
{
2061+
Amount = Amount,
2062+
Symbol = AliceCoinTokenInfo.Symbol
2063+
})).TransactionResult;
2064+
transferToContractResult.Status.ShouldBe(TransactionResultStatus.Mined);
2065+
2066+
// 16. AdvanceResourceToken should succeed after removing from blacklist
2067+
advanceRet = await TokenContractStub.AdvanceResourceToken.SendAsync(
2068+
new AdvanceResourceTokenInput
2069+
{
2070+
ContractAddress = BasicFunctionContractAddress,
2071+
Amount = Amount,
2072+
ResourceTokenSymbol = trafficToken
2073+
});
2074+
advanceRet.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
2075+
}
19072076
}

0 commit comments

Comments
 (0)