Skip to content

Commit fa9f2fb

Browse files
authored
Wallet API - revoking session keys and getting all active signers (#138)
1 parent 38557b2 commit fa9f2fb

File tree

6 files changed

+58432
-58258
lines changed

6 files changed

+58432
-58258
lines changed

Assets/Thirdweb/Core/Plugin/thirdweb.jslib

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,52 @@ var plugin = {
252252
dynCall_viii(cb, idPtr, null, buffer);
253253
});
254254
},
255+
ThirdwebSmartWalletRevokeSessionKey: async function (taskId, signer, cb) {
256+
// convert taskId from pointer to str and allocate it to keep in memory
257+
var id = UTF8ToString(taskId);
258+
var idSize = lengthBytesUTF8(id) + 1;
259+
var idPtr = _malloc(idSize);
260+
stringToUTF8(id, idPtr, idSize);
261+
// execute bridge call
262+
window.bridge
263+
.smartWalletRevokeSessionKey(UTF8ToString(signer))
264+
.then((returnStr) => {
265+
var bufferSize = lengthBytesUTF8(returnStr) + 1;
266+
var buffer = _malloc(bufferSize);
267+
stringToUTF8(returnStr, buffer, bufferSize);
268+
dynCall_viii(cb, idPtr, buffer, null);
269+
})
270+
.catch((err) => {
271+
var msg = err.message;
272+
var bufferSize = lengthBytesUTF8(msg) + 1;
273+
var buffer = _malloc(bufferSize);
274+
stringToUTF8(msg, buffer, bufferSize);
275+
dynCall_viii(cb, idPtr, null, buffer);
276+
});
277+
},
278+
ThirdwebSmartWalletGetAllActiveSigners: async function (taskId, cb) {
279+
// convert taskId from pointer to str and allocate it to keep in memory
280+
var id = UTF8ToString(taskId);
281+
var idSize = lengthBytesUTF8(id) + 1;
282+
var idPtr = _malloc(idSize);
283+
stringToUTF8(id, idPtr, idSize);
284+
// execute bridge call
285+
window.bridge
286+
.smartWalletGetAllActiveSigners()
287+
.then((returnStr) => {
288+
var bufferSize = lengthBytesUTF8(returnStr) + 1;
289+
var buffer = _malloc(bufferSize);
290+
stringToUTF8(returnStr, buffer, bufferSize);
291+
dynCall_viii(cb, idPtr, buffer, null);
292+
})
293+
.catch((err) => {
294+
var msg = err.message;
295+
var bufferSize = lengthBytesUTF8(msg) + 1;
296+
var buffer = _malloc(bufferSize);
297+
stringToUTF8(msg, buffer, bufferSize);
298+
dynCall_viii(cb, idPtr, null, buffer);
299+
});
300+
},
255301
ThirdwebWaitForTransactionResult: async function (taskId, txHash, cb) {
256302
// convert taskId from pointer to str and allocate it to keep in memory
257303
var id = UTF8ToString(taskId);

Assets/Thirdweb/Core/Scripts/Bridge.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,23 @@ public static async Task<T> SmartWalletCreateSessionKey<T>(string options)
262262
return JsonConvert.DeserializeObject<Result<T>>(result).result;
263263
}
264264

