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

Thirdweb Pay #31

Merged
merged 8 commits into from
Jun 13, 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
8 changes: 8 additions & 0 deletions Thirdweb.Tests/Thirdweb.Utils.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,4 +386,12 @@ public void GenerateSIWE_ThrowsOnNullIssuedAt()
};
_ = Assert.Throws<ArgumentNullException>(() => Utils.GenerateSIWE(loginPayloadData));
}

[Fact]
public void ToChecksumAddress_ReturnsCorrectValue()
{
var address = "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed".ToLower();
var checksumAddress = Utils.ToChecksumAddress(address);
Assert.Equal("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", checksumAddress);
}
}
17 changes: 17 additions & 0 deletions Thirdweb/Thirdweb.Pay/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Thirdweb.Pay
{
public static class Constants
{
public const string THIRDWEB_PAY_BASE_URL = "https://pay.thirdweb.com";

public const string THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/quote/v1";
public const string THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/status/v1";

public const string THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/quote/v1";
public const string THIRDWEB_PAY_FIAT_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/status/v1";

public const string THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/currency/v1";

public const string THIRDWEB_PAY_HISTORY_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/wallet/history/v1";
}
}
38 changes: 38 additions & 0 deletions Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Numerics;
using System.Threading.Tasks;
using Nethereum.Hex.HexTypes;

namespace Thirdweb.Pay
{
public partial class ThirdwebPay
{
public static async Task<string> BuyWithCrypto(ThirdwebClient client, IThirdwebWallet wallet, BuyWithCryptoQuoteResult buyWithCryptoQuote)
{
if (buyWithCryptoQuote.Approval != null)
{
var erc20ToApprove = await ThirdwebContract.Create(client, buyWithCryptoQuote.Approval.TokenAddress, buyWithCryptoQuote.Approval.ChainId);
var currentAllowance = await erc20ToApprove.ERC20_Allowance(await wallet.GetAddress(), buyWithCryptoQuote.Approval.SpenderAddress);
if (currentAllowance < BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei))
{
_ = await erc20ToApprove.ERC20_Approve(wallet, buyWithCryptoQuote.Approval.SpenderAddress, BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei));
}
}

var txInput = new ThirdwebTransactionInput()
{
From = buyWithCryptoQuote.TransactionRequest.From,
To = buyWithCryptoQuote.TransactionRequest.To,
Data = buyWithCryptoQuote.TransactionRequest.Data,
Value = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.Value)),
Gas = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasLimit)),
GasPrice = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasPrice)),
};

var tx = await ThirdwebTransaction.Create(client, wallet, txInput, buyWithCryptoQuote.TransactionRequest.ChainId);

var hash = await ThirdwebTransaction.Send(tx);

return hash;
}
}
}
20 changes: 20 additions & 0 deletions Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Threading.Tasks;

namespace Thirdweb.Pay
{
public partial class ThirdwebPay
{
public static string BuyWithFiat(BuyWithFiatQuoteResult buyWithFiatQuote)
{
if (string.IsNullOrEmpty(buyWithFiatQuote.OnRampLink))
{
throw new ArgumentException("On-ramp link cannot be null or empty.");
}

var onRampLink = buyWithFiatQuote.OnRampLink;

return onRampLink;
}
}
}
56 changes: 56 additions & 0 deletions Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Newtonsoft.Json;

namespace Thirdweb.Pay
{
public partial class ThirdwebPay
{
public static async Task<BuyHistoryResult> GetBuyHistory(ThirdwebClient client, string walletAddress, int start, int count, string cursor = null, int? pageSize = null)
{
var queryString = new Dictionary<string, string>
{
{ "walletAddress", walletAddress },
{ "start", start.ToString() },
{ "count", count.ToString() },
{ "cursor", cursor },
{ "pageSize", pageSize?.ToString() }
};

var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}"));
var url = $"{Constants.THIRDWEB_PAY_HISTORY_ENDPOINT}?{queryStringFormatted}";

var getResponse = await client.HttpClient.GetAsync(url);

var content = await getResponse.Content.ReadAsStringAsync();

if (!getResponse.IsSuccessStatusCode)
{
ErrorResponse error;
try
{
error = JsonConvert.DeserializeObject<ErrorResponse>(content);
}
catch
{
error = new ErrorResponse
{
Error = new ErrorDetails
{
Message = "Unknown error",
Reason = "Unknown",
Code = "Unknown",
Stack = "Unknown",
StatusCode = (int)getResponse.StatusCode
}
};
}

throw new Exception(
$"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"
);
}

var data = JsonConvert.DeserializeObject<BuyHistoryResponse>(content);
return data.Result;
}
}
}
62 changes: 62 additions & 0 deletions Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using Newtonsoft.Json;

