Skip to content

Commit

Permalink
Account -> Wallet + Embedded -> InApp (#15)
Browse files Browse the repository at this point in the history
* Account -> Wallet + Embedded -> InApp

* files
  • Loading branch information
0xFirekeeper authored Apr 10, 2024
1 parent d7bb543 commit 0debbbe
Show file tree
Hide file tree
Showing 33 changed files with 205 additions and 220 deletions.
90 changes: 46 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,42 +34,42 @@ var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23
var readResult = await ThirdwebContract.Read<string>(contract, "name");
Console.WriteLine($"Contract read result: {readResult}");

// Create embedded account as signer to unlock web2 auth
var embeddedAccount = await EmbeddedAccount.Create(client: client, email: "[email protected]"); // or email: null, phoneNumber: "+1234567890"
// Create InAppWallet wallet as signer to unlock web2 auth
var inAppWallet = await InAppWallet.Create(client: client, email: "[email protected]"); // or email: null, phoneNumber: "+1234567890"
// Relog if embedded account not logged in
if (!await embeddedAccount.IsConnected())
// Relog if InAppWallet wallet not logged in
if (!await inAppWallet.IsConnected())
{
await embeddedAccount.SendOTP();
await inAppWallet.SendOTP();
Console.WriteLine("Please submit the OTP.");
var otp = Console.ReadLine();
(var embeddedAccountAddress, var canRetry) = await embeddedAccount.SubmitOTP(otp);
if (embeddedAccountAddress == null && canRetry)
(var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp);
if (inAppWalletAddress == null && canRetry)
{
Console.WriteLine("Please submit the OTP again.");
otp = Console.ReadLine();
(embeddedAccountAddress, _) = await embeddedAccount.SubmitOTP(otp);
(inAppWalletAddress, _) = await inAppWallet.SubmitOTP(otp);
}
if (embeddedAccountAddress == null)
if (inAppWalletAddress == null)
{
Console.WriteLine("OTP login failed. Please try again.");
return;
}
}

// Create a smart account to unlock gasless features, with embedded account as a signer
var smartAccount = await SmartAccount.Create(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614);
// Create a smart wallet to unlock gasless features, with InAppWallet as a signer
var smartWallet = await SmartWallet.Create(client: client, personalWallet: inAppWallet, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614);

// Log addresses
Console.WriteLine($"Embedded Account: {await embeddedAccount.GetAddress()}");
Console.WriteLine($"Smart Account: {await smartAccount.GetAddress()}");
Console.WriteLine($"InAppWallet: {await inAppWallet.GetAddress()}");
Console.WriteLine($"Smart Wallet: {await smartWallet.GetAddress()}");

// Sign, triggering deploy as needed and 1271 verification if it's a smart wallet
var message = "Hello, Thirdweb!";
var signature = await smartAccount.PersonalSign(message);
var signature = await smartWallet.PersonalSign(message);
Console.WriteLine($"Signed message: {signature}");

var writeResult = await ThirdwebContract.Write(smartAccount, contract, "mintTo", 0, await smartAccount.GetAddress(), 100);
var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", 0, await smartWallet.GetAddress(), 100);
Console.WriteLine($"Contract write result: {writeResult}");
```

Expand All @@ -80,7 +80,7 @@ using Thirdweb;

// Do not use secret keys client side, use client id/bundle id instead
var secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY");
// Do not use private keys client side, use embedded/smart accounts instead
// Do not use private keys client side, use InAppWallet/SmartWallet instead
var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY");

// Fetch timeout options are optional, default is 60000ms
Expand All @@ -90,40 +90,42 @@ var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23
var readResult = await ThirdwebContract.Read<string>(contract, "name");
Console.WriteLine($"Contract read result: {readResult}");

// Create accounts (this is an advanced use case, typically one account is plenty)
var privateKeyAccount = await PrivateKeyAccount.Create(client: client, privateKeyHex: privateKey);
var embeddedAccount = await EmbeddedAccount.Create(client: client, email: "[email protected]"); // or email: null, phoneNumber: "+1234567890"
var smartAccount = await SmartAccount.Create(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614);
// Create wallets (this is an advanced use case, typically one wallet is plenty)
var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey);
var inAppWallet = await InAppWallet.Create(client: client, email: "[email protected]"); // or email: null, phoneNumber: "+1234567890"
// // Reset embedded account (optional step for testing login flow)
// if (await embeddedAccount.IsConnected())
// // Reset InAppWallet (optional step for testing login flow)
// if (await inAppWallet.IsConnected())
// {
// await embeddedAccount.Disconnect();
// await inAppWallet.Disconnect();
// }
// Relog if embedded account not logged in
if (!await embeddedAccount.IsConnected())
// Relog if InAppWallet not logged in
if (!await inAppWallet.IsConnected())
{
await embeddedAccount.SendOTP();
await inAppWallet.SendOTP();
Console.WriteLine("Please submit the OTP.");
var otp = Console.ReadLine();
(var embeddedAccountAddress, var canRetry) = await embeddedAccount.SubmitOTP(otp);
if (embeddedAccountAddress == null && canRetry)
(var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp);
if (inAppWalletAddress == null && canRetry)
{
Console.WriteLine("Please submit the OTP again.");
otp = Console.ReadLine();
(embeddedAccountAddress, _) = await embeddedAccount.SubmitOTP(otp);
(inAppWalletAddress, _) = await inAppWallet.SubmitOTP(otp);
}
if (embeddedAccountAddress == null)
if (inAppWalletAddress == null)
{
Console.WriteLine("OTP login failed. Please try again.");
return;
}
}

// Connect the smart account with embedded signer and grant a session key to pk account (advanced use case)
_ = await smartAccount.CreateSessionKey(
signerAddress: await privateKeyAccount.GetAddress(),
// Create smart wallet with InAppWallet signer
var smartWallet = await SmartWallet.Create(client: client, personalWallet: inAppWallet, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614);

// Connect the smart wallet with InAppWallet signer and grant a session key to pk wallet (advanced use case)
_ = await smartWallet.CreateSessionKey(
signerAddress: await privateKeyWallet.GetAddress(),
approvedTargets: new List<string>() { Constants.ADDRESS_ZERO },
nativeTokenLimitPerTransactionInWei: "0",
permissionStartTimestamp: "0",
Expand All @@ -132,33 +134,33 @@ _ = await smartAccount.CreateSessionKey(
reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString()
);

// Reconnect to same smart account with pk account as signer (specifying account address override)
smartAccount = await SmartAccount.Create(
// Reconnect to same smart wallet with pk wallet as signer (specifying wallet address override)
smartWallet = await SmartWallet.Create(
client: client,
personalAccount: privateKeyAccount,
personalWallet: privateKeyWallet,
factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052",
gasless: true,
chainId: 421614,
accountAddressOverride: await smartAccount.GetAddress()
accountAddressOverride: await smartWallet.GetAddress()
);

// Log addresses
Console.WriteLine($"PrivateKey Account: {await privateKeyAccount.GetAddress()}");
Console.WriteLine($"Embedded Account: {await embeddedAccount.GetAddress()}");
Console.WriteLine($"Smart Account: {await smartAccount.GetAddress()}");
Console.WriteLine($"PrivateKey Wallet: {await privateKeyWallet.GetAddress()}");
Console.WriteLine($"InAppWallet: {await inAppWallet.GetAddress()}");
Console.WriteLine($"Smart Wallet: {await smartWallet.GetAddress()}");

// Sign, triggering deploy as needed and 1271 verification if it's a smart wallet
var message = "Hello, Thirdweb!";
var signature = await smartAccount.PersonalSign(message);
var signature = await smartWallet.PersonalSign(message);
Console.WriteLine($"Signed message: {signature}");

var balanceBefore = await ThirdwebContract.Read<BigInteger>(contract, "balanceOf", await smartAccount.GetAddress());
var balanceBefore = await ThirdwebContract.Read<BigInteger>(contract, "balanceOf", await smartWallet.GetAddress());
Console.WriteLine($"Balance before mint: {balanceBefore}");

var writeResult = await ThirdwebContract.Write(smartAccount, contract, "mintTo", 0, await smartAccount.GetAddress(), 100);
var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", 0, await smartWallet.GetAddress(), 100);
Console.WriteLine($"Contract write result: {writeResult}");

var balanceAfter = await ThirdwebContract.Read<BigInteger>(contract, "balanceOf", await smartAccount.GetAddress());
var balanceAfter = await ThirdwebContract.Read<BigInteger>(contract, "balanceOf", await smartWallet.GetAddress());
Console.WriteLine($"Balance after mint: {balanceAfter}");

// Storage actions
Expand Down
207 changes: 101 additions & 106 deletions Thirdweb.Console/Program.cs
Original file line number Diff line number Diff line change
@@ -1,113 +1,108 @@
using System.Numerics;
using dotenv.net;
using Thirdweb;
using dotenv.net;

DotEnv.Load();

// Do not use secret keys client side, use client id/bundle id instead
var secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY");

// Do not use private keys client side, use InAppWallet/SmartWallet instead
var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY");

// Fetch timeout options are optional, default is 60000ms
var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000));

internal class Program
var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614);
var readResult = await ThirdwebContract.Read<string>(contract, "name");
Console.WriteLine($"Contract read result: {readResult}");

// Create wallets (this is an advanced use case, typically one wallet is plenty)
var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey);
var inAppWallet = await InAppWallet.Create(client: client, email: "[email protected]"); // or email: null, phoneNumber: "+1234567890"

// // Reset InAppWallet (optional step for testing login flow)
// if (await inAppWallet.IsConnected())
// {
// await inAppWallet.Disconnect();
// }

// Relog if InAppWallet not logged in
if (!await inAppWallet.IsConnected())
{
private static async Task Main(string[] args)
await inAppWallet.SendOTP();
Console.WriteLine("Please submit the OTP.");
var otp = Console.ReadLine();
(var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp);
if (inAppWalletAddress == null && canRetry)
{
DotEnv.Load();

// Do not use secret keys client side, use client id/bundle id instead
var secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY");
// Do not use private keys client side, use embedded/smart accounts instead
var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY");

// Fetch timeout options are optional, default is 60000ms
var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000));

var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614);
var readResult = await ThirdwebContract.Read<string>(contract, "name");
Console.WriteLine($"Contract read result: {readResult}");

// Create accounts (this is an advanced use case, typically one account is plenty)
var privateKeyAccount = await PrivateKeyAccount.Create(client: client, privateKeyHex: privateKey);
var embeddedAccount = await EmbeddedAccount.Create(client: client, email: "[email protected]"); // or email: null, phoneNumber: "+1234567890"

// // Reset embedded account (optional step for testing login flow)
// if (await embeddedAccount.IsConnected())
// {
// await embeddedAccount.Disconnect();
// }

// Relog if embedded account not logged in
if (!await embeddedAccount.IsConnected())
{
await embeddedAccount.SendOTP();
Console.WriteLine("Please submit the OTP.");
var otp = Console.ReadLine();
(var embeddedAccountAddress, var canRetry) = await embeddedAccount.SubmitOTP(otp);
if (embeddedAccountAddress == null && canRetry)
{
Console.WriteLine("Please submit the OTP again.");
otp = Console.ReadLine();
(embeddedAccountAddress, _) = await embeddedAccount.SubmitOTP(otp);
}
if (embeddedAccountAddress == null)
{
Console.WriteLine("OTP login failed. Please try again.");
return;
}
}

// Create smart account with embedded signer
var smartAccount = await SmartAccount.Create(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614);

// Connect the smart account with embedded signer and grant a session key to pk account (advanced use case)
_ = await smartAccount.CreateSessionKey(
signerAddress: await privateKeyAccount.GetAddress(),
approvedTargets: new List<string>() { Constants.ADDRESS_ZERO },
nativeTokenLimitPerTransactionInWei: "0",
permissionStartTimestamp: "0",
permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(),
reqValidityStartTimestamp: "0",
reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString()
);

// Reconnect to same smart account with pk account as signer (specifying account address override)
smartAccount = await SmartAccount.Create(
client: client,
personalAccount: privateKeyAccount,
factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052",
gasless: true,
chainId: 421614,
accountAddressOverride: await smartAccount.GetAddress()
);

// Log addresses
Console.WriteLine($"PrivateKey Account: {await privateKeyAccount.GetAddress()}");
Console.WriteLine($"Embedded Account: {await embeddedAccount.GetAddress()}");
Console.WriteLine($"Smart Account: {await smartAccount.GetAddress()}");

// Sign, triggering deploy as needed and 1271 verification if it's a smart wallet
var message = "Hello, Thirdweb!";
var signature = await smartAccount.PersonalSign(message);
Console.WriteLine($"Signed message: {signature}");

var balanceBefore = await ThirdwebContract.Read<BigInteger>(contract, "balanceOf", await smartAccount.GetAddress());
Console.WriteLine($"Balance before mint: {balanceBefore}");

var writeResult = await ThirdwebContract.Write(smartAccount, contract, "mintTo", 0, await smartAccount.GetAddress(), 100);
Console.WriteLine($"Contract write result: {writeResult}");

var balanceAfter = await ThirdwebContract.Read<BigInteger>(contract, "balanceOf", await smartAccount.GetAddress());
Console.WriteLine($"Balance after mint: {balanceAfter}");

// Storage actions

// // Will download from IPFS or normal urls
// var downloadResult = await ThirdwebStorage.Download<string>(client: client, uri: "AnyUrlIncludingIpfs");
// Console.WriteLine($"Download result: {downloadResult}");

// // Will upload to IPFS
// var uploadResult = await ThirdwebStorage.Upload(client: client, path: "AnyPath");
// Console.WriteLine($"Upload result preview: {uploadResult.PreviewUrl}");


// Access RPC directly if needed, generally not recommended

// var rpc = ThirdwebRPC.GetRpcInstance(client, 421614);
// var blockNumber = await rpc.SendRequestAsync<string>("eth_blockNumber");
// Console.WriteLine($"Block number: {blockNumber}");
Console.WriteLine("Please submit the OTP again.");
otp = Console.ReadLine();
(inAppWalletAddress, _) = await inAppWallet.SubmitOTP(otp);
}
if (inAppWalletAddress == null)
{
Console.WriteLine("OTP login failed. Please try again.");
return;
}
}

// Create smart wallet with InAppWallet signer
var smartWallet = await SmartWallet.Create(client: client, personalWallet: inAppWallet, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614);

// Grant a session key to pk wallet (advanced use case)
_ = await smartWallet.CreateSessionKey(
signerAddress: await privateKeyWallet.GetAddress(),
approvedTargets: new List<string>() { Constants.ADDRESS_ZERO },
nativeTokenLimitPerTransactionInWei: "0",
permissionStartTimestamp: "0",
permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(),
reqValidityStartTimestamp: "0",
reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString()
);

// Reconnect to same smart wallet with pk wallet as signer (specifying wallet address override)
smartWallet = await SmartWallet.Create(
client: client,
personalWallet: privateKeyWallet,
factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052",
gasless: true,
chainId: 421614,
accountAddressOverride: await smartWallet.GetAddress()
);

// Log addresses
Console.WriteLine($"PrivateKey Wallet: {await privateKeyWallet.GetAddress()}");
Console.WriteLine($"InAppWallet: {await inAppWallet.GetAddress()}");
Console.WriteLine($"Smart Wallet: {await smartWallet.GetAddress()}");

// Sign, triggering deploy as needed and 1271 verification if it's a smart wallet
var message = "Hello, Thirdweb!";
var signature = await smartWallet.PersonalSign(message);
Console.WriteLine($"Signed message: {signature}");

var balanceBefore = await ThirdwebContract.Read<BigInteger>(contract, "balanceOf", await smartWallet.GetAddress());
Console.WriteLine($"Balance before mint: {balanceBefore}");

var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", 0, await smartWallet.GetAddress(), 100);
Console.WriteLine($"Contract write result: {writeResult}");

var balanceAfter = await ThirdwebContract.Read<BigInteger>(contract, "balanceOf", await smartWallet.GetAddress());
Console.WriteLine($"Balance after mint: {balanceAfter}");

// Storage actions

// // Will download from IPFS or normal urls
// var downloadResult = await ThirdwebStorage.Download<string>(client: client, uri: "AnyUrlIncludingIpfs");
// Console.WriteLine($"Download result: {downloadResult}");

// // Will upload to IPFS
// var uploadResult = await ThirdwebStorage.Upload(client: client, path: "AnyPath");
// Console.WriteLine($"Upload result preview: {uploadResult.PreviewUrl}");


// Access RPC directly if needed, generally not recommended

// var rpc = ThirdwebRPC.GetRpcInstance(client, 421614);
// var blockNumber = await rpc.SendRequestAsync<string>("eth_blockNumber");
// Console.WriteLine($"Block number: {blockNumber}");
Loading

0 comments on commit 0debbbe

Please sign in to comment.