Skip to content

Commit 60b7ebe

Browse files
authored
Merge pull request #299 from 0xsequence/wallet-linking
Added GetLinkedWallets and RemoveLinkedWallet APIs
2 parents bf444cd + c88b2e7 commit 60b7ebe

12 files changed

Lines changed: 282 additions & 42 deletions

File tree

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright 2024 Horizon Blockchain Games Inc. All rights reserved.
22
#include "Errors.h"
33

4-
FSequenceError::FSequenceError(const EErrorType Type, const FString Message) : Message(Message), Type(Type)
5-
{
6-
}
4+
FSequenceError::FSequenceError(const EErrorType Type, const FString& Message) :
5+
Response(nullptr), Message(Message), Type(Type) { }
6+
7+
FSequenceError::FSequenceError(const EErrorType Type, const FHttpResponsePtr& Response, const FString& Message) :
8+
Response(Response), Message(Message), Type(Type) { }

Plugins/SequencePlugin/Source/SequencePlugin/Private/RequestHandler.cpp

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -112,24 +112,23 @@ void URequestHandler::ProcessAndThen(const TSuccessCallback<FHttpResponsePtr>& O
112112
const FFailureCallback& OnFailure) const
113113
{
114114
Process().BindLambda([OnSuccess, OnFailure](FHttpRequestPtr Req, const FHttpResponsePtr& Response, const bool bWasSuccessful)
115+
{
116+
const int32 Code = Response->GetResponseCode();
117+
if (bWasSuccessful && Code >= 200 && Code < 300)
115118
{
116-
if (bWasSuccessful)
117-
{
118-
OnSuccess(Response);
119-
}
120-
else
121-
{
122-
if (!Response.IsValid())
123-
OnFailure(FSequenceError(RequestFail, "The Request is invalid!"));
124-
else
125-
{
126-
if (Response.IsValid())
127-
OnFailure(FSequenceError(RequestFail, "The Request is invalid!"));
128-
else
129-
OnFailure(FSequenceError(RequestFail, "Request failed: " + Response->GetContentAsString()));
130-
}
131-
}
132-
});
119+
OnSuccess(Response);
120+
return;
121+
}
122+
123+
if (!Response.IsValid())
124+
{
125+
OnFailure(FSequenceError(RequestFail, Response, "The Request is invalid!"));
126+
return;
127+
}
128+
129+
const FString Content = Response->GetContentAsString();
130+
OnFailure(FSequenceError(RequestFail, Response, "Request failed: " + Content));
131+
});
133132
}
134133

135134

Plugins/SequencePlugin/Source/SequencePlugin/Private/Sequence/SequenceAPI.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,71 @@ void USequenceWallet::SendTransaction(const TArray<TransactionUnion>& Transactio
477477
}
478478
}
479479