namespace Thirdweb.Pay
{
public partial class ThirdwebPay
{
public static async Task<BuyWithCryptoQuoteResult> GetBuyWithCryptoQuote(ThirdwebClient client, BuyWithCryptoQuoteParams buyWithCryptoParams)
{
var queryString = new Dictionary<string, string>
{
{ "fromAddress", buyWithCryptoParams.FromAddress },
{ "fromChainId", buyWithCryptoParams.FromChainId?.ToString() },
{ "fromTokenAddress", buyWithCryptoParams.FromTokenAddress },
{ "fromAmount", buyWithCryptoParams.FromAmount },
{ "fromAmountWei", buyWithCryptoParams.FromAmountWei },
{ "toChainId", buyWithCryptoParams.ToChainId?.ToString() },
{ "toTokenAddress", buyWithCryptoParams.ToTokenAddress },
{ "toAmount", buyWithCryptoParams.ToAmount },
{ "toAmountWei", buyWithCryptoParams.ToAmountWei },
{ "maxSlippageBPS", buyWithCryptoParams.MaxSlippageBPS?.ToString() },
{ "intentId", buyWithCryptoParams.IntentId }
};

var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}"));
var url = $"{Constants.THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT}?{queryStringFormatted}";

var getResponse = await client.HttpClient.GetAsync(url);

var content = await getResponse.Content.ReadAsStringAsync();

if (!getResponse.IsSuccessStatusCode)
{
ErrorResponse error;
try
{
error = JsonConvert.DeserializeObject<ErrorResponse>(content);
}
catch
{
error = new ErrorResponse
{
Error = new ErrorDetails
{
Message = "Unknown error",
Reason = "Unknown",
Code = "Unknown",
Stack = "Unknown",
StatusCode = (int)getResponse.StatusCode
}
};
}

throw new Exception(
$"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"
);
}

var data = JsonConvert.DeserializeObject<GetSwapQuoteResponse>(content);
return data.Result;
}
}
}
54 changes: 54 additions & 0 deletions Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Newtonsoft.Json;

namespace Thirdweb.Pay
{
public partial class ThirdwebPay
{
public static async Task<BuyWithCryptoStatusResult> GetBuyWithCryptoStatus(ThirdwebClient client, string transactionHash)
{
if (string.IsNullOrEmpty(transactionHash))
{
throw new ArgumentException(nameof(transactionHash), "Transaction hash cannot be null or empty.");
}

var queryString = new Dictionary<string, string> { { "transactionHash", transactionHash } };

var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}"));
var url = $"{Constants.THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT}?{queryStringFormatted}";

var getResponse = await client.HttpClient.GetAsync(url);

var content = await getResponse.Content.ReadAsStringAsync();

if (!getResponse.IsSuccessStatusCode)
{
ErrorResponse error;
try
{
error = JsonConvert.DeserializeObject<ErrorResponse>(content);
}
catch
{
error = new ErrorResponse
{
Error = new ErrorDetails
{
Message = "Unknown error",
Reason = "Unknown",
Code = "Unknown",
Stack = "Unknown",
StatusCode = (int)getResponse.StatusCode
}
};
}

throw new Exception(
$"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"
);
}

var data = JsonConvert.DeserializeObject<SwapStatusResponse>(content);
return data.Result;
}
}
}
46 changes: 46 additions & 0 deletions Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Newtonsoft.Json;

namespace Thirdweb.Pay
{
public partial class ThirdwebPay
{
public static async Task<List<string>> GetBuyWithFiatCurrencies(ThirdwebClient client)
{
var url = $"{Constants.THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT}";

var getResponse = await client.HttpClient.GetAsync(url);

var content = await getResponse.Content.ReadAsStringAsync();

if (!getResponse.IsSuccessStatusCode)
{
ErrorResponse error;
try
{
error = JsonConvert.DeserializeObject<ErrorResponse>(content);
}
catch
{
error = new ErrorResponse
{
Error = new ErrorDetails
{
Message = "Unknown error",
Reason = "Unknown",
Code = "Unknown",
Stack = "Unknown",
StatusCode = (int)getResponse.StatusCode
}
};
}

throw new Exception(
$"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"
);
}

var data = JsonConvert.DeserializeObject<FiatCurrenciesResponse>(content);
return data.Result.FiatCurrencies;
}
}
}
61 changes: 61 additions & 0 deletions Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Newtonsoft.Json;

namespace Thirdweb.Pay
{
public partial class ThirdwebPay
{
public static async Task<BuyWithFiatQuoteResult> GetBuyWithFiatQuote(ThirdwebClient client, BuyWithFiatQuoteParams buyWithFiatParams)
{
var queryString = new Dictionary<string, string>
{
{ "fromCurrencySymbol", buyWithFiatParams.FromCurrencySymbol },
{ "fromAmount", buyWithFiatParams.FromAmount },
{ "fromAmountUnits", buyWithFiatParams.FromAmountUnits },
{ "toAddress", buyWithFiatParams.ToAddress },
{ "toChainId", buyWithFiatParams.ToChainId },
{ "toTokenAddress", buyWithFiatParams.ToTokenAddress },
{ "toAmount", buyWithFiatParams.ToAmount },
{ "toAmountWei", buyWithFiatParams.ToAmountWei },
{ "maxSlippageBPS", buyWithFiatParams.MaxSlippageBPS?.ToString() }
};

var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}"));
var url = $"{Constants.THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT}?{queryStringFormatted}";
url += buyWithFiatParams.IsTestMode ? "&isTestMode=true" : "&isTestMode=false";

var getResponse = await client.HttpClient.GetAsync(url);

var content = await getResponse.Content.ReadAsStringAsync();

if (!getResponse.IsSuccessStatusCode)
{
ErrorResponse error;
try
{
error = JsonConvert.DeserializeObject<ErrorResponse>(content);
}
catch
{
error = new ErrorResponse
{
Error = new ErrorDetails
{
Message = "Unknown error",
Reason = "Unknown",
Code = "Unknown",
Stack = "Unknown",
StatusCode = (int)getResponse.StatusCode
}
};
}

throw new Exception(
$"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"
);
}

var data = JsonConvert.DeserializeObject<GetFiatQuoteResponse>(content);
return data.Result;
}
}
}
Loading
Loading