Skip to content
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
2 changes: 1 addition & 1 deletion apps/portal/src/app/dotnet/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const walletActions: SidebarLink = (() => {
href: `${parentSlug}/switchnetwork`,
},
{
name: "SignAuthorization (Experimental)",
name: "SignAuthorization",
href: `${parentSlug}/signauthorization`,
},
],
Expand Down
40 changes: 40 additions & 0 deletions apps/portal/src/app/dotnet/universal-bridge/quickstart/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The design is akin to letting us know what your intent is.
- Buy: "I want to buy x USDC on y Chain using z Token"
- Sell: "I want to sell x USDC on y Chain for z Token"
- Transfer: "Just transfer all my money to vitalik"
- Onramp: "I want to buy x USDC on y Chain by paying with card"

We will return the transactions needed to achieve whatever you desire.
You may then handle execution yourself or use our extensions.
Expand Down Expand Up @@ -127,4 +128,43 @@ Console.WriteLine($"Sell hashes: {JsonConvert.SerializeObject(sellHashes, Format
var transferResult = await bridge.Execute(myWallet, preparedTransfer);
var transferHashes = transferResult.Select(receipt => receipt.TransactionHash).ToList();
Console.WriteLine($"Transfer hashes: {JsonConvert.SerializeObject(transferHashes, Formatting.Indented)}");
```

## Onramping with Fiat
The onramp flow will return a link for you to display/open as you please. You may poll the status of that onramp by its ID.
In some cases, you may receive an additional set of onchain steps required to get to your destination token post on-ramp, in such cases, you may use our extension `IsSwapRequiredPostOnramp` to check, and if a swap is indeed required, you may use our `Execute` extensions to execute the transactions, or manually execute them by going through each `Step`.

```csharp
// Onramp - Get a quote for buying crypto with Fiat
var preparedOnramp = await bridge.Onramp_Prepare(
onramp: OnrampProvider.Coinbase,
chainId: 8453,
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
amount: "10000000",
receiver: await myWallet.GetAddress()
);
Console.WriteLine($"Onramp link: {preparedOnramp.Link}");
Console.WriteLine($"Full onramp quote and steps data: {JsonConvert.SerializeObject(preparedOnramp, Formatting.Indented)}");

while (true)
{
var onrampStatus = await bridge.Onramp_Status(id: preparedOnramp.Id);
Console.WriteLine($"Full Onramp Status: {JsonConvert.SerializeObject(onrampStatus, Formatting.Indented)}");
if (onrampStatus.StatusType is StatusType.COMPLETED or StatusType.FAILED)
{
break;
}
await ThirdwebTask.Delay(5000);
}

if (preparedOnramp.IsSwapRequiredPostOnramp())
{
// Execute additional steps that are required post-onramp to get to your token, manually or via the Execute extension
var receipts = await bridge.Execute(myWallet, preparedOnramp);
Console.WriteLine($"Onramp receipts: {JsonConvert.SerializeObject(receipts, Formatting.Indented)}");
}
else
{
Console.WriteLine("No additional steps required post-onramp, you can use the tokens directly!");
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -5,96 +5,37 @@ export const metadata = createMetadata({
description: "Sign an EIP-7702 Payload to Set Code to your EOA.",
});

# [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Integration (Experimental)
# [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Integration (Low-level API)
Integrates `authorizationList` for any transactions.
This EIP essentially allows you to set code to an EOA, unlocking a world of possibilities to enhance their functionality.

The best way to understand it outside of reading the EIP is looking at the example below; to preface it: we sign an authorization using the wallet we want to set code to. Another wallet sends a transaction with said authorization passed in, essentially activating it. The authority wallet now has code set to it pointing to an (insecure) [Delegation](https://thirdweb.com/odyssey-911867/0x654F42b74885EE6803F403f077bc0409f1066c58) contract in this case, which allows any wallet to execute any call through it on behalf of the authority. In this example, we call the wallet executing both the authorization and the claim transaction afterwards, the exectuor.

An authority may execute its own authorization, the only difference is internal whereby the authorization nonce is incremented by 1.

```csharp
// Chain and contract addresses
var chainWith7702 = 911867;
var erc20ContractAddress = "0xAA462a5BE0fc5214507FDB4fB2474a7d5c69065b"; // Fake ERC20
var delegationContractAddress = "0x654F42b74885EE6803F403f077bc0409f1066c58"; // BatchCallDelegation

// Initialize contracts normally
var erc20Contract = await ThirdwebContract.Create(client: client, address: erc20ContractAddress, chain: chainWith7702);
var delegationContract = await ThirdwebContract.Create(client: client, address: delegationContractAddress, chain: chainWith7702);
You almost never need to use this API directly, but it's available for low-level access. Use higher level [Account Abstraction](/dotnet/wallets/providers/account-abstraction) APIs instead.

// Initialize a (to-be) 7702 EOA
var eoaWallet = await PrivateKeyWallet.Generate(client);
var eoaWalletAddress = await eoaWallet.GetAddress();
Console.WriteLine($"EOA address: {eoaWalletAddress}");
## Usage

// Initialize another wallet, the "executor" that will hit the eoa's (to-be) execute function
var executorWallet = await PrivateKeyWallet.Generate(client);
var executorWalletAddress = await executorWallet.GetAddress();
Console.WriteLine($"Executor address: {executorWalletAddress}");
```csharp
var authorization = await eoaWallet.SignAuthorization(chainId: chainWith7702Support, contractAddress: delegationContractAddress, willSelfExecute: false);
```

// Fund the executor wallet
var fundingWallet = await PrivateKeyWallet.Create(client, privateKey);
var fundingHash = (await fundingWallet.Transfer(chainWith7702, executorWalletAddress, BigInteger.Parse("0.001".ToWei()))).TransactionHash;
Console.WriteLine($"Funded Executor Wallet: {fundingHash}");
<Details summary="Parameters">

// Sign the authorization to make it point to the delegation contract
var authorization = await eoaWallet.SignAuthorization(chainId: chainWith7702, contractAddress: delegationContractAddress, willSelfExecute: false);
Console.WriteLine($"Authorization: {JsonConvert.SerializeObject(authorization, Formatting.Indented)}");
### chainId (required)

// Execute the delegation
var tx = await ThirdwebTransaction.Create(executorWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: executorWalletAddress, authorization: authorization));
var hash = (await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx)).TransactionHash;
Console.WriteLine($"Authorization execution transaction hash: {hash}");
Your chain ID as a `BigInteger` value.

// Prove that code has been deployed to the eoa
var rpc = ThirdwebRPC.GetRpcInstance(client, chainWith7702);
var code = await rpc.SendRequestAsync<string>("eth_getCode", eoaWalletAddress, "latest");
Console.WriteLine($"EOA code: {code}");
### contractAddress (required)
The address of the contract you want to authorize. Your EOA will essentially become a smart contract if this authorization is executed.

// Log erc20 balance of executor before the claim
var executorBalanceBefore = await erc20Contract.ERC20_BalanceOf(executorWalletAddress);
Console.WriteLine($"Executor balance before: {executorBalanceBefore}");
### willSelfExecute (required)
Whether the authorization will be executed by the EOA itself or by a third-party. It will affect the nonce of the authorization.

// Prepare the claim call
var claimCallData = erc20Contract.CreateCallData(
"claim",
new object[]
{
executorWalletAddress, // receiver
100, // quantity
Constants.NATIVE_TOKEN_ADDRESS, // currency
0, // pricePerToken
new object[] { Array.Empty<byte>(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }, // allowlistProof
Array.Empty<byte>() // data
}
);
</Details>

// Embed the claim call in the execute call
var executeCallData = delegationContract.CreateCallData(
method: "execute",
parameters: new object[]
{
new List<Thirdweb.Console.Call>
{
new()
{
Data = claimCallData.HexToBytes(),
To = erc20ContractAddress,
Value = BigInteger.Zero
}
}
}
);
<Details summary="Return Value">

// Execute from the executor wallet targeting the eoa which is pointing to the delegation contract
var tx2 = await ThirdwebTransaction.Create(executorWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, data: executeCallData));
var hash2 = (await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx2)).TransactionHash;
Console.WriteLine($"Token claim transaction hash: {hash2}");
### string

// Log erc20 balance of executor after the claim
var executorBalanceAfter = await erc20Contract.ERC20_BalanceOf(executorWalletAddress);
Console.WriteLine($"Executor balance after: {executorBalanceAfter}");
```
The method returns an `EIP7702Authorization` object that can be passed to our `ThirdwebTransaction`/`ThirdwebTransactionInput` related APIs and broadcast as such.

_Note that for the time being this only works on 7702-enabled chains such as [Odyssey](https://thirdweb.com/odyssey-911867) and the feature has only been integrated with `PrivateKeyWallet`._
</Details>
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,49 @@ export const metadata = createMetadata({
"Instantiate a SmartWallet for enhanced user interactions with blockchain applications.",
});

# SmartWallet.Create
# Native Account Abstraction (via EIP-7702 Smart EOAs)

With the recent Ethereum upgrade Pectra, EIP-7702 allows you to upgrade your EOA and get SmartWallet-like functionality with:
- Much cheaper gas costs, batching functionality
- No account separation - your wallet address does not change, not even on zksync chains (once they implement EIP-7702)
- Much faster execution, with the option of paying for gas yourself or having thirdweb manage gas sponsorship, similar to SmartWallet.

The API is also drastically simplified!

### ExecutionMode.EIP7702Sponsored
Upgrade to an EIP7702 smart account, unlocking all functionality of 4337 without the downsides, and thirdweb handles the execution and gas sponsorship for you!
```csharp
var smartEoa = await InAppWallet.Create(
client: thirdwebClient,
authProvider: AuthProvider.Google,
executionMode: ExecutionMode.EIP7702Sponsored
);
```

### ExecutionMode.EIP7702
Upgrade to an EIP7702 smart account, unlocking all functionality of 4337 without the downsides, but sponsoring gas yourself.
```csharp
var smartEoa = await InAppWallet.Create(
client: thirdwebClient,
authProvider: AuthProvider.Google,
executionMode: ExecutionMode.EIP7702
);
```

### ExecutionMode.EOA
"Normal" EOA Execution, no smart account functionality
```csharp
var basicEoa = await InAppWallet.Create(
client: thirdwebClient,
authProvider: AuthProvider.Google,
// does not need to be explicitly passed, is the default but we're showing it here
executionMode: ExecutionMode.EOA
);
```

_When using EIP-7702 execution modes - if not already delegated to a smart account - an EIP-7702 authorization will be signed and bundled with your first transaction, similar to how 4337 works with initcode, but without the large gas costs, slower execution and chain specific requirements._

# SmartWallet (via EIP-4337 Bundlers)

Instantiate a `SmartWallet` to enable advanced blockchain interactions, including gasless transactions through account abstraction. This wallet type is especially useful for creating a user-friendly experience in decentralized applications.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,31 @@ export const metadata = createMetadata({
"Instantiate a SmartWallet to sign transactions and messages.",
});

# SmartWallet
# Native Account Abstraction (via EIP-7702 Smart EOAs)
Native Account Abstraction is a system that allows you to set code to an EOA, unlocking a world of possibilities to enhance their functionality. It is available since the Pectra upgrade on various chains.

Enabling it is as simple as creating an `InAppWallet` and passing the `ExecutionMode.EIP7702Sponsored` flag during creation.

```csharp
// Turn your boring EOAs into Smart EOAs!
var smartIaw = await ConnectWallet(
new WalletOptions(
provider: WalletProvider.InAppWallet,
chainId: 11155111, // Sepolia supports EIP-7702
inAppWalletOptions: new InAppWalletOptions(
authprovider: AuthProvider.Google,
executionMode: ExecutionMode.EIP7702Sponsored // new!
)
)
);
ThirdwebDebug.Log("Connected to InAppWallet: " + await smartIaw.GetAddress());

// Execute a transaction as usual, execution is managed by thirdweb seamlessly!
var receipt = await smartIaw.Transfer(11155111, await smartIaw.GetAddress(), 0);
ThirdwebDebug.Log($"Transfer receipt: https://sepolia.etherscan.io/tx/{receipt.TransactionHash}");
```

# SmartWallet (via EIP-4337 Bundlers)

Instantiate or upgrade any other wallet to a `SmartWallet` to enable advanced blockchain interactions, including gasless transactions through Account Abstraction (ERC4337 as well as ZkSync Native AA).

Expand Down
Loading