Skip to content

Commit 7b82528

Browse files
committed
fix: prevent LastProfitPeriod from regressing across symbols
1 parent 31bf973 commit 7b82528

2 files changed

Lines changed: 202 additions & 2 deletions

File tree

contract/AElf.Contracts.Profit/ProfitContract.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,7 @@ private Dictionary<string, long> ProfitAllPeriods(Scheme scheme, ProfitDetail pr
905905
});
906906
}
907907

908-
lastProfitPeriod = period + 1;
908+
lastProfitPeriod = Math.Max(lastProfitPeriod, period + 1);
909909
}
910910

911911
totalAmount = totalAmount.Add(amount);

test/AElf.Contracts.Profit.Tests/ProfitTests.cs

Lines changed: 201 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,131 @@ public async Task MaximumProfitReceivingPeriodCount_Test()
17751775
maximumProfitReceivingPeriodCount.Value.ShouldBe(maxPeriodCount);
17761776
}
17771777

1778+
[Fact]
1779+
public async Task ClaimProfits_OtherSymbol_Should_Not_Regress_LastProfitPeriod_Test()
1780+
{
1781+
const long shares = 1;
1782+
const long elfAmountPerPeriod = 100;
1783+
const long otherSymbolAmount = 1;
1784+
const string otherSymbol = "CPU";
1785+
1786+
var creator = Creators[0];
1787+
var beneficiary1 = Normal[0];
1788+
var beneficiary1TokenStub = GetTokenContractTester(NormalKeyPair[0]);
1789+
var beneficiaryAddress1 = Address.FromPublicKey(NormalKeyPair[0].PublicKey);
1790+
var beneficiaryAddress2 = Address.FromPublicKey(NormalKeyPair[1].PublicKey);
1791+
1792+
var initialElfBalance = (await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
1793+
{
1794+
Owner = beneficiaryAddress1,
1795+
Symbol = ProfitContractTestConstants.NativeTokenSymbol
1796+
})).Balance;
1797+
1798+
var schemeId = await CreateSchemeAsync();
1799+
1800+
await creator.AddBeneficiary.SendAsync(new AddBeneficiaryInput
1801+
{
1802+
SchemeId = schemeId,
1803+
BeneficiaryShare = new BeneficiaryShare
1804+
{
1805+
Beneficiary = beneficiaryAddress1,
1806+
Shares = shares
1807+
}
1808+
});
1809+
1810+
await creator.AddBeneficiary.SendAsync(new AddBeneficiaryInput
1811+
{
1812+
SchemeId = schemeId,
1813+
BeneficiaryShare = new BeneficiaryShare
1814+
{
1815+
Beneficiary = beneficiaryAddress2,
1816+
Shares = shares
1817+
}
1818+
});
1819+
1820+
// Make ELF appear first in ReceivedTokenSymbols, then append a short-lived symbol.
1821+
await ContributeProfits(schemeId, elfAmountPerPeriod * 2);
1822+
await CreateTestTokenAsync(otherSymbol, beneficiaryAddress1, otherSymbolAmount);
1823+
await beneficiary1TokenStub.Approve.SendAsync(new ApproveInput
1824+
{
1825+
Spender = ProfitContractAddress,
1826+
Symbol = otherSymbol,
1827+
Amount = otherSymbolAmount
1828+
});
1829+
await beneficiary1.ContributeProfits.SendAsync(new ContributeProfitsInput
1830+
{
1831+
SchemeId = schemeId,
1832+
Symbol = otherSymbol,
1833+
Amount = otherSymbolAmount,
1834+
Period = 1
1835+
});
1836+
1837+
var scheme = await creator.GetScheme.CallAsync(schemeId);
1838+
scheme.ReceivedTokenSymbols.Count.ShouldBe(2);
1839+
scheme.ReceivedTokenSymbols[0].ShouldBe(ProfitContractTestConstants.NativeTokenSymbol);
1840+
scheme.ReceivedTokenSymbols[1].ShouldBe(otherSymbol);
1841+
1842+
await creator.DistributeProfits.SendAsync(new DistributeProfitsInput
1843+
{
1844+
SchemeId = schemeId,
1845+
Period = 1,
1846+
AmountsMap =
1847+
{
1848+
{ ProfitContractTestConstants.NativeTokenSymbol, elfAmountPerPeriod }
1849+
}
1850+
});
1851+
1852+
await creator.DistributeProfits.SendAsync(new DistributeProfitsInput
1853+
{
1854+
SchemeId = schemeId,
1855+
Period = 2,
1856+
AmountsMap =
1857+
{
1858+
{ ProfitContractTestConstants.NativeTokenSymbol, elfAmountPerPeriod }
1859+
}
1860+
});
1861+
1862+
await beneficiary1.ClaimProfits.SendAsync(new ClaimProfitsInput
1863+
{
1864+
SchemeId = schemeId
1865+
});
1866+
1867+
var detailsAfterFirstClaim = await creator.GetProfitDetails.CallAsync(new GetProfitDetailsInput
1868+
{
1869+
SchemeId = schemeId,
1870+
Beneficiary = beneficiaryAddress1
1871+
});
1872+
detailsAfterFirstClaim.Details.Count.ShouldBe(1);
1873+
detailsAfterFirstClaim.Details.First().LastProfitPeriod.ShouldBe(3);
1874+
1875+
var balanceAfterFirstClaim = (await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
1876+
{
1877+
Owner = beneficiaryAddress1,
1878+
Symbol = ProfitContractTestConstants.NativeTokenSymbol
1879+
})).Balance;
1880+
balanceAfterFirstClaim.ShouldBe(initialElfBalance + elfAmountPerPeriod);
1881+
1882+
await beneficiary1.ClaimProfits.SendAsync(new ClaimProfitsInput
1883+
{
1884+
SchemeId = schemeId
1885+
});
1886+
1887+
var balanceAfterSecondClaim = (await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
1888+
{
1889+
Owner = beneficiaryAddress1,
1890+
Symbol = ProfitContractTestConstants.NativeTokenSymbol
1891+
})).Balance;
1892+
balanceAfterSecondClaim.ShouldBe(initialElfBalance + elfAmountPerPeriod);
1893+
1894+
var detailsAfterSecondClaim = await creator.GetProfitDetails.CallAsync(new GetProfitDetailsInput
1895+
{
1896+
SchemeId = schemeId,
1897+
Beneficiary = beneficiaryAddress1
1898+
});
1899+
detailsAfterSecondClaim.Details.Count.ShouldBe(1);
1900+
detailsAfterSecondClaim.Details.First().LastProfitPeriod.ShouldBe(3);
1901+
}
1902+
17781903
private async Task ContributeProfits(Hash schemeId, long amount = 100)
17791904
{
17801905
await ProfitContractStub.ContributeProfits.SendAsync(new ContributeProfitsInput
@@ -1784,4 +1909,79 @@ await ProfitContractStub.ContributeProfits.SendAsync(new ContributeProfitsInput
17841909
Amount = amount
17851910
});
17861911
}
1787-
}
1912+
1913+
private async Task CreateTestTokenAsync(string symbol, Address to, long amount)
1914+
{
1915+
const string seedCollectionSymbol = "SEED-0";
1916+
const string seedSymbol = "SEED-1";
1917+
1918+
var seedCollectionInfo = await TokenContractStub.GetTokenInfo.CallAsync(new GetTokenInfoInput
1919+
{
1920+
Symbol = seedCollectionSymbol
1921+
});
1922+
if (string.IsNullOrEmpty(seedCollectionInfo.Symbol))
1923+
{
1924+
await TokenContractStub.Create.SendAsync(new CreateInput
1925+
{
1926+
Symbol = seedCollectionSymbol,
1927+
Decimals = 0,
1928+
IsBurnable = true,
1929+
TokenName = "seed Collection",
1930+
TotalSupply = 1,
1931+
Issuer = Starter,
1932+
Owner = Starter,
1933+
ExternalInfo = new ExternalInfo()
1934+
});
1935+
}
1936+
1937+
await TokenContractStub.Create.SendAsync(new CreateInput
1938+
{
1939+
Symbol = seedSymbol,
1940+
Decimals = 0,
1941+
IsBurnable = true,
1942+
TokenName = "seed token 1",
1943+
TotalSupply = 1,
1944+
Issuer = Starter,
1945+
Owner = Starter,
1946+
ExternalInfo = new ExternalInfo
1947+
{
1948+
Value =
1949+
{
1950+
{ "__seed_owned_symbol", symbol },
1951+
{
1952+
"__seed_exp_time",
1953+
Timestamp.FromDateTime(global::System.DateTime.UtcNow.AddDays(1)).Seconds.ToString()
1954+
}
1955+
}
1956+
},
1957+
LockWhiteList = { TokenContractAddress }
1958+
});
1959+
1960+
await TokenContractStub.Issue.SendAsync(new IssueInput
1961+
{
1962+
Symbol = seedSymbol,
1963+
Amount = 1,
1964+
Memo = "Issue seed NFT.",
1965+
To = Starter
1966+
});
1967+
1968+
await TokenContractStub.Create.SendAsync(new CreateInput
1969+
{
1970+
Symbol = symbol,
1971+
Decimals = 2,
1972+
IsBurnable = true,
1973+
TokenName = $"{symbol} token",
1974+
TotalSupply = amount,
1975+
Issuer = Starter,
1976+
Owner = Starter
1977+
});
1978+
1979+
await TokenContractStub.Issue.SendAsync(new IssueInput
1980+
{
1981+
Symbol = symbol,
1982+
Amount = amount,
1983+
Memo = $"Issue {symbol}.",
1984+
To = to
1985+
});
1986+
}
1987+
}

0 commit comments

Comments
 (0)