Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor everything, simpler api #14

Merged
merged 2 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 41 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,19 @@ dotnet add package Thirdweb
**Simple Example**

```csharp
// Generate a thirdweb client
var client = new ThirdwebClient(clientId: "myClientId", bundleId: "com.my.bundleid");
// A single client fits most use cases
var client = ThirdwebClient.Create(clientId: "myClientId", bundleId: "com.my.bundleid");

// Define a contract
var abi = await ThirdwebContract.FetchAbi("0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", 1); // helper in case you don't have abi on hand
var contract = new ThirdwebContract(client: client, address: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", chain: 1, abi: abi);

// Read from any contract
var readResult = await ThirdwebContract.ReadContract<string>(contract, "name");
// Optionally pass abi, if not passed we fetch it for you
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}");

// Generate a persistent cross platform EOA to act as a signer
var embeddedAccount = new EmbeddedAccount(client: client, email: "[email protected]"); // or email: null, phoneNumber: "+1234567890"
await embeddedAccount.Connect();
// If no previous session exists
// Create a smart account to unlock gasless features, with an embedded account as signer to unlock web2 auth
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);

// Relog if embedded account not logged in
if (!await embeddedAccount.IsConnected())
{
await embeddedAccount.SendOTP();
Expand All @@ -60,18 +58,17 @@ if (!await embeddedAccount.IsConnected())
}
}

// Finally, upgrade that signer to a Smart Account to unlock onchain features such as gasless txs and session keys out of the box
var smartAccount = new SmartAccount(client: client, personalAccount: embeddedAccount, factoryAddress: "mySmartAccountFactory", gasless: true, chainId: 421614);
await smartAccount.Connect();
// Log addresses
Console.WriteLine($"Embedded Account: {await embeddedAccount.GetAddress()}");
Console.WriteLine($"Smart Account: {await smartAccount.GetAddress()}");

// Generate a top level wallet for users (wallets may contain multiple accounts, but don't have to)
var thirdwebWallet = new ThirdwebWallet();
await thirdwebWallet.Initialize(new List<IThirdwebAccount> { smartAccount });
// 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}");

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

```

**Advanced Example**
Expand All @@ -85,32 +82,22 @@ var secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY");
var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY");

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

// 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}");
var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000));

// Interact with a contract
var contract = new ThirdwebContract(client: client, address: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", chain: 1, abi: "MyC#EscapedContractABI");
var readResult = await ThirdwebContract.ReadContract<string>(contract, "name");
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 = new PrivateKeyAccount(client: client, privateKeyHex: privateKey);
var embeddedAccount = new EmbeddedAccount(client: client, email: "firekeeper+7121271d@thirdweb.com"); // or email: null, phoneNumber: "+1234567890"
var smartAccount = new SmartAccount(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614);
var privateKeyAccount = await PrivateKeyAccount.Create(client: client, privateKeyHex: privateKey);
var embeddedAccount = await EmbeddedAccount.Create(client: client, email: "email@email.com"); // or email: null, phoneNumber: "+1234567890"
var smartAccount = await SmartAccount.Create(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614);

// Attempt to connect pk accounts
await privateKeyAccount.Connect();
await embeddedAccount.Connect();

// Reset embedded account (optional step for testing login flow)
if (await embeddedAccount.IsConnected())
{
await embeddedAccount.Disconnect();
}
// // 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())
Expand All @@ -133,7 +120,6 @@ if (!await embeddedAccount.IsConnected())
}