265+
public static async Task<T> SmartWalletRevokeSessionKey<T>(string signer)
266+
{
267+
if (!Utils.IsWebGLBuild())
268+
{
269+
ThirdwebDebug.LogWarning("Interacting with the thirdweb SDK is not fully supported in the editor.");
270+
return default;
271+
}
272+
string taskId = Guid.NewGuid().ToString();
273+
var task = new TaskCompletionSource<string>();
274+
taskMap[taskId] = task;
275+
#if UNITY_WEBGL
276+
ThirdwebSmartWalletRevokeSessionKey(taskId, signer, jsCallback);
277+
#endif
278+
string result = await task.Task;
279+
return JsonConvert.DeserializeObject<Result<T>>(result).result;
280+
}
281+
265282
public static async Task<TransactionReceipt> WaitForTransactionResult(string txHash)
266283
{
267284
if (!Utils.IsWebGLBuild())
@@ -279,6 +296,23 @@ public static async Task<TransactionReceipt> WaitForTransactionResult(string txH
279296
return JsonConvert.DeserializeObject<Result<TransactionReceipt>>(result).result;
280297
}
281298

299+
public static async Task<T> SmartWalletGetAllActiveSigners<T>()
300+
{
301+
if (!Utils.IsWebGLBuild())
302+
{
303+
ThirdwebDebug.LogWarning("Interacting with the thirdweb SDK is not fully supported in the editor.");
304+
return default;
305+
}
306+
string taskId = Guid.NewGuid().ToString();
307+
var task = new TaskCompletionSource<string>();
308+
taskMap[taskId] = task;
309+
#if UNITY_WEBGL
310+
ThirdwebSmartWalletGetAllActiveSigners(taskId, jsCallback);
311+
#endif
312+
string result = await task.Task;
313+
return JsonConvert.DeserializeObject<Result<T>>(result).result;
314+
}
315+
282316
public static async Task<BigInteger> GetLatestBlockNumber()
283317
{
284318
if (!Utils.IsWebGLBuild())
@@ -371,6 +405,10 @@ public static async Task<string> GetEmail()
371405
[DllImport("__Internal")]
372406
private static extern string ThirdwebSmartWalletCreateSessionKey(string taskId, string options, Action<string, string, string> cb);
373407
[DllImport("__Internal")]
408+
private static extern string ThirdwebSmartWalletRevokeSessionKey(string taskId, string signer, Action<string, string, string> cb);
409+
[DllImport("__Internal")]
410+
private static extern string ThirdwebSmartWalletGetAllActiveSigners(string taskId, Action<string, string, string> cb);
411+
[DllImport("__Internal")]
374412
private static extern string ThirdwebWaitForTransactionResult(string taskId, string txHash, Action<string, string, string> cb);
375413
[DllImport("__Internal")]
376414
private static extern string ThirdwebGetLatestBlockNumber(string taskId, Action<string, string, string> cb);

Assets/Thirdweb/Core/Scripts/Types.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,4 +530,35 @@ public override readonly string ToString()
530530
+ $"\n>eventSignature: {eventSignature}";
531531
}
532532
}
533+
534+
[System.Serializable]
535+
public struct SignerWithPermissions
536+
{
537+
public bool? isAdmin;
538+
public string signer;
539+
public SignerPermissions permissions;
540+
541+
public override readonly string ToString()
542+
{
543+
return $"SignerWithPermissions:" + $"\n>isAdmin: {isAdmin}" + $"\n>signer: {signer}" + $"\n>permissions: {permissions}";
544+
}
545+
}
546+
547+
[System.Serializable]
548+
public struct SignerPermissions
549+
{
550+
public string startDate;
551+
public string expirationDate;
552+
public string nativeTokenLimitPerTransaction;
553+
public List<string> approvedCallTargets;
554+
555+
public override readonly string ToString()
556+
{
557+
return $"SignerPermissions:"
558+
+ $"\n>startDate: {startDate}"
559+
+ $"\n>expirationDate: {expirationDate}"
560+
+ $"\n>nativeTokenLimitPerTransaction: {nativeTokenLimitPerTransaction}"
561+
+ $"\n>approvedCallTargets: {approvedCallTargets}";
562+
}
563+
}
533564
}

Assets/Thirdweb/Core/Scripts/Utils.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,5 +457,13 @@ public static bool Supports1559(string chainId)
457457
return true;
458458
}
459459
}
460+
461+
public static string JSDateToUnixTimestamp(string dateString)
462+
{
463+
DateTime dateTime = DateTime.Parse(dateString, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
464+
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
465+
long unixTimestamp = (long)(dateTime - unixEpoch).TotalSeconds;
466+
return unixTimestamp.ToString();
467+
}
460468
}
461469
}

Assets/Thirdweb/Core/Scripts/Wallet.cs

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,6 @@ public async Task<TransactionResult> RemoveAdmin(string admin)
573573
/// <param name="reqValidityStartTimestamp">UNIX timestamp of when the signer's permissions request validity starts.</param>
574574
/// <param name="reqValidityEndTimestamp">UNIX timestamp of when the signer's permissions request validity ends.</param>
575575
/// <returns>The result of the transaction as a TransactionResult object.</returns>
576-
/// <exception cref="UnityException"></exception>
577576
public async Task<TransactionResult> CreateSessionKey(
578577
string signerAddress,
579578
List<string> approvedTargets,
@@ -603,8 +602,6 @@ string reqValidityEndTimestamp
603602
}
604603
else
605604
{
606-
if (ThirdwebManager.Instance.SDK.session.ActiveWallet.GetProvider() != WalletProvider.SmartWallet)
607-
throw new UnityException("This functionality is only available for SmartWallets.");
608605
var smartWallet = ThirdwebManager.Instance.SDK.session.ActiveWallet as Wallets.ThirdwebSmartWallet;
609606
var request = new Contracts.Account.ContractDefinition.SignerPermissionRequest()
610607
{
@@ -623,6 +620,99 @@ string reqValidityEndTimestamp
623620
}
624621
}
625622

