Skip to content

Commit

Permalink
Cancel a sig request also show correctly for founder (#40)
Browse files Browse the repository at this point in the history
* Cancel a sig request

* invest page navigate to view if no project is found

* add a todo comment

* add spacing on the approve sigs

* link portfolio page to pending investment

* Act on review

* act on review
  • Loading branch information
dangershony authored Jan 30, 2024
1 parent f0fa81f commit e0f68a5
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/Angor/Client/Components/FounderProjectItem.razor
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<NavLink href=@($"/view/{FounderProject.ProjectInfo.ProjectIdentifier}") class="btn btn-primary">View Project</NavLink>
@if (InvestmentRequests)
{
<NavLink href=@($"/signatures/{FounderProject.ProjectInfo.ProjectIdentifier}") class="btn btn-success">Approve signatures</NavLink>
<NavLink href=@($"/signatures/{FounderProject.ProjectInfo.ProjectIdentifier}") class="btn btn-success ml-2">Approve signatures</NavLink>
}
</div>
</div>
Expand Down
19 changes: 13 additions & 6 deletions src/Angor/Client/Pages/Invest.razor
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@
else
{
project = SessionStorage.GetProjectById(ProjectId);

if (project == null)
{
NavigationManager.NavigateTo($"/view/{ProjectId}");
return;
}
}
}

Expand Down Expand Up @@ -296,7 +302,7 @@

_SignService.LookupSignatureForInvestmentRequest(
NostrPrivateKey.FromHex(nostrPrivateKeyHex).DerivePublicKey().Hex
, project.NostrPubKey, recoverySigs.TimeOfRequestForSigning.Value,
, project.NostrPubKey, recoverySigs.TimeOfRequestForSigning.Value, recoverySigs.SignatureRequestEventId,
async _ => await HandleSignatureReceivedAsync(nostrPrivateKeyHex, _));
}
}
Expand Down Expand Up @@ -456,14 +462,17 @@
project.NostrPubKey,
strippedInvestmentTransaction.ToHex(network.Consensus.ConsensusFactory));