480+
void USequenceWallet::GetLinkedWallets(const TSuccessCallback<FSeqLinkedWalletsResponse>& OnSuccess, const FFailureCallback& OnFailure) const
481+
{
482+
const FString& WalletAddress = this->GetWalletAddress();
483+
const FString& MessageToSign = "parent wallet with address " + WalletAddress;
484+
485+
const TSuccessCallback<FSeqSignMessageResponse_Response> OnSignatureSuccess = [this, WalletAddress, MessageToSign, OnSuccess, OnFailure](FSeqSignMessageResponse_Response SignatureResponse)
486+
{
487+
if (this->SequenceRPCManager)
488+
{
489+
const FString& ChainId = this->Credentials.GetNetworkString();
490+
FSeqLinkedWalletRequest Request;
491+
Request.SignatureChainId = ChainId;
492+
Request.ParentWalletAddress = WalletAddress;
493+
Request.ParentWalletMessage = MessageToSign;
494+
Request.ParentWalletSignature = SignatureResponse.Data.Signature;
495+
496+
this->SequenceRPCManager->GetLinkedWallets(Request, OnSuccess, OnFailure);
497+
}
498+
else
499+
{
500+
OnFailure(FSequenceError(RequestFail, "SequenceRPCManager is not available."));
501+
}
502+
};
503+
504+
const TFunction<void (FString, FSequenceError)> OnSignatureFailure = [OnFailure](FString Data, FSequenceError Err)
505+
{
506+
OnFailure(FSequenceError(RequestFail, "Error Parsing Response: " + Err.Message));
507+
};
508+
509+
this->SignMessage(MessageToSign, OnSignatureSuccess, OnFailure);
510+
}
511+
512+
void USequenceWallet::RemoveLinkedWallet(const FString& LinkedWalletAddress, const TFunction<void()>& OnSuccess, const FFailureCallback& OnFailure) const
513+
{
514+
const FString& WalletAddress = this->GetWalletAddress();
515+
const FString& MessageToSign = "parent wallet with address " + WalletAddress + LinkedWalletAddress;
516+
517+
const TSuccessCallback<FSeqSignMessageResponse_Response> OnSignatureSuccess = [this, LinkedWalletAddress, WalletAddress, MessageToSign, OnSuccess, OnFailure](FSeqSignMessageResponse_Response SignatureResponse)
518+
{
519+
if (this->SequenceRPCManager)
520+
{
521+
const FString& ChainId = this->Credentials.GetNetworkString();
522+
FSeqLinkedWalletRequest Request;
523+
Request.SignatureChainId = ChainId;
524+
Request.ParentWalletAddress = WalletAddress;
525+
Request.ParentWalletMessage = MessageToSign;
526+
Request.ParentWalletSignature = SignatureResponse.Data.Signature;
527+
Request.LinkedWalletAddress = LinkedWalletAddress;
528+
529+
this->SequenceRPCManager->RemoveLinkedWallet(Request, OnSuccess, OnFailure);
530+
}
531+
else
532+
{
533+
OnFailure(FSequenceError(RequestFail, "SequenceRPCManager is not available."));
534+
}
535+
};
536+
537+
const TFunction<void (FString, FSequenceError)> OnSignatureFailure = [OnFailure](FString Data, FSequenceError Err)
538+
{
539+
OnFailure(FSequenceError(RequestFail, "Error Parsing Response: " + Err.Message));
540+
};
541+
542+
this->SignMessage(MessageToSign, OnSignatureSuccess, OnFailure);
543+
}
544+
480545
//Indexer Calls
481546

482547
void USequenceWallet::Ping(const TSuccessCallback<bool>& OnSuccess, const FFailureCallback& OnFailure) const

Plugins/SequencePlugin/Source/SequencePlugin/Private/Sequence/SequenceWalletBP.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "Engine/Engine.h"
66
#include "Engine/GameInstance.h"
77
#include "Sequence/SequenceAPI.h"
8+
#include "Util/Log.h"
89

910
USequenceWalletBP::USequenceWalletBP() { }
1011

@@ -304,6 +305,47 @@ void USequenceWalletBP::ApiSignOut()
304305
}
305306
}
306307

