Skip to content

Commit 4ffdab4

Browse files
authored
[Beta] EIP7702 Unmanaged/Managed Execution for In-App & Ecosystem Wallets, turn your EOAs into Smart EOAs with a simple flag. (#138)
1 parent d77cb75 commit 4ffdab4

File tree

12 files changed

+775
-202
lines changed

12 files changed

+775
-202
lines changed

Thirdweb.Console/Program.cs

+37-101
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Nethereum.ABI;
99
using Nethereum.Hex.HexConvertors.Extensions;
1010
using Nethereum.Hex.HexTypes;
11+
using Nethereum.Util;
1112
using Newtonsoft.Json;
1213
using Newtonsoft.Json.Linq;
1314
using Thirdweb;
@@ -26,10 +27,10 @@
2627
var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY");
2728

2829
// Fetch timeout options are optional, default is 120000ms
29-
var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 120000, rpc: 120000, other: 120000));
30+
var client = ThirdwebClient.Create(secretKey: secretKey);
3031

31-
// Create a private key wallet
32-
var privateKeyWallet = await PrivateKeyWallet.Generate(client: client);
32+
// Create a private key wallet
33+
var privateKeyWallet = await PrivateKeyWallet.Generate(client);
3334

3435
// var walletAddress = await privateKeyWallet.GetAddress();
3536
// Console.WriteLine($"PK Wallet address: {walletAddress}");
@@ -326,113 +327,48 @@
326327

327328
#region EIP-7702
328329

329-
// // --------------------------------------------------------------------------
330-
// // Configuration
331-
// // --------------------------------------------------------------------------
330+
// var chain = 11155111; // sepolia
332331

333-
// var chainWith7702 = 911867;
334-
// var delegationContractAddress = "0xb012446cba783d0f7723daf96cf4c49005022307"; // MinimalAccount
335-
336-
// // Required environment variables
337-
// var backendWalletAddress = Environment.GetEnvironmentVariable("ENGINE_BACKEND_WALLET_ADDRESS") ?? throw new Exception("ENGINE_BACKEND_WALLET_ADDRESS is required");
338-
// var engineUrl = Environment.GetEnvironmentVariable("ENGINE_URL") ?? throw new Exception("ENGINE_URL is required");
339-
// var engineAccessToken = Environment.GetEnvironmentVariable("ENGINE_ACCESS_TOKEN") ?? throw new Exception("ENGINE_ACCESS_TOKEN is required");
340-
341-
// // --------------------------------------------------------------------------
342-
// // Initialize Engine Wallet
343-
// // --------------------------------------------------------------------------
344-
345-
// var engineWallet = await EngineWallet.Create(client, engineUrl, engineAccessToken, backendWalletAddress, 15);
346-
347-
// // --------------------------------------------------------------------------
348-
// // Delegation Contract Implementation
349-
// // --------------------------------------------------------------------------
350-
351-
// var delegationContract = await ThirdwebContract.Create(client, delegationContractAddress, chainWith7702);
352-
353-
// // Initialize a (to-be) 7702 EOA
354-
// var eoaWallet = await PrivateKeyWallet.Generate(client);
355-
// var eoaWalletAddress = await eoaWallet.GetAddress();
356-
// Console.WriteLine($"EOA address: {eoaWalletAddress}");
357-
358-
// // Sign the authorization to point to the delegation contract
359-
// var authorization = await eoaWallet.SignAuthorization(chainWith7702, delegationContractAddress, willSelfExecute: false);
360-
// Console.WriteLine($"Authorization: {JsonConvert.SerializeObject(authorization, Formatting.Indented)}");
361-
362-
// // Sign message for session key
363-
// var sessionKeyParams = new SessionKeyParams_7702()
332+
// // Connect to EOA
333+
// var smartEoa = await InAppWallet.Create(client, authProvider: AuthProvider.Google, executionMode: ExecutionMode.EIP7702Sponsored);
334+
// if (!await smartEoa.IsConnected())
364335
// {
365-
// Signer = backendWalletAddress,
366-
// NativeTokenLimitPerTransaction = 0,
367-
// StartTimestamp = 0,
368-
// EndTimestamp = Utils.GetUnixTimeStampNow() + (3600 * 24),
369-
// ApprovedTargets = new List<string> { Constants.ADDRESS_ZERO },
370-
// Uid = Guid.NewGuid().ToByteArray()
371-
// };
372-
// var sessionKeySig = await EIP712.GenerateSignature_SmartAccount_7702("MinimalAccount", "1", chainWith7702, eoaWalletAddress, sessionKeyParams, eoaWallet);
373-
374-
// // Create call data for the session key
375-
// var sessionKeyCallData = delegationContract.CreateCallData("createSessionKeyWithSig", sessionKeyParams, sessionKeySig.HexToBytes());
376-
377-
// // Execute the delegation & session key creation in one go, from the backend!
378-
// var delegationReceipt = await engineWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, data: sessionKeyCallData, authorization: authorization));
379-
// Console.WriteLine($"Delegation Execution Receipt: {JsonConvert.SerializeObject(delegationReceipt, Formatting.Indented)}");
380-
381-
// // Verify contract code deployed to the EOA
382-
// var rpc = ThirdwebRPC.GetRpcInstance(client, chainWith7702);
383-
// var code = await rpc.SendRequestAsync<string>("eth_getCode", eoaWalletAddress, "latest");
384-
// Console.WriteLine($"EOA code: {code}");
385-
386-
// // The EOA is now a contract
387-
// var eoaContract = await ThirdwebContract.Create(client, eoaWalletAddress, chainWith7702, delegationContract.Abi);
336+
// _ = await smartEoa.LoginWithOauth(
337+
// isMobile: false,
338+
// (url) =>
339+
// {
340+
// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true };
341+
// _ = Process.Start(psi);
342+
// }
343+
// );
344+
// }
345+
// var smartEoaAddress = await smartEoa.GetAddress();
346+
// Console.WriteLine($"User Wallet address: {await smartEoa.GetAddress()}");
388347