recoverySigs.TimeOfRequestForSigning = _SignService.RequestInvestmentSigs(new SignRecoveryRequest
var investmentSigsRequest = _SignService.RequestInvestmentSigs(new SignRecoveryRequest
{
ProjectIdentifier = project.ProjectIdentifier,
EncryptedContent = encryptedContent,
NostrPubKey = project.NostrPubKey,
InvestorNostrPrivateKey = nostrPrivateKeyHex
});

recoverySigs.TimeOfRequestForSigning = investmentSigsRequest.eventTime;
recoverySigs.SignatureRequestEventId = investmentSigsRequest.eventId;

storage.AddInvestmentProject(project); //TODO David need to verify that this is the correct place to change state in storage
storage.AddOrUpdateSignatures(recoverySigs);

Expand All @@ -474,7 +483,7 @@

_SignService.LookupSignatureForInvestmentRequest(
NostrPrivateKey.FromHex(nostrPrivateKeyHex).DerivePublicKey().Hex
, project.NostrPubKey, recoverySigs.TimeOfRequestForSigning.Value,
, project.NostrPubKey, recoverySigs.TimeOfRequestForSigning.Value, recoverySigs.SignatureRequestEventId,
async _ => await HandleSignatureReceivedAsync(nostrPrivateKeyHex, _));

return new OperationResult { Success = true, };
Expand Down Expand Up @@ -517,9 +526,6 @@

public async Task CancelInvestment()
{
notificationComponent.ShowErrorMessage("Cancel is not supported yet");
return;

if (recoverySigs == null)
{
var signatures = storage.GetSignatures();
Expand All @@ -540,6 +546,7 @@
}

storage.RemoveSignatures(recoverySigs);
storage.RemoveInvestmentProject(project.ProjectIdentifier);

recoverySigs = null;
}
Expand Down
7 changes: 6 additions & 1 deletion src/Angor/Client/Pages/Investor.razor
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,12 @@
<p class="text-success">Live</p>
}
</td>
<td>@Money.Satoshis(project.SignatureInfo?.AmountInvested ?? 0).ToUnit(MoneyUnit.BTC) @network.CoinTicker @(!project.SignatureInfo?.Signatures?.Any() ?? false ? "(pending)" : string.Empty)</td>
<td>@Money.Satoshis(project.SignatureInfo?.AmountInvested ?? 0).ToUnit(MoneyUnit.BTC) @network.CoinTicker
@if (!project.SignatureInfo?.Signatures?.Any() ?? false)
{
<a href=@($"/invest/{project.ProjectInfo.ProjectIdentifier}") class="btn btn-link" data-toggle="tooltip" title="Pending"> <i class="oi oi-clock"></i></a>
}
</td>
<td>-</td>
<td>-</td>
<td>@Money.Satoshis(project.SignatureInfo?.AmountInRecovery ?? 0).ToUnit(MoneyUnit.BTC) @network.CoinTicker</td>
Expand Down
51 changes: 40 additions & 11 deletions src/Angor/Client/Pages/Signatures.razor
Original file line number Diff line number Diff line change
Expand Up @@ -173,22 +173,37 @@
private async Task FetchPendingSignatures(FounderProject project)
{
await SignService.LookupInvestmentRequestsAsync(project.ProjectInfo.NostrPubKey, null,// project.LastRequestForSignaturesTime , async
(investorPubKey,encryptedMessage, requestTime) =>
(eventId, investorPubKey, encryptedMessage, timeArrived) =>
{
Logger.LogDebug($"Event received");
Logger.LogDebug($"Sig request event received investorPubKey: {investorPubKey} - timeArrived: {timeArrived}");

if (signaturesRequests.Any(_ => _.investorPubKey == investorPubKey))
return; //multiple relays could mean the same massage multiple times
var sigReq = signaturesRequests.FirstOrDefault(_ => _.investorPubKey == investorPubKey);

Logger.LogDebug($"Event received is new");
if (sigReq != null)
{
if (sigReq.TimeArrived < timeArrived)
{
Logger.LogDebug($"Sig request event received is replaced");

// this is a newer sig request so replace it
signaturesRequests.Remove(sigReq);
}
else
{
return; //multiple relays could mean the same massage multiple times
}
}

Logger.LogDebug($"Sig request event received is new");

messagesReceived = true;

var signatureRequest = new SignatureRequest
{
investorPubKey = investorPubKey,
TimeArrived = requestTime,
TransactionHex = encryptedMessage //To be encrypted after js interop is loaded
TimeArrived = timeArrived,
TransactionHex = encryptedMessage, //To be encrypted after js interop is loaded
EventId = eventId
};

signaturesRequests.Add(signatureRequest);
Expand All @@ -209,18 +224,30 @@
private void FetchFounderApprovalsSignatures(FounderProject project)
{
SignService.LookupInvestmentRequestApprovals(project.ProjectInfo.NostrPubKey,
(investorPubKey, requestTime) =>
(investorPubKey, timeApproved, reqEventId) =>
{
Logger.LogDebug($"Event received");
Logger.LogDebug($"Sig response event received investorPubKey: {investorPubKey} - timeApproved: {timeApproved} - reqEventId: {reqEventId}");

var signatureRequest = signaturesRequests.FirstOrDefault(_ => _.investorPubKey == investorPubKey);

if (signatureRequest is null || signatureRequest.TimeApproved != null)
return; //multiple relays could mean the same massage multiple times
if (signatureRequest.TimeArrived > timeApproved)
{
Logger.LogDebug($"The event received is replaced by time");
return; // sig of an old request
}

if (reqEventId != null && signatureRequest.EventId != reqEventId)
{
Logger.LogDebug($"The event received is replaced by eventid");
return; // sig of an old request
}

Logger.LogDebug($"The event received is new");

signatureRequest.TimeApproved = requestTime;
signatureRequest.TimeApproved = timeApproved;

Logger.LogDebug($"Added to pendingSignatures");
},
Expand Down Expand Up @@ -267,7 +294,7 @@
signature.investorPubKey,
sigJson);

FounderProject.LastRequestForSignaturesTime = SignService.SendSignaturesToInvestor(encryptedContent, nostrPrivateKeyHex, signature.investorPubKey);
FounderProject.LastRequestForSignaturesTime = SignService.SendSignaturesToInvestor(encryptedContent, nostrPrivateKeyHex, signature.investorPubKey, signature.EventId);

Storage.UpdateFounderProject(FounderProject);

Expand Down Expand Up @@ -311,5 +338,7 @@
public DateTime? TimeApproved { get; set; }

public string? TransactionHex { get; set; }

public string EventId { get; set; }
}
}
11 changes: 11 additions & 0 deletions src/Angor/Client/Storage/ClientStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ public void UpdateInvestmentProject(ProjectInfo project)
_storage.SetItem("projects", ret);
}

public void RemoveInvestmentProject(string projectId)
{
var ret = GetInvestmentProjects();

var item = ret.First(_ => _.ProjectIdentifier == projectId);

ret.Remove(item);

_storage.SetItem("projects", ret);
}

public void DeleteInvestmentProjects()
{
_storage.RemoveItem("projects");
Expand Down
1 change: 1 addition & 0 deletions src/Angor/Client/Storage/IClientStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public interface IClientStorage
void SetAccountInfo(string network, AccountInfo items);
void DeleteAccountInfo(string network);
void AddInvestmentProject(ProjectInfo project);
void RemoveInvestmentProject(string projectId);
void UpdateInvestmentProject(ProjectInfo project);
List<ProjectInfo> GetInvestmentProjects();
void AddInvestmentProjectMetadata(string pubkey, ProjectMetadata projectMetadata);
Expand Down
2 changes: 2 additions & 0 deletions src/Angor/Shared/Models/SignatureInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class SignatureInfo
public string EndOfProjectTransactionId { get; set; }
public List<SignatureInfoItem> Signatures { get; set; } = new();
public DateTime? TimeOfRequestForSigning { get; set; }
public string? SignatureRequestEventId { get; set; }

public string? SignedTransactionHex { get; set; }
public long AmountInvested { get; set; }
public long AmountInRecovery { get; set; }
Expand Down
10 changes: 5 additions & 5 deletions src/Angor/Shared/Services/ISignService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ namespace Angor.Client.Services;

public interface ISignService
{
DateTime RequestInvestmentSigs(SignRecoveryRequest signRecoveryRequest);
void LookupSignatureForInvestmentRequest(string investorNostrPubKey, string projectNostrPubKey, DateTime sigRequestSentTime, Func<string, Task> action);
(DateTime eventTime, string eventId) RequestInvestmentSigs(SignRecoveryRequest signRecoveryRequest);
void LookupSignatureForInvestmentRequest(string investorNostrPubKey, string projectNostrPubKey, DateTime sigRequestSentTime, string sigRequestEventId, Func<string, Task> action);

Task LookupInvestmentRequestsAsync(string nostrPubKey, DateTime? since, Action<string, string, DateTime> action,
Task LookupInvestmentRequestsAsync(string nostrPubKey, DateTime? since, Action<string, string, string, DateTime> action,
Action onAllMessagesReceived);

void LookupInvestmentRequestApprovals(string nostrPubKey, Action<string, DateTime> action,
void LookupInvestmentRequestApprovals(string nostrPubKey, Action<string, DateTime, string> action,
Action onAllMessagesReceived);

DateTime SendSignaturesToInvestor(string encryptedSignatureInfo, string nostrPrivateKey,
string investorNostrPubKey);
string investorNostrPubKey, string eventId);
}
31 changes: 18 additions & 13 deletions src/Angor/Shared/Services/SignService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public SignService(INostrCommunicationFactory communicationFactory, INetworkServ
_subscriptionsHanding = subscriptionsHanding;
}

public DateTime RequestInvestmentSigs(SignRecoveryRequest signRecoveryRequest)
public (DateTime,string) RequestInvestmentSigs(SignRecoveryRequest signRecoveryRequest)
{
var sender = NostrPrivateKey.FromHex(signRecoveryRequest.InvestorNostrPrivateKey);

Expand All @@ -43,10 +43,10 @@ public DateTime RequestInvestmentSigs(SignRecoveryRequest signRecoveryRequest)
var nostrClient = _communicationFactory.GetOrCreateClient(_networkService);
nostrClient.Send(new NostrEventRequest(signed));

return signed.CreatedAt!.Value;
return (signed.CreatedAt!.Value, signed.Id);
}

public void LookupSignatureForInvestmentRequest(string investorNostrPubKey, string projectNostrPubKey, DateTime sigRequestSentTime, Func<string, Task> action)
public void LookupSignatureForInvestmentRequest(string investorNostrPubKey, string projectNostrPubKey, DateTime sigRequestSentTime, string sigRequestEventId, Func<string, Task> action)
{
var nostrClient = _communicationFactory.GetOrCreateClient(_networkService);

Expand All @@ -67,12 +67,13 @@ public void LookupSignatureForInvestmentRequest(string investorNostrPubKey, stri
P = new[] { investorNostrPubKey }, // To investor
Kinds = new[] { NostrKind.EncryptedDm },
Since = sigRequestSentTime,
A = new[] { NostrCoordinatesIdentifierTag(projectNostrPubKey) }, //Only signature requests
Limit = 1
E = new [] { sigRequestEventId },
//A = new[] { NostrCoordinatesIdentifierTag(projectNostrPubKey) }, //Only signature requests
Limit = 1,
}));
}

public Task LookupInvestmentRequestsAsync(string nostrPubKey, DateTime? since, Action<string,string,DateTime> action, Action onAllMessagesReceived)
public Task LookupInvestmentRequestsAsync(string nostrPubKey, DateTime? since, Action<string, string, string,DateTime> action, Action onAllMessagesReceived)
{
var nostrClient = _communicationFactory.GetOrCreateClient(_networkService);
var subscriptionKey = nostrPubKey + "sig_req";
Expand All @@ -82,7 +83,10 @@ public Task LookupInvestmentRequestsAsync(string nostrPubKey, DateTime? since, A
var subscription = nostrClient.Streams.EventStream
.Where(_ => _.Subscription == subscriptionKey)
.Select(_ => _.Event)
.Subscribe(_ => { action.Invoke(_.Pubkey, _.Content, _.CreatedAt.Value); });
.Subscribe(nostrEvent =>
{
action.Invoke(nostrEvent.Id, nostrEvent.Pubkey, nostrEvent.Content, nostrEvent.CreatedAt.Value);
});

_subscriptionsHanding.TryAddRelaySubscription(subscriptionKey, subscription);
}
Expand All @@ -100,7 +104,7 @@ public Task LookupInvestmentRequestsAsync(string nostrPubKey, DateTime? since, A
return Task.CompletedTask;
}

public void LookupInvestmentRequestApprovals(string nostrPubKey, Action<string, DateTime> action, Action onAllMessagesReceived)
public void LookupInvestmentRequestApprovals(string nostrPubKey, Action<string, DateTime, string> action, Action onAllMessagesReceived)
{
var nostrClient = _communicationFactory.GetOrCreateClient(_networkService);
var subscriptionKey = nostrPubKey + "sig_res";
Expand All @@ -110,9 +114,9 @@ public void LookupInvestmentRequestApprovals(string nostrPubKey, Action<string,
var subscription = nostrClient.Streams.EventStream
.Where(_ => _.Subscription == subscriptionKey)
.Select(_ => _.Event)
.Subscribe(_ =>
.Subscribe(nostrEvent =>
{
action.Invoke(_.Tags.FindFirstTagValue(NostrEventTag.ProfileIdentifier), _.CreatedAt.Value);
action.Invoke(nostrEvent.Tags.FindFirstTagValue(NostrEventTag.ProfileIdentifier), nostrEvent.CreatedAt.Value, nostrEvent.Tags.FindFirstTagValue(NostrEventTag.EventIdentifier));
});

_subscriptionsHanding.TryAddRelaySubscription(subscriptionKey, subscription);
Expand All @@ -124,11 +128,11 @@ public void LookupInvestmentRequestApprovals(string nostrPubKey, Action<string,
{
Authors = new[] { nostrPubKey }, //From founder
Kinds = new[] { NostrKind.EncryptedDm },
A = new[] { NostrCoordinatesIdentifierTag(nostrPubKey) }, //Only signature requests
A = new[] { NostrCoordinatesIdentifierTag(nostrPubKey) } //Only signature requests
}));
}

public DateTime SendSignaturesToInvestor(string encryptedSignatureInfo, string nostrPrivateKeyHex, string investorNostrPubKey)
public DateTime SendSignaturesToInvestor(string encryptedSignatureInfo, string nostrPrivateKeyHex, string investorNostrPubKey, string eventId)
{
var nostrPrivateKey = NostrPrivateKey.FromHex(nostrPrivateKeyHex);

Expand All @@ -140,7 +144,8 @@ public DateTime SendSignaturesToInvestor(string encryptedSignatureInfo, string n
Tags = new NostrEventTags(new []
{
NostrEventTag.Profile(investorNostrPubKey),
new NostrEventTag(NostrEventTag.CoordinatesIdentifier,NostrCoordinatesIdentifierTag(nostrPrivateKey.DerivePublicKey().Hex))
new NostrEventTag(NostrEventTag.CoordinatesIdentifier,NostrCoordinatesIdentifierTag(nostrPrivateKey.DerivePublicKey().Hex)),
NostrEventTag.Event(eventId)
})
};

Expand Down

0 comments on commit e0f68a5

Please sign in to comment.