mirror of
https://github.com/aljazceru/BTCPayServerPlugins.git
synced 2025-12-17 07:34:24 +01:00
pimp ss and prism plugins
This commit is contained in:
@@ -1,10 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using AuthenticationSchemes = BTCPayServer.Abstractions.Constants.AuthenticationSchemes;
|
||||
|
||||
namespace BTCPayServer.Plugins.SideShift
|
||||
{
|
||||
@@ -15,11 +28,29 @@ namespace BTCPayServer.Plugins.SideShift
|
||||
{
|
||||
private readonly BTCPayServerClient _btcPayServerClient;
|
||||
private readonly SideShiftService _sideShiftService;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IEnumerable<IPayoutHandler> _payoutHandlers;
|
||||
private readonly PullPaymentHostedService _pullPaymentHostedService;
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly BTCPayNetworkJsonSerializerSettings _serializerSettings;
|
||||
private readonly ApplicationDbContextFactory _dbContextFactory;
|
||||
|
||||
public SideShiftController(BTCPayServerClient btcPayServerClient, SideShiftService sideShiftService)
|
||||
public SideShiftController(BTCPayServerClient btcPayServerClient,
|
||||
SideShiftService sideShiftService,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IEnumerable<IPayoutHandler> payoutHandlers,
|
||||
PullPaymentHostedService pullPaymentHostedService,
|
||||
StoreRepository storeRepository,
|
||||
BTCPayNetworkJsonSerializerSettings serializerSettings, ApplicationDbContextFactory dbContextFactory)
|
||||
{
|
||||
_btcPayServerClient = btcPayServerClient;
|
||||
_sideShiftService = sideShiftService;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_payoutHandlers = payoutHandlers;
|
||||
_pullPaymentHostedService = pullPaymentHostedService;
|
||||
_storeRepository = storeRepository;
|
||||
_serializerSettings = serializerSettings;
|
||||
_dbContextFactory = dbContextFactory;
|
||||
}
|
||||
|
||||
[HttpGet("")]
|
||||
@@ -78,5 +109,229 @@ namespace BTCPayServer.Plugins.SideShift
|
||||
return View(vm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpPost("~/plugins/sidehift/{pullPaymentId}/payouts")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> CreatePayout(string pullPaymentId,
|
||||
[FromBody] CreateSideShiftPayoutRequest request)
|
||||
{
|
||||
IPayoutHandler handler = null;
|
||||
if (string.IsNullOrEmpty(request.ShiftCurrency))
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.ShiftCurrency), "ShiftCurrency must be specified");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(request.ShiftNetwork))
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.ShiftNetwork), "ShiftNetwork must be specified");
|
||||
}
|
||||
|
||||
if (request.Amount is null)
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.Amount), "Amount must be specified");
|
||||
}
|
||||
|
||||
if (!PaymentMethodId.TryParse(request.PaymentMethod, out var pmi))
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.PaymentMethod), "Invalid payment method");
|
||||
}
|
||||
else
|
||||
{
|
||||
handler = _payoutHandlers.FindPayoutHandler(pmi);
|
||||
if (handler == null)
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.PaymentMethod), "Invalid payment method");
|
||||
}
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return this.CreateValidationError(ModelState);
|
||||
}
|
||||
|
||||
var pp = await
|
||||
_pullPaymentHostedService.GetPullPayment(pullPaymentId, false);
|
||||
var ppBlob = pp?.GetBlob();
|
||||
if (ppBlob is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var ip = HttpContext.Connection.RemoteIpAddress;
|
||||
|
||||
var client = _httpClientFactory.CreateClient("sideshift");
|
||||
if (ip is not null && !ip.IsLocal())
|
||||
client.DefaultRequestHeaders.Add("x-user-ip", ip.ToString());
|
||||
//
|
||||
// var quoteResponse = await client.PostAsJsonAsync("https://sideshift.ai/api/v2/quotes", new
|
||||
// {
|
||||
// depositCoin = pmi.CryptoCode,
|
||||
// depositNetwork = pmi.PaymentType == LightningPaymentType.Instance ? "lightning" : null,
|
||||
// settleCoin = request.ShiftCurrency,
|
||||
// settleNetwork = request.ShiftNetwork,
|
||||
// depositAmount = request.Amount.ToString(),
|
||||
// affiliateId = "qg0OrfHJV"
|
||||
// }
|
||||
// );
|
||||
// quoteResponse.EnsureSuccessStatusCode();
|
||||
// var quote = await quoteResponse.Content.ReadAsAsync<QuoteResponse>();
|
||||
// var shiftResponse = await client.PostAsJsonAsync("https://sideshift.ai/api/v2/shifts/fixed", new
|
||||
// {
|
||||
// settleAddress = request.Destination,
|
||||
// settleMemo = request.Memo,
|
||||
// quoteId = quote.id,
|
||||
// affiliateId = "qg0OrfHJV"
|
||||
// }
|
||||
// );
|
||||
// shiftResponse.EnsureSuccessStatusCode();
|
||||
// var shift = await shiftResponse.Content.ReadAsAsync<ShiftResponse>();
|
||||
|
||||
var shiftResponse = await client.PostAsJsonAsync("https://sideshift.ai/api/v2/shifts/variable", new
|
||||
{
|
||||
settleAddress = request.Destination,
|
||||
affiliateId = "qg0OrfHJV",
|
||||
settleMemo = request.Memo,
|
||||
depositCoin = pmi.CryptoCode,
|
||||
depositNetwork = pmi.PaymentType == LightningPaymentType.Instance ? "lightning" : null,
|
||||
settleCoin = request.ShiftCurrency,
|
||||
settleNetwork = request.ShiftNetwork,
|
||||
}
|
||||
);
|
||||
if (!shiftResponse.IsSuccessStatusCode)
|
||||
{
|
||||
var error = JObject.Parse(await shiftResponse.Content.ReadAsStringAsync());
|
||||
ModelState.AddModelError("",error["error"]["message"].Value<string>());
|
||||
|
||||
return this.CreateValidationError(ModelState);
|
||||
}
|
||||
var shift = await shiftResponse.Content.ReadAsAsync<ShiftResponse>();
|
||||
|
||||
|
||||
var destination =
|
||||
await handler.ParseAndValidateClaimDestination(pmi, shift.depositAddress, ppBlob,
|
||||
CancellationToken.None);
|
||||
|
||||
var claim = await _pullPaymentHostedService.Claim(new ClaimRequest()
|
||||
{
|
||||
PullPaymentId = pullPaymentId,
|
||||
Destination = destination.destination,
|
||||
PaymentMethodId = pmi,
|
||||
Value = request.Amount
|
||||
});
|
||||
if (claim.Result == ClaimRequest.ClaimResult.Ok)
|
||||
{
|
||||
await using var ctx = _dbContextFactory.CreateContext();
|
||||
ppBlob.Description += $"The payout of {claim.PayoutData.Destination} will be forwarded to SideShift.ai for further conversion. Please go to <a href=\"https://sideshift.ai/orders/{shift.id}\">the order page</a> for support.";
|
||||
pp.SetBlob(ppBlob);
|
||||
ctx.Attach(pp).State = EntityState.Modified;
|
||||
await ctx.SaveChangesAsync();
|
||||
|
||||
}
|
||||
return HandleClaimResult(claim);
|
||||
}
|
||||
|
||||
|
||||
private IActionResult HandleClaimResult(ClaimRequest.ClaimResponse result)
|
||||
{
|
||||
switch (result.Result)
|
||||
{
|
||||
case ClaimRequest.ClaimResult.Ok:
|
||||
break;
|
||||
case ClaimRequest.ClaimResult.Duplicate:
|
||||
return this.CreateAPIError("duplicate-destination", ClaimRequest.GetErrorMessage(result.Result));
|
||||
case ClaimRequest.ClaimResult.Expired:
|
||||
return this.CreateAPIError("expired", ClaimRequest.GetErrorMessage(result.Result));
|
||||
case ClaimRequest.ClaimResult.NotStarted:
|
||||
return this.CreateAPIError("not-started", ClaimRequest.GetErrorMessage(result.Result));
|
||||
case ClaimRequest.ClaimResult.Archived:
|
||||
return this.CreateAPIError("archived", ClaimRequest.GetErrorMessage(result.Result));
|
||||
case ClaimRequest.ClaimResult.Overdraft:
|
||||
return this.CreateAPIError("overdraft", ClaimRequest.GetErrorMessage(result.Result));
|
||||
case ClaimRequest.ClaimResult.AmountTooLow:
|
||||
return this.CreateAPIError("amount-too-low", ClaimRequest.GetErrorMessage(result.Result));
|
||||
case ClaimRequest.ClaimResult.PaymentMethodNotSupported:
|
||||
return this.CreateAPIError("payment-method-not-supported",
|
||||
ClaimRequest.GetErrorMessage(result.Result));
|
||||
default:
|
||||
throw new NotSupportedException("Unsupported ClaimResult");
|
||||
}
|
||||
|
||||
return Ok(ToModel(result.PayoutData));
|
||||
}
|
||||
|
||||
private Client.Models.PayoutData ToModel(Data.PayoutData p)
|
||||
{
|
||||
var blob = p.GetBlob(_serializerSettings);
|
||||
var model = new Client.Models.PayoutData
|
||||
{
|
||||
Id = p.Id,
|
||||
PullPaymentId = p.PullPaymentDataId,
|
||||
Date = p.Date,
|
||||
Amount = blob.Amount,
|
||||
PaymentMethodAmount = blob.CryptoAmount,
|
||||
Revision = blob.Revision,
|
||||
State = p.State,
|
||||
Destination = blob.Destination,
|
||||
PaymentMethod = p.PaymentMethodId,
|
||||
CryptoCode = p.GetPaymentMethodId().CryptoCode,
|
||||
PaymentProof = p.GetProofBlobJson()
|
||||
};
|
||||
return model;
|
||||
}
|
||||
|
||||
public class CreateSideShiftPayoutThroughStoreRequest : CreatePayoutThroughStoreRequest
|
||||
{
|
||||
public string Memo { get; set; }
|
||||
public string ShiftCurrency { get; set; }
|
||||
public string ShiftNetwork { get; set; }
|
||||
}
|
||||
|
||||
public class CreateSideShiftPayoutRequest : CreatePayoutRequest
|
||||
{
|
||||
public string Memo { get; set; }
|
||||
public string ShiftCurrency { get; set; }
|
||||
public string ShiftNetwork { get; set; }
|
||||
}
|
||||
|
||||
public class QuoteResponse
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string createdAt { get; set; }
|
||||
public string depositCoin { get; set; }
|
||||
public string settleCoin { get; set; }
|
||||
public string depositNetwork { get; set; }
|
||||
public string settleNetwork { get; set; }
|
||||
public string expiresAt { get; set; }
|
||||
public string depositAmount { get; set; }
|
||||
public string settleAmount { get; set; }
|
||||
public string rate { get; set; }
|
||||
public string affiliateId { get; set; }
|
||||
}
|
||||
|
||||
public class ShiftResponse
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string createdAt { get; set; }
|
||||
public string depositCoin { get; set; }
|
||||
public string settleCoin { get; set; }
|
||||
public string depositNetwork { get; set; }
|
||||
public string settleNetwork { get; set; }
|
||||
public string depositAddress { get; set; }
|
||||
public string settleAddress { get; set; }
|
||||
public string depositMin { get; set; }
|
||||
public string depositMax { get; set; }
|
||||
public string refundAddress { get; set; }
|
||||
public string type { get; set; }
|
||||
public string quoteId { get; set; }
|
||||
public string depositAmount { get; set; }
|
||||
public string settleAmount { get; set; }
|
||||
public string expiresAt { get; set; }
|
||||
public string status { get; set; }
|
||||
public string updatedAt { get; set; }
|
||||
public string rate { get; set; }
|
||||
public string averageShiftSeconds { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user