389-
// // --------------------------------------------------------------------------
390-
// // Mint Tokens (DropERC20) to the EOA Using the backend session key
391-
// // --------------------------------------------------------------------------
348+
// // Upgrade EOA - This wallet explicitly uses EIP-7702 delegation to the thirdweb MinimalAccount (will delegate upon first tx)
392349

393-
// var erc20ContractAddress = "0xAA462a5BE0fc5214507FDB4fB2474a7d5c69065b"; // DropERC20
394-
// var erc20Contract = await ThirdwebContract.Create(client, erc20ContractAddress, chainWith7702);
350+
// // Transact, will upgrade EOA
351+
// var receipt = await smartEoa.Transfer(chainId: chain, toAddress: await Utils.GetAddressFromENS(client, "vitalik.eth"), weiAmount: 0);
352+
// Console.WriteLine($"Transfer Receipt: {receipt.TransactionHash}");
395353

396-
// // Log ERC20 balance before mint
397-
// var eoaBalanceBefore = await erc20Contract.ERC20_BalanceOf(eoaWalletAddress);
398-
// Console.WriteLine($"EOA balance before: {eoaBalanceBefore}");
354+
// // Double check that it was upgraded
355+
// var isDelegated = await Utils.IsDelegatedAccount(client, chain, smartEoaAddress);
356+
// Console.WriteLine($"Is delegated: {isDelegated}");
399357

400-
// // Create execution call data (calling 'claim' on the DropERC20)
401-
// var executeCallData = eoaContract.CreateCallData(
402-
// "execute",
403-
// new object[]
358+
// // Create a session key
359+
// var sessionKeyReceipt = await smartEoa.CreateSessionKey(
360+
// chain,
361+
// new SessionSpec()
404362
// {
405-
// new List<Call>
406-
// {
407-
// new()
408-
// {
409-
// Data = erc20Contract
410-
// .CreateCallData(
411-
// "claim",
412-
// new object[]
413-
// {
414-
// eoaWalletAddress, // receiver
415-
// 100, // quantity
416-
// Constants.NATIVE_TOKEN_ADDRESS, // currency
417-
// 0, // pricePerToken
418-
// new object[] { Array.Empty<byte>(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }, // allowlistProof
419-
// Array.Empty<byte>() // data
420-
// }
421-
// )
422-
// .HexToBytes(),
423-
// To = erc20ContractAddress,
424-
// Value = BigInteger.Zero
425-
// }
426-
// }
363+
// Signer = await Utils.GetAddressFromENS(client, "0xfirekeeper.eth"),
364+
// IsWildcard = true,
365+
// ExpiresAt = Utils.GetUnixTimeStampNow() + 86400, // 1 day
366+
// CallPolicies = new List<CallSpec>(),
367+
// TransferPolicies = new List<TransferSpec>(),
368+
// Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes()
427369
// }
428370
// );
429-
430-
// var executeReceipt = await engineWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, data: executeCallData));
431-
// Console.WriteLine($"Execute receipt: {JsonConvert.SerializeObject(executeReceipt, Formatting.Indented)}");
432-
433-
// // Log ERC20 balance after mint
434-
// var eoaBalanceAfter = await erc20Contract.ERC20_BalanceOf(eoaWalletAddress);
435-
// Console.WriteLine($"EOA balance after: {eoaBalanceAfter}");
371+
// Console.WriteLine($"Session key receipt: {sessionKeyReceipt.TransactionHash}");
436372

