Skip to content

Commit 2a268cd

Browse files
authored
ThirdwebBridge - Onramp Integration & Improved APIs (#148)
1 parent ea4d093 commit 2a268cd

File tree

4 files changed

+543
-166
lines changed

4 files changed

+543
-166
lines changed

Thirdweb.Console/Program.cs

+41-70
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
// originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
5555
// destinationChainId: 324,
5656
// destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
57-
// buyAmountWei: BigInteger.Parse("0.1".ToWei())
57+
// buyAmountWei: BigInteger.Parse("0.01".ToWei())
5858
// );
5959
// Console.WriteLine($"Buy quote: {JsonConvert.SerializeObject(buyQuote, Formatting.Indented)}");
6060

@@ -64,19 +64,19 @@
6464
// originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
6565
// destinationChainId: 324,
6666
// destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
67-
// buyAmountWei: BigInteger.Parse("0.1".ToWei()),
67+
// buyAmountWei: BigInteger.Parse("0.01".ToWei()),
6868
// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"),
6969
// receiver: await myWallet.GetAddress()
7070
// );
71-
// Console.WriteLine($"Prepared Buy contains {preparedBuy.Transactions.Count} transaction(s)!");
71+
// Console.WriteLine($"Prepared Buy contains {preparedBuy.Steps.Count} steps(s) with a total of {preparedBuy.Steps.Sum(step => step.Transactions.Count)} transactions!");
7272

7373
// // Sell - Get a quote for selling a specific amount of tokens
7474
// var sellQuote = await bridge.Sell_Quote(
7575
// originChainId: 324,
7676
// originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
7777
// destinationChainId: 1,
7878
// destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
79-
// sellAmountWei: BigInteger.Parse("0.1".ToWei())
79+
// sellAmountWei: BigInteger.Parse("0.01".ToWei())
8080
// );
8181
// Console.WriteLine($"Sell quote: {JsonConvert.SerializeObject(sellQuote, Formatting.Indented)}");
8282

@@ -86,17 +86,17 @@
8686
// originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
8787
// destinationChainId: 1,
8888
// destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
89-
// sellAmountWei: BigInteger.Parse("0.1".ToWei()),
89+
// sellAmountWei: BigInteger.Parse("0.01".ToWei()),
9090
// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"),
9191
// receiver: await myWallet.GetAddress()
9292
// );
93-
// Console.WriteLine($"Prepared Sell contains {preparedSell.Transactions.Count} transaction(s)!");
93+
// Console.WriteLine($"Prepared Sell contains {preparedBuy.Steps.Count} steps(s) with a total of {preparedBuy.Steps.Sum(step => step.Transactions.Count)} transactions!");
9494

9595
// // Transfer - Get an executable transaction for transferring a specific amount of tokens
9696
// var preparedTransfer = await bridge.Transfer_Prepare(
9797
// chainId: 137,
98-
// tokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync
99-
// transferAmountWei: BigInteger.Parse("0.1".ToWei()),
98+
// tokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // POL on Polygon
99+
// transferAmountWei: BigInteger.Parse("0.01".ToWei()),
100100
// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"),
101101
// receiver: await myWallet.GetAddress()
102102
// );
@@ -128,6 +128,39 @@
128128
// var transferHashes = transferResult.Select(receipt => receipt.TransactionHash).ToList();
129129
// Console.WriteLine($"Transfer hashes: {JsonConvert.SerializeObject(transferHashes, Formatting.Indented)}");
130130

131+
// // Onramp - Get a quote for buying crypto with Fiat
132+
// var preparedOnramp = await bridge.Onramp_Prepare(
133+
// onramp: OnrampProvider.Coinbase,
134+
// chainId: 8453,
135+
// tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
136+
// amount: "10000000",
137+
// receiver: await myWallet.GetAddress()
138+
// );
139+
// Console.WriteLine($"Onramp link: {preparedOnramp.Link}");
140+
// Console.WriteLine($"Full onramp quote and steps data: {JsonConvert.SerializeObject(preparedOnramp, Formatting.Indented)}");
141+
142+
// while (true)
143+
// {
144+
// var onrampStatus = await bridge.Onramp_Status(id: preparedOnramp.Id);
145+
// Console.WriteLine($"Full Onramp Status: {JsonConvert.SerializeObject(onrampStatus, Formatting.Indented)}");
146+
// if (onrampStatus.StatusType is StatusType.COMPLETED or StatusType.FAILED)
147+
// {
148+
// break;
149+
// }
150+
// await ThirdwebTask.Delay(5000);
151+
// }
152+
153+
// if (preparedOnramp.IsSwapRequiredPostOnramp())
154+
// {
155+
// // Execute additional steps that are required post-onramp to get to your token, manually or via the Execute extension
156+
// var receipts = await bridge.Execute(myWallet, preparedOnramp);
157+
// Console.WriteLine($"Onramp receipts: {JsonConvert.SerializeObject(receipts, Formatting.Indented)}");
158+
// }
159+
// else
160+
// {
161+
// Console.WriteLine("No additional steps required post-onramp, you can use the tokens directly!");
162+
// }
163+
131164
#endregion
132165

133166
#region Indexer
@@ -728,68 +761,6 @@
728761

729762
#endregion
730763

731-
#region Buy with Fiat
732-
733-
// // Supported currencies
734-
// var supportedCurrencies = await ThirdwebPay.GetBuyWithFiatCurrencies(client);
735-
// Console.WriteLine($"Supported currencies: {JsonConvert.SerializeObject(supportedCurrencies, Formatting.Indented)}");
736-
737-
// // Get a Buy with Fiat quote
738-
// var fiatQuoteParamsWithProvider = new BuyWithFiatQuoteParams(fromCurrencySymbol: "USD", toAddress: walletAddress, toChainId: "137", toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, toAmount: "20", preferredProvider: "STRIPE");
739-
// var fiatQuoteParams = new BuyWithFiatQuoteParams(fromCurrencySymbol: "USD", toAddress: walletAddress, toChainId: "137", toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, toAmount: "20");
740-
// var fiatOnrampQuote = await ThirdwebPay.GetBuyWithFiatQuote(client, fiatQuoteParams);
741-
// Console.WriteLine($"Fiat onramp quote: {JsonConvert.SerializeObject(fiatOnrampQuote, Formatting.Indented)}");
742-
743-
// // Get a Buy with Fiat link
744-
// var onRampLink = ThirdwebPay.BuyWithFiat(fiatOnrampQuote);
745-
// Console.WriteLine($"Fiat onramp link: {onRampLink}");
746-
747-
// // Open onramp link to start the process (use your framework's version of this)
748-
// var psi = new ProcessStartInfo { FileName = onRampLink, UseShellExecute = true };
749-
// _ = Process.Start(psi);
750-
751-
// // Poll for status
752-
// var currentOnRampStatus = OnRampStatus.NONE;
753-
// while (currentOnRampStatus is not OnRampStatus.ON_RAMP_TRANSFER_COMPLETED and not OnRampStatus.ON_RAMP_TRANSFER_FAILED)
754-
// {
755-
// var onRampStatus = await ThirdwebPay.GetBuyWithFiatStatus(client, fiatOnrampQuote.IntentId);
756-
// currentOnRampStatus = Enum.Parse<OnRampStatus>(onRampStatus.Status);
757-
// Console.WriteLine($"Fiat onramp status: {JsonConvert.SerializeObject(onRampStatus, Formatting.Indented)}");
758-
// await Task.Delay(5000);
759-
// }
760-
761-
#endregion
762-
763-
#region Buy with Crypto
764-
765-
// // Swap Polygon MATIC to Base ETH
766-
// var swapQuoteParams = new BuyWithCryptoQuoteParams(
767-
// fromAddress: walletAddress,
768-
// fromChainId: 137,
769-
// fromTokenAddress: Constants.NATIVE_TOKEN_ADDRESS,
770-
// toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS,
771-
// toChainId: 8453,
772-
// toAmount: "0.1"
773-
// );
774-
// var swapQuote = await ThirdwebPay.GetBuyWithCryptoQuote(client, swapQuoteParams);
775-
// Console.WriteLine($"Swap quote: {JsonConvert.SerializeObject(swapQuote, Formatting.Indented)}");
776-
777-
// // Initiate swap
778-
// var txHash3 = await ThirdwebPay.BuyWithCrypto(wallet: privateKeyWallet, buyWithCryptoQuote: swapQuote);
779-
// Console.WriteLine($"Swap transaction hash: {txHash3}");
780-
781-
// // Poll for status
782-
// var currentSwapStatus = SwapStatus.NONE;
783-
// while (currentSwapStatus is not SwapStatus.COMPLETED and not SwapStatus.FAILED)
784-
// {
785-
// var swapStatus = await ThirdwebPay.GetBuyWithCryptoStatus(client, txHash3);
786-
// currentSwapStatus = Enum.Parse<SwapStatus>(swapStatus.Status);
787-
// Console.WriteLine($"Swap status: {JsonConvert.SerializeObject(swapStatus, Formatting.Indented)}");
788-
// await Task.Delay(5000);
789-
// }
790-
791-
#endregion
792-
793764
#region Storage Actions
794765

795766
// // Will download from IPFS or normal urls

Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs

+44-14
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public static class ThirdwebBridgeExtensions
1616
/// <returns>The transaction receipts as a list of <see cref="ThirdwebTransactionReceipt"/>.</returns>
1717
public static async Task<List<ThirdwebTransactionReceipt>> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, BuyPrepareData preparedBuy, CancellationToken cancellationToken = default)
1818
{
19-
return await ExecuteInternal(bridge, executor, preparedBuy.Transactions, cancellationToken);
19+
return await ExecuteInternal(bridge, executor, preparedBuy.Steps, cancellationToken);
2020
}
2121