308+
void USequenceWalletBP::GetLinkedWallets(FOnLinkedWallets OnSuccess, FOnLinkedWalletsFailure OnFailure)
309+
{
310+
const TFunction<void (FSeqLinkedWalletsResponse)> OnApiSuccess = [OnSuccess](const FSeqLinkedWalletsResponse& LinkedWallets)
311+
{
312+
OnSuccess.ExecuteIfBound(LinkedWallets);
313+
};
314+
315+
const TFunction<void (FSequenceError)> OnApiFailure = [OnFailure](const FSequenceError& Err)
316+
{
317+
OnFailure.ExecuteIfBound(Err.Message);
318+
};
319+
320+
const TOptional<USequenceWallet*> WalletOptional = USequenceWallet::Get();
321+
if (WalletOptional.IsSet() && WalletOptional.GetValue())
322+
{
323+
const USequenceWallet * Wallet = WalletOptional.GetValue();
324+
Wallet->GetLinkedWallets(OnApiSuccess, OnApiFailure);
325+
}
326+
}
327+
328+
void USequenceWalletBP::RemoveLinkedWallet(const FString& LinkedWalletAddress, FOnSuccess OnSuccess, FOnLinkedWalletsFailure OnFailure)
329+
{
330+
const TFunction<void()> OnApiSuccess = [OnSuccess]()
331+
{
332+
OnSuccess.ExecuteIfBound();
333+
};
334+
335+
const TFunction<void (FSequenceError)> OnApiFailure = [OnFailure](const FSequenceError& Err)
336+
{
337+
SEQ_LOG(Error, TEXT("Failed to unlink wallet."));
338+
OnFailure.ExecuteIfBound(Err.Message);
339+
};
340+
341+
const TOptional<USequenceWallet*> WalletOptional = USequenceWallet::Get();
342+
if (WalletOptional.IsSet() && WalletOptional.GetValue())
343+
{
344+
const USequenceWallet * Wallet = WalletOptional.GetValue();
345+
Wallet->RemoveLinkedWallet(LinkedWalletAddress, OnApiSuccess, OnApiFailure);
346+
}
347+
}
348+
307349
void USequenceWalletBP::ApiSignMessage(const FString& Message)
308350
{
309351
const TFunction<void (FSeqSignMessageResponse_Response)> OnSuccess = [this](const FSeqSignMessageResponse_Response& SignedMessage)

Plugins/SequencePlugin/Source/SequencePlugin/Private/SequenceRPCManager.cpp

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "Sequence/SequenceAPI.h"
1414
#include "Sequence/SequenceAuthResponseIntent.h"
1515
#include "Misc/DateTime.h"
16+
#include "Util/Log.h"
1617

1718
template<typename T> FString USequenceRPCManager::GenerateIntent(T Data, TOptional<int64> CurrentTime) const
1819
{
@@ -41,6 +42,8 @@ void USequenceRPCManager::SequenceRPC(const FString& Url, const FString& Content
4142
{
4243
UResponseSignatureValidator& RPCValidator = *Validator;
4344

45+
SEQ_LOG_EDITOR(Display, TEXT("%s - %s"), *Url, *Content);
46+
4447
NewObject<URequestHandler>()
4548
->PrepareRequest()
4649
->WithUrl(Url)
@@ -55,6 +58,8 @@ void USequenceRPCManager::SequenceRPC(const FString& Url, const FString& Content
5558

5659
void USequenceRPCManager::SequenceRPC(const FString& Url, const FString& Content, const TSuccessCallback<FHttpResponsePtr>& OnSuccess, const FFailureCallback& OnFailure) const
5760
{
61+
SEQ_LOG_EDITOR(Display, TEXT("%s - %s"), *Url, *Content);
62+
5863
NewObject<URequestHandler>()
5964
->PrepareRequest()
6065
->WithUrl(Url)
@@ -71,31 +76,36 @@ void USequenceRPCManager::SendIntent(const FString& Url, TFunction<FString(TOpti
7176
{
7277
this->SequenceRPC(Url, ContentGenerator(TOptional<int64>()), [this, Url, ContentGenerator, OnSuccess, OnFailure](FHttpResponsePtr Response)
7378
{
74-
UE_LOG(LogTemp, Display, TEXT("SUCCESS"));
75-
UE_LOG(LogTemp, Display, TEXT("CONTENT"));
76-
FString Content = UTF8ToString(FUnsizedData(Response.Get()->GetContent()));
77-
UE_LOG(LogTemp, Display, TEXT("%s"), *Content);
79+
const FString Content = UTF8ToString(FUnsizedData(Response.Get()->GetContent()));
80+
const int32 Code = Response.Get()->GetResponseCode();
81+
82+
SEQ_LOG_EDITOR(Display, TEXT("%d %s"), Code, *Content);
7883

79-
if(Content.Contains("intent is invalid: intent expired") || Content.Contains("intent is invalid: intent issued in the future"))
84+
OnSuccess(Content);
85+
}, [this, Url, ContentGenerator, OnSuccess, OnFailure](const FSequenceError& Error)
86+
{
87+
const FString Content = Error.Response->GetContentAsString();
88+
const int32 Code = Error.Response->GetResponseCode();
89+
SEQ_LOG_EDITOR(Error, TEXT("%d %s"), Code, *Content);
90+
91+
if (!Content.Contains("intent is invalid: intent expired") &&
92+
!Content.Contains("intent is invalid: intent issued in the future"))
8093
{
81-
FString Date = Response->GetHeader("Date");
82-
FDateTime Time;
83-
bool IsParsed = FDateTime::ParseHttpDate(Date, Time);
84-
85-
if(!IsParsed)
86-
{
87-
OnFailure(FSequenceError(FailedToParseIntentTime, "Failed to parse intent time " + Date));
88-
return;
89-
}
90-
91-
UE_LOG(LogTemp, Display, TEXT("Resending intent with date %i"), Time.ToUnixTimestamp());
92-
this->SequenceRPC(Url, ContentGenerator(TOptional(Time.ToUnixTimestamp())), OnSuccess, OnFailure);
94+
OnFailure(Error);
95+
return;
9396
}
94-
else
97+
98+
FDateTime Time;
99+
const FString Date = Error.Response->GetHeader("Date");
100+
if(!FDateTime::ParseHttpDate(Date, Time))
95101
{
96-
OnSuccess(Content);
102+
OnFailure(FSequenceError(FailedToParseIntentTime, Error.Response, "Failed to parse intent time " + Date));
103+
return;
97104
}
98-
}, OnFailure);
105+
106+
UE_LOG(LogTemp, Display, TEXT("Resending intent with date %i"), Time.ToUnixTimestamp());
107+
this->SequenceRPC(Url, ContentGenerator(TOptional(Time.ToUnixTimestamp())), OnSuccess, OnFailure);
108+
});
99109
}
100110

101111
FString USequenceRPCManager::BuildGetFeeOptionsIntent(const FCredentials_BE& Credentials, const TArray<TransactionUnion>& Transactions, TOptional<int64> CurrentTime) const
@@ -952,6 +962,33 @@ void USequenceRPCManager::ForceOpenSessionInUse(const TSuccessCallback<FCredenti
952962
}, OnOpenResponse, OnFailure);
953963
}
954964

965+
void USequenceRPCManager::GetLinkedWallets(const FSeqLinkedWalletRequest& Request, const TSuccessCallback<FSeqLinkedWalletsResponse>& OnSuccess, const FFailureCallback& OnFailure) const
966+
{
967+
const TSuccessCallback<FString> OnResponse = [this, OnSuccess](const FString& OnResponse)
968+
{
969+
const FSeqLinkedWalletsResponse LinkedWallets = USequenceSupport::JSONStringToStruct<FSeqLinkedWalletsResponse>(OnResponse);
970+
OnSuccess(LinkedWallets);
971+
};
972+
973+
this->SendIntent(this->BuildAPIUrl("GetLinkedWallets"),[this, Request](const TOptional<int64>& CurrentTime)
974+
{
975+
return USequenceSupport::StructToString(Request);
976+
}, OnResponse, OnFailure);
977+
}
978+
979+
void USequenceRPCManager::RemoveLinkedWallet(const FSeqLinkedWalletRequest& Request, const TFunction<void()>& OnSuccess, const FFailureCallback& OnFailure) const
980+
{
981+
const TSuccessCallback<FString> OnResponse = [this, OnSuccess](const FString& OnResponse)
982+
{
983+
OnSuccess();
984+
};
985+
986+
this->SendIntent(this->BuildAPIUrl("RemoveLinkedWallet"),[this, Request](const TOptional<int64>& CurrentTime)
987+
{
988+
return USequenceSupport::StructToString(Request);
989+
}, OnResponse, OnFailure);
990+
}
991+
955992
void USequenceRPCManager::FederateEmailSession(const FString& WalletIn, const FString& CodeIn, const TFunction<void()>& OnSuccess, const FFailureCallback& OnFailure)
956993
{
957994
this->UpdateWithStoredSessionWallet();

Plugins/SequencePlugin/Source/SequencePlugin/Private/SequenceRPCManager.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,20 @@ class SEQUENCEPLUGIN_API USequenceRPCManager : public UObject
276276
* @param OnFailure Fires if there's an Authentication Issue
277277
*/
278278
void ForceOpenSessionInUse(const TSuccessCallback<FCredentials_BE>& OnSuccess, const FFailureCallback& OnFailure);
279+
280+
/**
281+
* GetLinkedWallets
282+
* @param OnSuccess
283+
* @param OnFailure
284+
*/
285+
void GetLinkedWallets(const FSeqLinkedWalletRequest& Request, const TSuccessCallback<FSeqLinkedWalletsResponse>& OnSuccess, const FFailureCallback& OnFailure) const;
286+
287+
/**
288+
* GetLinkedWallets
289+
* @param OnSuccess
290+
* @param OnFailure
291+
*/
292+
void RemoveLinkedWallet(const FSeqLinkedWalletRequest& Request, const TFunction<void()>& OnSuccess, const FFailureCallback& OnFailure) const;
279293

280294
//Auth Calls//
281295

Plugins/SequencePlugin/Source/SequencePlugin/Private/Util/SequenceSupport.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,11 @@ FString USequenceSupport::StringCleanup(FString String)
575575
return (*Ret);
576576
}
577577

578+
void USequenceSupport::StringReplace(FString* Input, const FString& Search, const FString& Replacement)
579+
{
580+
Input->ReplaceInline(*Search, *Replacement, ESearchCase::IgnoreCase);
581+
}
582+
578583
int64 USequenceSupport::StringDateToUnixDate(const FString& Iso8601)
579584
{
580585
FDateTime ParsedDate;

Plugins/SequencePlugin/Source/SequencePlugin/Public/Errors.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright 2024 Horizon Blockchain Games Inc. All rights reserved.
22
#pragma once
3+
#include "Http.h"
34
#include "Templates/ValueOrError.h"
45
#include "Containers/UnrealString.h"
56

@@ -20,7 +21,9 @@ enum EErrorType
2021
class SEQUENCEPLUGIN_API FSequenceError
2122
{
2223
public:
23-
FSequenceError(EErrorType Type, FString Message);
24+
FSequenceError(EErrorType Type, const FString& Message);
25+
FSequenceError(EErrorType Type, const FHttpResponsePtr& Response, const FString& Message);
26+
FHttpResponsePtr Response;
2427
FString Message;
2528
EErrorType Type;
2629
};

Plugins/SequencePlugin/Source/SequencePlugin/Public/Sequence/SequenceAPI.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,16 @@ class SEQUENCEPLUGIN_API USequenceWallet : public UGameInstanceSubsystem
310310
*/
311311
void GetTransactionHistory(const FSeqGetTransactionHistoryArgs& Args, const TSuccessCallback<FSeqGetTransactionHistoryReturn>& OnSuccess, const FFailureCallback& OnFailure) const;
312312

313+
/*
314+
Get Linked Wallets
315+
*/
316+
void GetLinkedWallets(const TSuccessCallback<FSeqLinkedWalletsResponse>& OnSuccess, const FFailureCallback& OnFailure) const;
317+
318+
/*
319+
Remove a Linked Wallet
320+
*/
321+
void RemoveLinkedWallet(const FString& LinkedWalletAddress, const TFunction<void()>& OnSuccess, const FFailureCallback& OnFailure) const;
322+
313323
//Provider calls
314324

315325
void BlockByNumber(uint64 Number, const TFunction<void(TSharedPtr<FJsonObject>)>& OnSuccess,

0 commit comments

Comments
 (0)