437373
#endregion
438374

Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs

+23-33
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Thirdweb.Tests.AI;
66

77
public class NebulaTests : BaseTests
88
{
9-
private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238";
9+
// private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238";
1010

1111
private const string NEBULA_TEST_CONTRACT = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8";
1212

@@ -46,16 +46,6 @@ public async Task Chat_Single_ReturnsResponse()
4646
Assert.Contains("CAT", response.Message);
4747
}
4848

49-
[Fact(Timeout = 120000)]
50-
public async Task Chat_Single_NoContext_ReturnsResponse()
51-
{
52-
var nebula = await ThirdwebNebula.Create(this.Client);
53-
var response = await nebula.Chat(message: $"What's the symbol of this contract: {NEBULA_TEST_CONTRACT} (Sepolia)?");
54-
Assert.NotNull(response);
55-
Assert.NotNull(response.Message);
56-
Assert.Contains("CAT", response.Message);
57-
}
58-
5949
[Fact(Timeout = 120000)]
6050
public async Task Chat_UnderstandsWalletContext()
6151
{
@@ -68,26 +58,26 @@ public async Task Chat_UnderstandsWalletContext()
6858
Assert.Contains(expectedAddress, response.Message);
6959
}
7060

71-
[Fact(Timeout = 120000)]
72-
public async Task Execute_ReturnsMessageAndReceipt()
73-
{
74-
var signer = await PrivateKeyWallet.Generate(this.Client);
75-
var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN);
76-
var nebula = await ThirdwebNebula.Create(this.Client);
77-
var response = await nebula.Execute(
78-
new List<NebulaChatMessage>
79-
{
80-
new("What's the address of vitalik.eth", NebulaChatRole.User),
81-
new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant),
82-
new($"Approve 1 USDC (this contract: {NEBULA_TEST_USDC_ADDRESS}) to them", NebulaChatRole.User),
83-
},
84-
wallet: wallet
85-
);
86-
Assert.NotNull(response);
87-
Assert.NotNull(response.Message);
88-
Assert.NotNull(response.TransactionReceipts);
89-
Assert.NotEmpty(response.TransactionReceipts);
90-
Assert.NotNull(response.TransactionReceipts[0].TransactionHash);
91-
Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66);
92-
}
61+
// [Fact(Timeout = 120000)]
62+
// public async Task Execute_ReturnsMessageAndReceipt()
63+
// {
64+
// var signer = await PrivateKeyWallet.Generate(this.Client);
65+
// var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN);
66+
// var nebula = await ThirdwebNebula.Create(this.Client);
67+
// var response = await nebula.Execute(
68+
// new List<NebulaChatMessage>
69+
// {
70+
// new("What's the address of vitalik.eth", NebulaChatRole.User),
71+
// new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant),
72+
// new($"Approve 1 USDC (this contract: {NEBULA_TEST_USDC_ADDRESS}) to them", NebulaChatRole.User),
73+
// },
74+
// wallet: wallet
75+
// );
76+
// Assert.NotNull(response);
77+
// Assert.NotNull(response.Message);
78+
// Assert.NotNull(response.TransactionReceipts);
79+
// Assert.NotEmpty(response.TransactionReceipts);
80+
// Assert.NotNull(response.TransactionReceipts[0].TransactionHash);
81+
// Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66);
82+
// }
9383
}

Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ public EIP7702Authorization(BigInteger chainId, string address, BigInteger nonce
214214
this.ChainId = new HexBigInteger(chainId).HexValue;
215215
this.Address = address;
216216
this.Nonce = new HexBigInteger(nonce).HexValue;
217-
this.YParity = yParity.BytesToHex();
217+
this.YParity = yParity.BytesToHex() == "0x00" ? "0x0" : "0x1";
218218
this.R = r.BytesToHex();
219219
this.S = s.BytesToHex();
220220
}

0 commit comments

Comments
 (0)