Skip to content

Commit 5ee4402

Browse files
authored
[Beta] ThirdwebBridge - Universal Bridge Integration (#142)
1 parent fc2d1a6 commit 5ee4402

File tree

6 files changed

+966
-6
lines changed

6 files changed

+966
-6
lines changed

Thirdweb.Console/Program.cs

+88
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Thirdweb;
1414
using Thirdweb.AccountAbstraction;
1515
using Thirdweb.AI;
16+
using Thirdweb.Bridge;
1617
using Thirdweb.Indexer;
1718
using Thirdweb.Pay;
1819

@@ -41,6 +42,93 @@
4142

4243
#endregion
4344

45+
#region Bridge
46+
47+
// // Create a ThirdwebBridge instance
48+
// var bridge = await ThirdwebBridge.Create(client);
49+
50+
// // Buy - Get a quote for buying a specific amount of tokens
51+
// var buyQuote = await bridge.Buy_Quote(
52+
// originChainId: 1,
53+
// originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
54+
// destinationChainId: 324,
55+
// destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
56+
// buyAmountWei: BigInteger.Parse("0.1".ToWei())
57+
// );
58+
// Console.WriteLine($"Buy quote: {JsonConvert.SerializeObject(buyQuote, Formatting.Indented)}");
59+
60+
// // Buy - Get an executable set of transactions (alongside a quote) for buying a specific amount of tokens
61+
// var preparedBuy = await bridge.Buy_Prepare(
62+
// originChainId: 1,
63+
// originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
64+
// destinationChainId: 324,
65+
// destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
66+
// buyAmountWei: BigInteger.Parse("0.1".ToWei()),
67+
// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"),
68+
// receiver: await myWallet.GetAddress()
69+
// );
70+
// Console.WriteLine($"Prepared Buy contains {preparedBuy.Transactions.Count} transaction(s)!");
71+
72+
// // Sell - Get a quote for selling a specific amount of tokens
73+
// var sellQuote = await bridge.Sell_Quote(
74+
// originChainId: 324,
75+
// originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
76+
// destinationChainId: 1,
77+
// destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
78+
// sellAmountWei: BigInteger.Parse("0.1".ToWei())
79+
// );
80+
// Console.WriteLine($"Sell quote: {JsonConvert.SerializeObject(sellQuote, Formatting.Indented)}");
81+
82+
// // Sell - Get an executable set of transactions (alongside a quote) for selling a specific amount of tokens
83+
// var preparedSell = await bridge.Sell_Prepare(
84+
// originChainId: 324,
85+
// originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
86+
// destinationChainId: 1,
87+
// destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
88+
// sellAmountWei: BigInteger.Parse("0.1".ToWei()),
89+
// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"),
90+
// receiver: await myWallet.GetAddress()
91+
// );
92+
// Console.WriteLine($"Prepared Sell contains {preparedSell.Transactions.Count} transaction(s)!");
93+
94+
// // Transfer - Get an executable transaction for transferring a specific amount of tokens
95+
// var preparedTransfer = await bridge.Transfer_Prepare(
96+
// chainId: 137,
97+
// tokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
98+
// transferAmountWei: BigInteger.Parse("0.1".ToWei()),
99+
// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"),
100+
// receiver: await myWallet.GetAddress()
101+
// );
102+
// Console.WriteLine($"Prepared Transfer: {JsonConvert.SerializeObject(preparedTransfer, Formatting.Indented)}");
103+
104+
// // You may use our extensions to execute yourself...
105+
// var myTx = await preparedTransfer.Transactions[0].ToThirdwebTransaction(myWallet);
106+
// var myHash = await ThirdwebTransaction.Send(myTx);
107+
108+
// // ...and poll for the status...
109+
// var status = await bridge.Status(transactionHash: myHash, chainId: 1);
110+
// var isComplete = status.StatusType == StatusType.COMPLETED;
111+
// Console.WriteLine($"Status: {JsonConvert.SerializeObject(status, Formatting.Indented)}");
112+
113+
// // Or use our Execute extensions directly to handle everything for you!
114+
115+
// // Execute a prepared Buy
116+
// var buyResult = await bridge.Execute(myWallet, preparedBuy);
117+
// var buyHashes = buyResult.Select(receipt => receipt.TransactionHash).ToList();
118+
// Console.WriteLine($"Buy hashes: {JsonConvert.SerializeObject(buyHashes, Formatting.Indented)}");
119+
120+
// // Execute a prepared Sell
121+
// var sellResult = await bridge.Execute(myWallet, preparedSell);
122+
// var sellHashes = sellResult.Select(receipt => receipt.TransactionHash).ToList();
123+
// Console.WriteLine($"Sell hashes: {JsonConvert.SerializeObject(sellHashes, Formatting.Indented)}");
124+
125+
// // Execute a prepared Transfer
126+
// var transferResult = await bridge.Execute(myWallet, preparedTransfer);
127+
// var transferHashes = transferResult.Select(receipt => receipt.TransactionHash).ToList();
128+
// Console.WriteLine($"Transfer hashes: {JsonConvert.SerializeObject(transferHashes, Formatting.Indented)}");
129+
130+
#endregion
131+
44132
#region Indexer
45133

46134
// // Create a ThirdwebInsight instance
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using System.Numerics;
2+
3+
namespace Thirdweb.Bridge;
4+
5+
public static class ThirdwebBridgeExtensions
6+
{
7+
#region Execution
8+
9+
/// <summary>
10+
/// Executes buy transaction(s) and handles status polling.
11+
/// </summary>
12+
/// <param name="bridge">The Thirdweb bridge.</param>
13+
/// <param name="executor">The executor wallet.</param>
14+
/// <param name="preparedBuy">The buy data.</param>
15+
/// <param name="cancellationToken">The cancellation token.</param>
16+
/// <returns>The transaction receipts as a list of <see cref="ThirdwebTransactionReceipt"/>.</returns>
17+
public static async Task<List<ThirdwebTransactionReceipt>> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, BuyPrepareData preparedBuy, CancellationToken cancellationToken = default)
18+
{
19+
return await ExecuteInternal(bridge, executor, preparedBuy.Transactions, cancellationToken);
20+
}
21+
22+
/// <summary>
23+
/// Executes sell transaction(s) and handles status polling.
24+
/// </summary>
25+
/// <param name="bridge">The Thirdweb bridge.</param>
26+
/// <param name="executor">The executor wallet.</param>
27+
/// <param name="preparedSell">The prepared sell data.</param>
28+
/// <param name="cancellationToken">The cancellation token.</param>
29+
/// <returns>The transaction receipts as a list of <see cref="ThirdwebTransactionReceipt"/>.</returns>
30+
public static async Task<List<ThirdwebTransactionReceipt>> Execute(
31+
this ThirdwebBridge bridge,
32+
IThirdwebWallet executor,
33+
SellPrepareData preparedSell,
34+
CancellationToken cancellationToken = default
35+
)
36+
{
37+
return await ExecuteInternal(bridge, executor, preparedSell.Transactions, cancellationToken);
38+
}
39+
40+
/// <summary>
41+
/// Executes a transfer transaction and handles status polling.
42+
/// </summary>
43+
/// <param name="bridge">The Thirdweb bridge.</param>
44+
/// <param name="executor">The executor wallet.</param>
45+
/// <param name="preparedTransfer">The prepared transfer data.</param>
46+
/// <param name="cancellationToken">The cancellation token.</param>
47+
/// <returns>The transaction receipts as a list of <see cref="ThirdwebTransactionReceipt"/>.</returns>
48+
public static Task<List<ThirdwebTransactionReceipt>> Execute(
49+
this ThirdwebBridge bridge,
50+
IThirdwebWallet executor,
51+
TransferPrepareData preparedTransfer,
52+
CancellationToken cancellationToken = default
53+
)
54+
{
55+
return ExecuteInternal(bridge, executor, preparedTransfer.Transactions, cancellationToken);
56+
}
57+
58+
private static async Task<List<ThirdwebTransactionReceipt>> ExecuteInternal(
59+
this ThirdwebBridge bridge,
60+
IThirdwebWallet executor,
61+
List<Transaction> transactions,
62+
CancellationToken cancellationToken = default
63+
)
64+
{
65+
var receipts = new List<ThirdwebTransactionReceipt>();
66+
foreach (var tx in transactions)
67+
{
68+
var thirdwebTx = await tx.ToThirdwebTransaction(executor);
69+
var hash = await ThirdwebTransaction.Send(thirdwebTx);
70+
receipts.Add(await ThirdwebTransaction.WaitForTransactionReceipt(executor.Client, tx.ChainId, hash, cancellationToken));
71+
_ = await bridge.WaitForStatusCompletion(hash, tx.ChainId, cancellationToken);
72+
}
73+
return receipts;
74+
}
75+
76+
#endregion
77+
78+
#region Helpers
79+
80+
public static async Task<ThirdwebTransaction> ToThirdwebTransaction(this Transaction transaction, IThirdwebWallet executor)
81+
{
82+
return await ThirdwebTransaction.Create(
83+
executor,
84+
new ThirdwebTransactionInput(
85+
chainId: transaction.ChainId,
86+
to: transaction.To,
87+
value: BigInteger.Parse(string.IsNullOrEmpty(transaction.Value) ? "0" : transaction.Value),
88+
data: string.IsNullOrEmpty(transaction.Data) ? "0x" : transaction.Data
89+
)
90+
);
91+
}
92+
93+
public static async Task<StatusData> WaitForStatusCompletion(this ThirdwebBridge bridge, string hash, BigInteger chainId, CancellationToken cancellationToken = default)
94+
{
95+
if (string.IsNullOrEmpty(hash))
96+
{
97+
throw new ArgumentNullException(nameof(hash));
98+
}
99+
100+
if (chainId == 0)
101+
{
102+
throw new ArgumentNullException(nameof(chainId));
103+
}
104+
105+
var status = await bridge.Status(hash, chainId);
106+
while (status.StatusType is StatusType.PENDING or StatusType.NOT_FOUND)
107+
{
108+
await ThirdwebTask.Delay(500, cancellationToken);
109+
status = await bridge.Status(hash, chainId);
110+
}
111+
112+
if (status.StatusType is StatusType.FAILED)
113+
{
114+
throw new Exception($"Transaction with hash {hash} failed.");
115+
}
116+
117+
return status;
118+
}
119+
120+
#endregion
121+
}

0 commit comments

Comments
 (0)