// Connect the smart account with embedded signer and grant a session key to pk account (advanced use case)
await smartAccount.Connect();
_ = await smartAccount.CreateSessionKey(
signerAddress: await privateKeyAccount.GetAddress(),
approvedTargets: new List<string>() { Constants.ADDRESS_ZERO },
Expand All @@ -145,39 +131,32 @@ _ = await smartAccount.CreateSessionKey(
);

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

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

// Initialize wallet (a wallet can hold multiple accounts, but only one can be active at a time)
var thirdwebWallet = new ThirdwebWallet();
await thirdwebWallet.Initialize(new List<IThirdwebAccount> { privateKeyAccount, embeddedAccount, smartAccount });
thirdwebWallet.SetActive(await smartAccount.GetAddress());
Console.WriteLine($"Active account: {await thirdwebWallet.GetAddress()}");

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

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

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

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

// Storage actions
Expand All @@ -189,4 +168,11 @@ Console.WriteLine($"Balance after mint: {balanceAfter}");
// // 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}");
```
62 changes: 23 additions & 39 deletions Thirdweb.Console/Program.cs

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions Thirdweb.Tests/Thirdweb.Client.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ public ClientTests(ITestOutputHelper output)
[Fact]
public void NoSecretKeyNoClientId()
{
Assert.Throws<InvalidOperationException>(() => new ThirdwebClient());
Assert.Throws<InvalidOperationException>(() => ThirdwebClient.Create());
}

[Fact]
public void SecretKeyInitialization()
{
var client = new ThirdwebClient(secretKey: _secretKey);
var client = ThirdwebClient.Create(secretKey: _secretKey);
Assert.NotNull(client.ClientId);
Assert.NotNull(client.SecretKey);
Assert.Null(client.BundleId);
Expand All @@ -26,7 +26,7 @@ public void SecretKeyInitialization()
public void ClientIdInitialization()
{
var clientId = "test-client-id";
var client = new ThirdwebClient(clientId: clientId);
var client = ThirdwebClient.Create(clientId: clientId);
Assert.NotNull(client.ClientId);
Assert.Null(client.SecretKey);
Assert.Null(client.BundleId);
Expand All @@ -37,15 +37,15 @@ public void ClientIdInitialization()
public void BundleIdInitialization()
{
var bundleId = "test-bundle-id";
var exception = Assert.Throws<InvalidOperationException>(() => new ThirdwebClient(bundleId: bundleId));
var exception = Assert.Throws<InvalidOperationException>(() => ThirdwebClient.Create(bundleId: bundleId));
Assert.Equal("ClientId or SecretKey must be provided", exception.Message);
}

[Fact]
public void ClientIdAndSecretKeyInitialization()
{
var clientId = "test-client-id";
var client = new ThirdwebClient(clientId: clientId, secretKey: _secretKey);
var client = ThirdwebClient.Create(clientId: clientId, secretKey: _secretKey);
Assert.NotNull(client.ClientId);
Assert.NotNull(client.SecretKey);
Assert.Null(client.BundleId);
Expand All @@ -59,7 +59,7 @@ public void ClientIdAndBundleIdInitialization()
{
var clientId = "test-client-id";
var bundleId = "test-bundle-id";
var client = new ThirdwebClient(clientId: clientId, bundleId: bundleId);
var client = ThirdwebClient.Create(clientId: clientId, bundleId: bundleId);
Assert.NotNull(client.ClientId);
Assert.NotNull(client.BundleId);
Assert.Null(client.SecretKey);
Expand All @@ -71,7 +71,7 @@ public void ClientIdAndBundleIdInitialization()
public void SecretKeyAndBundleIdInitialization()
{
var bundleId = "test-bundle-id";
var client = new ThirdwebClient(secretKey: _secretKey, bundleId: bundleId);
var client = ThirdwebClient.Create(secretKey: _secretKey, bundleId: bundleId);
Assert.NotNull(client.SecretKey);
Assert.NotNull(client.BundleId);
Assert.NotNull(client.ClientId);
Expand All @@ -83,7 +83,7 @@ public void SecretKeyAndBundleIdInitialization()
[Fact]
public void TimeoutOptions()
{
var client = new ThirdwebClient(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 30000, other: 30000));
var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 30000, other: 30000));
Assert.NotNull(client.FetchTimeoutOptions);
Assert.Equal(30000, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage));
Assert.Equal(30000, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc));
Expand All @@ -94,7 +94,7 @@ public void TimeoutOptions()
[Fact]
public void NoTimeoutOptions()
{
var client = new ThirdwebClient(secretKey: _secretKey);
var client = ThirdwebClient.Create(secretKey: _secretKey);
Assert.NotNull(client.FetchTimeoutOptions);
Assert.Equal(Constants.DEFAULT_FETCH_TIMEOUT, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage));
Assert.Equal(Constants.DEFAULT_FETCH_TIMEOUT, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc));
Expand Down
Loading
Loading