Skip to content

Commit a5752ef

Browse files
authored
Fixing a few issues (#667)
* Add a button to show the project info as json * add correct currency symbol * Add the total available and invested in the shell window * load the balance from database on start and fix amount length * order projects by most recent * fix the payment flow when investing to consider the penalty threshold and use default password when creating a wallet
1 parent a199e89 commit a5752ef

35 files changed

+274
-58
lines changed

src/Angor/Avalonia/Angor.Sdk/Funding/Investor/Domain/InvestmentRecord.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,9 @@ public class InvestmentRecord
1414
public string? RecoveryTransactionId { get; set; }
1515
public string? RecoveryReleaseTransactionId { get; set; }
1616
public string? EndOfProjectTransactionId { get; set; }
17+
18+
/// <summary>
19+
/// The amount invested in satoshis. Stored at publish time so we can sum totals without hitting the indexer.
20+
/// </summary>
21+
public long InvestedAmountSats { get; set; }
1722
}

src/Angor/Avalonia/Angor.Sdk/Funding/Investor/Domain/PortfolioService.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ public class PortfolioService(
1919
{
2020
public async Task<Result<InvestmentRecords>> GetByWalletId(string walletId)
2121
{
22-
// We need to pronmpt user permission to access wallet sensitive data
22+
// Try to get from local document collection first (no password needed)
23+
var localDoc = await documentCollection.FindByIdAsync(walletId);
24+
if (localDoc is { IsSuccess: true, Value: not null })
25+
return Result.Success(new InvestmentRecords(){ProjectIdentifiers = localDoc.Value.Investments});
26+
27+
// Local not found — need wallet sensitive data to fetch from relay
2328
var sensiveDataResult = await seedwordsProvider.GetSensitiveData(walletId);
2429
if (sensiveDataResult.IsFailure)
2530
{
2631
return Result.Failure<InvestmentRecords>(sensiveDataResult.Error);
2732
}
28-
29-
// Try to get from local document collection first
30-
var localDoc = await documentCollection.FindByIdAsync(walletId);
31-
if (localDoc is { IsSuccess: true, Value: not null })
32-
return Result.Success(new InvestmentRecords(){ProjectIdentifiers = localDoc.Value.Investments});
3333

3434
var words = sensiveDataResult.Value.ToWalletWords();
3535
var storageAccountKey = derivationOperations.DeriveNostrStoragePubKeyHex(words);

src/Angor/Avalonia/Angor.Sdk/Funding/Investor/IInvestmentAppService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,9 @@ public interface IInvestmentAppService
4343
/// Monitors a Boltz swap until funds arrive on-chain.
4444
/// </summary>
4545
Task<Result<MonitorLightningSwap.MonitorLightningSwapResponse>> MonitorLightningSwap(MonitorLightningSwap.MonitorLightningSwapRequest request);
46+
47+
/// <summary>
48+
/// Gets the total invested amount (in sats) for a wallet by summing locally stored InvestmentRecord amounts.
49+
/// </summary>
50+
Task<Result<GetTotalInvested.GetTotalInvestedResponse>> GetTotalInvested(GetTotalInvested.GetTotalInvestedRequest request);
4651
}

src/Angor/Avalonia/Angor.Sdk/Funding/Investor/InvestmentAppService.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,8 @@ public class InvestmentAppService(IMediator mediator) : IInvestmentAppService
6464
public Task<Result<MonitorLightningSwap.MonitorLightningSwapResponse>> MonitorLightningSwap(MonitorLightningSwap.MonitorLightningSwapRequest request)
6565
=> mediator.Send(request);
6666

67+
public Task<Result<GetTotalInvested.GetTotalInvestedResponse>> GetTotalInvested(GetTotalInvested.GetTotalInvestedRequest request)
68+
=> mediator.Send(request);
69+
6770
#endregion
6871
}

src/Angor/Avalonia/Angor.Sdk/Funding/Investor/Operations/BuildInvestmentDraft.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ public async Task<Result<BuildInvestmentDraftResponse>> Handle(BuildInvestmentDr
151151
TransactionFee = new Amount(minerFee + angorFee),
152152
MinerFee = new Amount(minerFee),
153153
AngorFee = new Amount(angorFee),
154+
InvestedAmount = transactionRequest.Amount,
154155
SignedTxHex = signedTxHex,
155156
TransactionId = trxId,
156157
}));
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using Angor.Sdk.Common;
2+
using Angor.Sdk.Funding.Investor.Domain;
3+
using Angor.Data.Documents.Interfaces;
4+
using CSharpFunctionalExtensions;
5+
using MediatR;
6+
7+
namespace Angor.Sdk.Funding.Investor.Operations;
8+
9+
public static class GetTotalInvested
10+
{
11+
public record GetTotalInvestedRequest(WalletId WalletId) : IRequest<Result<GetTotalInvestedResponse>>;
12+
13+
public record GetTotalInvestedResponse(long TotalInvestedSats);
14+
15+
/// <summary>
16+
/// Reads investment records directly from local storage (no password required).
17+
/// Only returns data that has already been cached locally.
18+
/// </summary>
19+
public class GetTotalInvestedHandler(IGenericDocumentCollection<InvestmentRecordsDocument> documentCollection)
20+
: IRequestHandler<GetTotalInvestedRequest, Result<GetTotalInvestedResponse>>
21+
{
22+
public async Task<Result<GetTotalInvestedResponse>> Handle(GetTotalInvestedRequest request, CancellationToken cancellationToken)
23+
{
24+
var localDoc = await documentCollection.FindByIdAsync(request.WalletId.Value);
25+
26+
if (localDoc.IsFailure || localDoc.Value is null)
27+
return Result.Success(new GetTotalInvestedResponse(0));
28+
29+
var investments = localDoc.Value.Investments;
30+
if (investments == null || !investments.Any())
31+
return Result.Success(new GetTotalInvestedResponse(0));
32+
33+
var totalSats = investments.Sum(r => r.InvestedAmountSats);
34+
35+
return Result.Success(new GetTotalInvestedResponse(totalSats));
36+
}
37+
}
38+
}

