Skip to content

Commit

Permalink
Account Unlinking (#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xFirekeeper authored Dec 17, 2024
1 parent 429187d commit b0631e7
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 5 deletions.
13 changes: 8 additions & 5 deletions Thirdweb.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@

#region Account Linking

// var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google);
// var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Telegram);
// if (!await inAppWalletMain.IsConnected())
// {
// _ = await inAppWalletMain.LoginWithOauth(
Expand All @@ -260,12 +260,15 @@
// var oldLinkedAccounts = await inAppWalletMain.GetLinkedAccounts();
// Console.WriteLine($"Old linked accounts: {JsonConvert.SerializeObject(oldLinkedAccounts, Formatting.Indented)}");

// var inAppWalletToLink = await InAppWallet.Create(client: client, authProvider: AuthProvider.Guest);
// _ = await inAppWalletMain.LinkAccount(walletToLink: inAppWalletToLink);

// var linkedAccounts = await inAppWalletMain.GetLinkedAccounts();
// // External wallet variant
// var externalWallet = await PrivateKeyWallet.Generate(client: client);
// var inAppWalletToLink = await InAppWallet.Create(client: client, authProvider: AuthProvider.Siwe, siweSigner: externalWallet);
// var linkedAccounts = await inAppWalletMain.LinkAccount(walletToLink: inAppWalletToLink, chainId: 421614);
// Console.WriteLine($"Linked accounts: {JsonConvert.SerializeObject(linkedAccounts, Formatting.Indented)}");

// var unlinkingResult = await inAppWalletMain.UnlinkAccount(linkedAccounts.First(linkedAccounts => linkedAccounts.Type == "siwe"));
// Console.WriteLine($"Unlinking result: {JsonConvert.SerializeObject(unlinkingResult, Formatting.Indented)}");

#endregion

#region Smart Wallet - Authenticate
Expand Down
6 changes: 6 additions & 0 deletions Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ Task<List<LinkedAccount>> LinkAccount(
string payload = null
);

/// <summary>
/// Unlinks an account (auth method) from the current wallet.
/// </summary>
/// <param name="accountToUnlink">The linked account to unlink. Same type returned by <see cref="GetLinkedAccounts"/>.</param>
Task<List<LinkedAccount>> UnlinkAccount(LinkedAccount accountToUnlink);

/// <summary>
/// Returns a list of linked accounts to the current wallet.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,36 @@ public string GenerateExternalLoginLink(string redirectUrl)

#region Account Linking

public async Task<List<LinkedAccount>> UnlinkAccount(LinkedAccount accountToUnlink)
{
if (!await this.IsConnected().ConfigureAwait(false))
{
throw new InvalidOperationException("Cannot unlink account with a wallet that is not connected. Please login to the wallet before unlinking other wallets.");
}

var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken;

var serverLinkedAccounts = await this.EmbeddedWallet.UnlinkAccountAsync(currentAccountToken, accountToUnlink).ConfigureAwait(false);
var linkedAccounts = new List<LinkedAccount>();
foreach (var linkedAccount in serverLinkedAccounts)
{
linkedAccounts.Add(
new LinkedAccount
{
Type = linkedAccount.Type,
Details = new LinkedAccount.LinkedAccountDetails
{
Email = linkedAccount.Details?.Email,
Address = linkedAccount.Details?.Address,
Phone = linkedAccount.Details?.Phone,
Id = linkedAccount.Details?.Id
}
}
);
}
return linkedAccounts;
}

public async Task<List<LinkedAccount>> LinkAccount(
IThirdwebWallet walletToLink,
string otp = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Thirdweb.EWS;

internal abstract class ServerBase
{
internal abstract Task<List<Server.LinkedAccount>> UnlinkAccountAsync(string currentAccountToken, Server.LinkedAccount linkedAccount);
internal abstract Task<List<Server.LinkedAccount>> LinkAccountAsync(string currentAccountToken, string authTokenToConnect);
internal abstract Task<List<Server.LinkedAccount>> GetLinkedAccountsAsync(string currentAccountToken);

Expand Down Expand Up @@ -50,6 +51,21 @@ internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient)
this._httpClient = httpClient;
}

// account/disconnect
internal override async Task<List<LinkedAccount>> UnlinkAccountAsync(string currentAccountToken, LinkedAccount linkedAccount)
{
var uri = MakeUri2024("/account/disconnect");
var request = new HttpRequestMessage(HttpMethod.Post, uri)
{
Content = MakeHttpContent(linkedAccount)
};
var response = await this.SendHttpWithAuthAsync(request, currentAccountToken).ConfigureAwait(false);
await CheckStatusCodeAsync(response).ConfigureAwait(false);

var res = await DeserializeAsync<AccountConnectResponse>(response).ConfigureAwait(false);
return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? throw new InvalidOperationException("No linked accounts returned") : res.LinkedAccounts;
}

// account/connect
internal override async Task<List<LinkedAccount>> LinkAccountAsync(string currentAccountToken, string authTokenToConnect)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

internal partial class EmbeddedWallet
{
public async Task<List<Server.LinkedAccount>> UnlinkAccountAsync(string currentAccountToken, LinkedAccount linkedAccount)
{
var serverLinkedAccount = new Server.LinkedAccount
{
Type = linkedAccount.Type,
Details = new Server.LinkedAccount.LinkedAccountDetails
{
Email = linkedAccount.Details.Email,
Address = linkedAccount.Details.Address,
Phone = linkedAccount.Details.Phone,
Id = linkedAccount.Details.Id
}
};
return await this._server.UnlinkAccountAsync(currentAccountToken, serverLinkedAccount).ConfigureAwait(false);
}

public async Task<List<Server.LinkedAccount>> LinkAccountAsync(string currentAccountToken, string authTokenToConnect)
{
return await this._server.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false);
Expand Down
10 changes: 10 additions & 0 deletions Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,24 @@ public enum AuthProvider
/// </summary>
public struct LinkedAccount
{
[JsonProperty("type")]
public string Type { get; set; }

[JsonProperty("details")]
public LinkedAccountDetails Details { get; set; }

public struct LinkedAccountDetails
{
[JsonProperty("email")]
public string Email { get; set; }

[JsonProperty("name")]
public string Address { get; set; }

[JsonProperty("phone")]
public string Phone { get; set; }

[JsonProperty("id")]
public string Id { get; set; }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,5 +380,10 @@ public virtual Task<List<LinkedAccount>> GetLinkedAccounts()
throw new InvalidOperationException("GetLinkedAccounts is not supported for private key wallets.");
}

public Task<List<LinkedAccount>> UnlinkAccount(LinkedAccount accountToUnlink)
{
throw new InvalidOperationException("UnlinkAccount is not supported for private key wallets.");
}

#endregion
}
10 changes: 10 additions & 0 deletions Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,16 @@ public Task Disconnect()
return Task.CompletedTask;
}

public async Task<List<LinkedAccount>> UnlinkAccount(LinkedAccount accountToUnlink)
{
var personalWallet = await this.GetPersonalWallet().ConfigureAwait(false);
if (personalWallet is not InAppWallet and not EcosystemWallet)
{
throw new Exception("SmartWallet.UnlinkAccount is only supported if the signer is an InAppWallet or EcosystemWallet");
}
return await personalWallet.UnlinkAccount(accountToUnlink).ConfigureAwait(false);
}

public async Task<List<LinkedAccount>> LinkAccount(
IThirdwebWallet walletToLink,
string otp = null,
Expand Down

0 comments on commit b0631e7

Please sign in to comment.