623+
/// <summary>
624+
/// Smart Wallet only: Revoke a signer for the connected smart account.
625+
/// </summary>
626+
/// <param name="signerAddress">Address of the signer to revoke.</param>
627+
/// <returns>The result of the transaction as a TransactionResult object.</returns>
628+
public async Task<TransactionResult> RevokeSessionKey(string signerAddress)
629+
{
630+
if (Utils.IsWebGLBuild())
631+
{
632+
return await Bridge.SmartWalletRevokeSessionKey<TransactionResult>(signerAddress);
633+
}
634+
else
635+
{
636+
var smartWallet = ThirdwebManager.Instance.SDK.session.ActiveWallet as Wallets.ThirdwebSmartWallet;
637+
var request = new Contracts.Account.ContractDefinition.SignerPermissionRequest()
638+
{
639+
Signer = signerAddress,
640+
IsAdmin = 0,
641+
ApprovedTargets = new List<string>(),
642+
NativeTokenLimitPerTransaction = 0,
643+
PermissionStartTimestamp = 0,
644+
PermissionEndTimestamp = 0,
645+
ReqValidityStartTimestamp = 0,
646+
ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(),
647+
Uid = Guid.NewGuid().ToByteArray()
648+
};
649+
string signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", await GetChainId(), await GetAddress(), request);
650+
return await smartWallet.SmartWallet.SetPermissionsForSigner(request, signature.HexToByteArray());
651+
}
652+
}
653+
654+
/// <summary>
655+
/// Smart Wallet only: Get all active signers for the connected smart account.
656+
/// </summary>
657+
/// <returns>A list of SignerWithPermissions objects.</returns>
658+
public async Task<List<SignerWithPermissions>> GetAllActiveSigners()
659+
{
660+
if (Utils.IsWebGLBuild())
661+
{
662+
var activeSigners = await Bridge.SmartWalletGetAllActiveSigners<List<SignerWithPermissions>>();
663+
for (int i = 0; i < activeSigners.Count; i++)
664+
{
665+
var signer = activeSigners[i];
666+
signer.permissions.startDate = signer.permissions.startDate == "0" ? "0" : Utils.JSDateToUnixTimestamp(signer.permissions.startDate);
667+
signer.permissions.expirationDate = signer.permissions.expirationDate == "0" ? "0" : Utils.JSDateToUnixTimestamp(signer.permissions.expirationDate);
668+
activeSigners[i] = signer;
669+
}
670+
return activeSigners;
671+
}
672+
else
673+
{
674+
string address = await GetAddress();
675+
var raw = await TransactionManager.ThirdwebRead<Contracts.Account.ContractDefinition.GetAllActiveSignersFunction, Contracts.Account.ContractDefinition.GetAllActiveSignersOutputDTO>(
676+
address,
677+
new Contracts.Account.ContractDefinition.GetAllActiveSignersFunction()
678+
);
679+
var signers = new List<SignerWithPermissions>();
680+
foreach (var rawSigner in raw.Signers)
681+
{
682+
bool? isAdmin;
683+
try
684+
{
685+
isAdmin = (
686+
await TransactionManager.ThirdwebRead<Contracts.Account.ContractDefinition.IsAdminFunction, Contracts.Account.ContractDefinition.IsAdminOutputDTO>(
687+
address,
688+
new Contracts.Account.ContractDefinition.IsAdminFunction() { Account = rawSigner.Signer }
689+
)
690+
).ReturnValue1;
691+
}
692+
catch
693+
{
694+
isAdmin = null;
695+
}
696+
697+
signers.Add(
698+
new SignerWithPermissions()
699+
{
700+
isAdmin = isAdmin,
701+
signer = rawSigner.Signer,
702+
permissions = new SignerPermissions()
703+
{
704+
approvedCallTargets = rawSigner.ApprovedTargets,
705+
nativeTokenLimitPerTransaction = rawSigner.NativeTokenLimitPerTransaction.ToString(),
706+
startDate = rawSigner.StartTimestamp.ToString(),
707+
expirationDate = rawSigner.EndTimestamp.ToString(),
708+
}
709+
}
710+
);
711+
}
712+
return signers;
713+
}
714+
}
715+
626716
/// <summary>
627717
/// Sends a raw transaction from the connected wallet.
628718
/// </summary>

0 commit comments

Comments
 (0)