public override Empty AddProfits(AddProfitsInput input) { var profitItem = State.ProfitItemsMap[input.ProfitId]; Assert(profitItem != null, "Profit item not found."); if (profitItem == null) { return(new Empty()); } var virtualAddress = Context.ConvertVirtualAddressToContractAddress(input.ProfitId); if (input.Period == 0) { State.TokenContract.TransferFrom.Send(new TransferFromInput { From = Context.Sender, To = virtualAddress, Symbol = profitItem.TokenSymbol, Amount = input.Amount, Memo = $"Add dividends for {input.ProfitId}." }); profitItem.TotalAmount += input.Amount; State.ProfitItemsMap[input.ProfitId] = profitItem; } else { var releasedProfitsVirtualAddress = GetReleasedPeriodProfitsVirtualAddress(virtualAddress, input.Period); State.TokenContract.TransferFrom.Send(new TransferFromInput { From = Context.Sender, To = releasedProfitsVirtualAddress, Symbol = profitItem.TokenSymbol, Amount = input.Amount, Memo = $"Add dividends for {input.ProfitId} (period {input.Period})." }); var releasedProfitsInformation = State.ReleasedProfitsMap[releasedProfitsVirtualAddress]; if (releasedProfitsInformation == null) { releasedProfitsInformation = new ReleasedProfitsInformation { ProfitsAmount = input.Amount }; } else { releasedProfitsInformation.ProfitsAmount += input.Amount; } State.ReleasedProfitsMap[releasedProfitsVirtualAddress] = releasedProfitsInformation; } return(new Empty()); }
/// <summary> /// There should be at least one pre-condition to release profits if this is a sub profit item: /// Higher level profit item has already released. /// Otherwise this profit item maybe has nothing to release. /// This pre-condition should be met before calling this method. /// </summary> /// <param name="input"></param> /// <returns></returns> public override Empty ReleaseProfit(ReleaseProfitInput input) { var profitItem = State.ProfitItemsMap[input.ProfitId]; Assert(profitItem != null, "Profit item not found."); if (profitItem == null) { return(new Empty()); } Assert(Context.Sender == profitItem.Creator, "Only creator can release profits."); // Update current_period. var releasingPeriod = profitItem.CurrentPeriod; Assert(input.Period == releasingPeriod, "Invalid period."); Assert(profitItem.TotalWeight > 0, "Invalid total weight."); var profitVirtualAddress = Context.ConvertVirtualAddressToContractAddress(input.ProfitId); var balance = State.TokenContract.GetBalance.Call(new GetBalanceInput { Owner = profitVirtualAddress, Symbol = profitItem.TokenSymbol }).Balance; Assert(input.Amount <= balance, "Insufficient profits amount."); var profitsReceivingVirtualAddress = GetReleasedPeriodProfitsVirtualAddress(profitVirtualAddress, releasingPeriod); var releasedProfitInformation = State.ReleasedProfitsMap[profitsReceivingVirtualAddress]; if (releasedProfitInformation == null) { releasedProfitInformation = new ReleasedProfitsInformation { TotalWeight = profitItem.TotalWeight, ProfitsAmount = input.Amount, IsReleased = true }; } else { releasedProfitInformation.TotalWeight = profitItem.TotalWeight; releasedProfitInformation.ProfitsAmount += input.Amount; releasedProfitInformation.IsReleased = true; } State.ReleasedProfitsMap[profitsReceivingVirtualAddress] = releasedProfitInformation; // Start releasing. var remainAmount = input.Amount; foreach (var subProfitItem in profitItem.SubProfitItems) { var subItemVirtualAddress = Context.ConvertVirtualAddressToContractAddress(subProfitItem.ProfitId); var amount = subProfitItem.Weight.Mul(input.Amount).Div(profitItem.TotalWeight); if (amount != 0) { State.TokenContract.TransferFrom.Send(new TransferFromInput { From = profitVirtualAddress, To = subItemVirtualAddress, Amount = amount, Symbol = profitItem.TokenSymbol }); } remainAmount -= amount; var subItem = State.ProfitItemsMap[subProfitItem.ProfitId]; subItem.TotalAmount += amount; State.ProfitItemsMap[subProfitItem.ProfitId] = subItem; // Update current_period of detail of sub profit item. var subItemDetail = State.ProfitDetailsMap[input.ProfitId][subItemVirtualAddress]; foreach (var detail in subItemDetail.Details) { detail.LastProfitPeriod = profitItem.CurrentPeriod; } State.ProfitDetailsMap[input.ProfitId][subItemVirtualAddress] = subItemDetail; } if (remainAmount != 0) { State.TokenContract.TransferFrom.Send(new TransferFromInput { From = profitVirtualAddress, To = profitsReceivingVirtualAddress, Amount = remainAmount, Symbol = profitItem.TokenSymbol }); } profitItem.CurrentPeriod += 1; State.ProfitItemsMap[input.ProfitId] = profitItem; return(new Empty()); }