src/Angor/Avalonia/Angor.Sdk/Funding/Investor/Operations/PublishAndStoreInvestorTransaction.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ private async Task<Result> UpdateInvestmentRecordWithTransaction(
8686
investment.InvestmentTransactionHash = draft.TransactionId;
8787
investment.InvestmentTransactionHex = draft.SignedTxHex;
8888
investment.InvestorPubKey = investmentDraft.InvestorKey;
89+
investment.InvestedAmountSats = investmentDraft.InvestedAmount.Sats;
8990
}
9091
else
9192
{
@@ -98,7 +99,8 @@ private async Task<Result> UpdateInvestmentRecordWithTransaction(
9899
ProjectIdentifier = projectId,
99100
UnfundedReleaseAddress = null, // No penalty path for direct investments
100101
RequestEventId = null, // No founder approval request for investments below threshold
101-
RequestEventTime = null
102+
RequestEventTime = null,
103+
InvestedAmountSats = investmentDraft.InvestedAmount.Sats,
102104
};
103105
}
104106
break;

src/Angor/Avalonia/Angor.Sdk/Funding/Projects/Operations/LatestProjects.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public async Task<Result<LatestProjectsResponse>> Handle(LatestProjectsRequest r
1818
{
1919
// var projects = await projectService.LatestAsync();
2020
var projects = await projectService.LatestFromNostrAsync();
21-
return projects.Map(sequence => new LatestProjectsResponse(sequence.Select(project => project.ToDto())));
21+
return projects.Map(sequence => new LatestProjectsResponse(sequence.OrderByDescending(p => p.StartingDate).Select(project => project.ToDto())));
2222
}
2323
}
2424
}

src/Angor/Avalonia/Angor.Sdk/Funding/Services/DocumentProjectService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public async Task<Result<IEnumerable<Project>>> GetAllAsync(params ProjectId[] i
112112

113113
var insertResult = await collection.InsertAsync(project => project.Id.Value, response.ToArray()); //TODO log the result?
114114

115-
return Result.Success(response.Concat(localLookup));
115+
return Result.Success(response.Concat(localLookup).OrderByDescending(p => p.StartingDate).AsEnumerable());
116116
}
117117
catch (Exception ex)
118118
{

src/Angor/Avalonia/Angor.Sdk/Funding/Shared/TransactionDrafts/InvestmentDraft.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,9 @@ public record InvestmentDraft(string InvestorKey) : TransactionDraft
66
{
77
public Amount MinerFee { get; set; } = new Amount(-1);
88
public Amount AngorFee { get; set; } = new Amount(-1);
9+
10+
/// <summary>
11+
/// The investment amount in satoshis (excluding fees).
12+
/// </summary>
13+
public Amount InvestedAmount { get; set; } = new Amount(0);
914
}

0 commit comments

Comments
 (0)