2222
/// <summary>
@@ -34,7 +34,7 @@ public static async Task<List<ThirdwebTransactionReceipt>> Execute(
3434
CancellationToken cancellationToken = default
3535
)
3636
{
37-
return await ExecuteInternal(bridge, executor, preparedSell.Transactions, cancellationToken);
37+
return await ExecuteInternal(bridge, executor, preparedSell.Steps, cancellationToken);
3838
}
3939

4040
/// <summary>
@@ -52,23 +52,48 @@ public static Task<List<ThirdwebTransactionReceipt>> Execute(
5252
CancellationToken cancellationToken = default
5353
)
5454
{
55-
return ExecuteInternal(bridge, executor, preparedTransfer.Transactions, cancellationToken);
55+
var steps = new List<Step>() { new() { Transactions = preparedTransfer.Transactions } };
56+
return ExecuteInternal(bridge, executor, steps, cancellationToken);
5657
}
5758

58-
private static async Task<List<ThirdwebTransactionReceipt>> ExecuteInternal(
59-
this ThirdwebBridge bridge,
60-
IThirdwebWallet executor,
61-
List<Transaction> transactions,
62-
CancellationToken cancellationToken = default
63-
)
59+
/// <summary>
60+
/// Executes a set of post-onramp transactions and handles status polling.
61+
/// </summary>
62+
/// <param name="bridge">The Thirdweb bridge.</param>
63+
/// <param name="executor">The executor wallet.</param>
64+
/// <param name="preparedOnRamp">The prepared onramp data.</param>
65+
/// <param name="cancellationToken">The cancellation token.</param>
66+
/// <returns>The transaction receipts as a list of <see cref="ThirdwebTransactionReceipt"/>.</returns>
67+
/// <remarks>Note: This method is used for executing transactions after an onramp process.</remarks>
68+
public static Task<List<ThirdwebTransactionReceipt>> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, OnrampPrepareData preparedOnRamp, CancellationToken cancellationToken = default)
69+
{
70+
return ExecuteInternal(bridge, executor, preparedOnRamp.Steps, cancellationToken);
71+
}
72+
73+
/// <summary>
74+
/// Executes a set of transactions and handles status polling.
75+
/// </summary>
76+
/// /// <param name="bridge">The Thirdweb bridge.</param>
77+
/// <param name="executor">The executor wallet.</param>
78+
/// <param name="steps">The steps containing transactions to execute.</param>
79+
/// <param name="cancellationToken">The cancellation token.</param>
80+
public static Task<List<ThirdwebTransactionReceipt>> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, List<Step> steps, CancellationToken cancellationToken = default)
81+
{
82+
return ExecuteInternal(bridge, executor, steps, cancellationToken);
83+
}
84+
85+
private static async Task<List<ThirdwebTransactionReceipt>> ExecuteInternal(this ThirdwebBridge bridge, IThirdwebWallet executor, List<Step> steps, CancellationToken cancellationToken = default)
6486
{
6587
var receipts = new List<ThirdwebTransactionReceipt>();
66-
foreach (var tx in transactions)
88+
foreach (var step in steps)
6789
{
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);
90+
foreach (var tx in step.Transactions)
91+
{
92+
var thirdwebTx = await tx.ToThirdwebTransaction(executor);
93+
var hash = await ThirdwebTransaction.Send(thirdwebTx);
94+
receipts.Add(await ThirdwebTransaction.WaitForTransactionReceipt(executor.Client, tx.ChainId, hash, cancellationToken));
95+
_ = await bridge.WaitForStatusCompletion(hash, tx.ChainId, cancellationToken);
96+
}
7297
}
7398
return receipts;
7499
}
@@ -117,5 +142,10 @@ public static async Task<StatusData> WaitForStatusCompletion(this ThirdwebBridge
117142
return status;
118143
}
119144

145+
public static bool IsSwapRequiredPostOnramp(this OnrampPrepareData preparedOnramp)
146+
{
147+
return preparedOnramp.Steps == null || preparedOnramp.Steps.Count == 0 || !preparedOnramp.Steps.Any(step => step.Transactions?.Count > 0);
148+
}
149+
120150
#endregion
121151
}

0 commit comments

Comments
 (0)