Skip to content

Commit

Permalink
Account Unlinking
Browse files Browse the repository at this point in the history
  • Loading branch information
0xFirekeeper committed Dec 17, 2024
1 parent 429187d commit d8d1432
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 3 deletions.
20 changes: 17 additions & 3 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,26 @@
// 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);
// External wallet variant
// var externalWallet = await PrivateKeyWallet.Generate(client: client);
// var externalWalletAddress = await externalWallet.GetAddress();
// var inAppWalletToLink = await InAppWallet.Create(client: client, authProvider: AuthProvider.Siwe, siweSigner: externalWallet);
// _ = await inAppWalletMain.LinkAccount(walletToLink: inAppWalletToLink, chainId: 421614);

// Email variant
// var linkedEmail = "[email protected]";
// var inAppWalletToLink = await InAppWallet.Create(client: client, email: linkedEmail);
// await inAppWalletToLink.SendOTP();
// Console.WriteLine("Enter OTP:");
// var otp = Console.ReadLine();
// _ = await inAppWalletMain.LinkAccount(walletToLink: inAppWalletToLink, otp: otp);

// var linkedAccounts = await inAppWalletMain.GetLinkedAccounts();
// Console.WriteLine($"Linked accounts: {JsonConvert.SerializeObject(linkedAccounts, Formatting.Indented)}");

// var unlinkingResult = await inAppWalletMain.UnlinkAccount(authProviderToUnlink: UnlinkingType.email, email: linkedEmail);
// Console.WriteLine($"Unlinking result: {JsonConvert.SerializeObject(unlinkingResult, Formatting.Indented)}");

#endregion

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

/// <summary>
/// Unlinks an account (auth method) from the current wallet. Must pass corresponding parameter to unlink.
/// </summary>
/// <param name="authProviderToUnlink">The auth provider to unlink.</param>
/// <param name="address">The related wallet address to unlink (if applicable).</param>
/// <param name="email">The related email to unlink (if applicable).</param>
/// <param name="phone">The related phone number to unlink (if applicable).</param>
/// <param name="id">The related user ID to unlink (if applicable).</param>
Task<List<LinkedAccount>> UnlinkAccount(UnlinkingType authProviderToUnlink, string address = null, string email = null, string phone = null, string id = null);

/// <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,44 @@ public string GenerateExternalLoginLink(string redirectUrl)

#region Account Linking

public async Task<List<LinkedAccount>> UnlinkAccount(UnlinkingType authProviderToUnlink, string address = null, string email = null, string phone = null, string id = null)
{
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 linkedType = authProviderToUnlink.ToString();
var linkedDetails = new
{
address,
email,
phone,
id
};

var serverLinkedAccounts = await this.EmbeddedWallet.UnlinkAccountAsync(currentAccountToken, linkedType, linkedDetails).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, string linkedType, object linkedDetails);
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, string linkedType, object linkedDetails)
{
var uri = MakeUri2024("/account/disconnect");
var request = new HttpRequestMessage(HttpMethod.Post, uri)
{
Content = MakeHttpContent(new { type = linkedType, details = linkedDetails })
};
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,11 @@

internal partial class EmbeddedWallet
{
public async Task<List<Server.LinkedAccount>> UnlinkAccountAsync(string currentAccountToken, string linkedType, object linkedDetails)
{
return await this._server.UnlinkAccountAsync(currentAccountToken, linkedType, linkedDetails).ConfigureAwait(false);
}

public async Task<List<Server.LinkedAccount>> LinkAccountAsync(string currentAccountToken, string authTokenToConnect)
{
return await this._server.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false);
Expand Down
22 changes: 22 additions & 0 deletions Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,28 @@ public enum AuthProvider
Steam
}

public enum UnlinkingType
{
apple,
coinbase,
discord,
email,
facebook,
farcaster,
github,
google,
guest,
line,
passkey,
phone,
siwe,
steam,
telegram,
twitch,
x,
wallet
}

/// <summary>
/// Represents a linked account.
/// </summary>
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(UnlinkingType authProviderToUnlink, string address = null, string email = null, string phone = null, string id = null)
{
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(UnlinkingType authProviderToUnlink, string address = null, string email = null, string phone = null, string id = null)
{
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(authProviderToUnlink, address, email, phone, id).ConfigureAwait(false);
}

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

0 comments on commit d8d1432

Please sign in to comment.