2022-04-24 05:19:34 +02:00
using System ;
2023-04-26 18:24:46 +09:00
using System.ComponentModel.DataAnnotations ;
2022-04-24 05:19:34 +02:00
using System.Linq ;
using System.Threading.Tasks ;
using BTCPayServer.Abstractions.Constants ;
using BTCPayServer.Abstractions.Extensions ;
using BTCPayServer.Abstractions.Models ;
using BTCPayServer.Client ;
2023-02-21 15:06:34 +09:00
using BTCPayServer.Data ;
2024-05-01 10:22:07 +09:00
using BTCPayServer.Payouts ;
2022-04-24 05:19:34 +02:00
using BTCPayServer.Services.Invoices ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Mvc ;
2024-10-17 15:51:40 +02:00
using Microsoft.Extensions.Localization ;
2022-04-24 05:19:34 +02:00
namespace BTCPayServer.PayoutProcessors.OnChain ;
public class UIOnChainAutomatedPayoutProcessorsController : Controller
{
private readonly EventAggregator _eventAggregator ;
2024-04-04 16:31:04 +09:00
private readonly PaymentMethodHandlerDictionary _handlers ;
2022-04-24 05:19:34 +02:00
private readonly OnChainAutomatedPayoutSenderFactory _onChainAutomatedPayoutSenderFactory ;
private readonly PayoutProcessorService _payoutProcessorService ;
2024-10-17 15:51:40 +02:00
public IStringLocalizer StringLocalizer { get ; }
2022-04-24 05:19:34 +02:00
public UIOnChainAutomatedPayoutProcessorsController (
EventAggregator eventAggregator ,
2024-04-04 16:31:04 +09:00
PaymentMethodHandlerDictionary handlers ,
2022-04-24 05:19:34 +02:00
OnChainAutomatedPayoutSenderFactory onChainAutomatedPayoutSenderFactory ,
2024-11-12 17:57:32 +09:00
IStringLocalizer stringLocalizer ,
2022-04-24 05:19:34 +02:00
PayoutProcessorService payoutProcessorService )
{
_eventAggregator = eventAggregator ;
2024-04-04 16:31:04 +09:00
_handlers = handlers ;
2022-04-24 05:19:34 +02:00
_onChainAutomatedPayoutSenderFactory = onChainAutomatedPayoutSenderFactory ;
_payoutProcessorService = payoutProcessorService ;
2024-11-12 17:57:32 +09:00
StringLocalizer = stringLocalizer ;
2022-04-24 05:19:34 +02:00
}
2024-05-01 10:22:07 +09:00
PayoutMethodId GetPayoutMethod ( string cryptoCode ) = > PayoutTypes . CHAIN . GetPayoutMethodId ( cryptoCode ) ;
2022-04-24 05:19:34 +02:00
[HttpGet("~/stores/{storeId}/payout-processors/onchain-automated/{cryptocode}")]
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
2024-03-14 10:25:40 +01:00
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
2022-04-24 05:19:34 +02:00
public async Task < IActionResult > Configure ( string storeId , string cryptoCode )
{
2024-05-01 10:22:07 +09:00
var id = GetPayoutMethod ( cryptoCode ) ;
if ( ! _onChainAutomatedPayoutSenderFactory . GetSupportedPayoutMethods ( ) . Any ( i = > id = = i ) )
2022-04-24 05:19:34 +02:00
{
2024-10-17 15:51:40 +02:00
TempData . SetStatusMessageModel ( new StatusMessageModel
2022-04-24 05:19:34 +02:00
{
Severity = StatusMessageModel . StatusSeverity . Error ,
2024-10-17 15:51:40 +02:00
Message = StringLocalizer [ "This processor cannot handle {0}." , cryptoCode ] . Value
2022-04-24 05:19:34 +02:00
} ) ;
return RedirectToAction ( "ConfigureStorePayoutProcessors" , "UiPayoutProcessors" ) ;
}
2024-04-04 16:31:04 +09:00
var wallet = HttpContext . GetStoreData ( ) . GetDerivationSchemeSettings ( _handlers , cryptoCode ) ;
2022-04-24 05:19:34 +02:00
if ( wallet ? . IsHotWallet is not true )
{
2024-10-17 15:51:40 +02:00
TempData . SetStatusMessageModel ( new StatusMessageModel
2022-04-24 05:19:34 +02:00
{
Severity = StatusMessageModel . StatusSeverity . Error ,
2024-10-17 15:51:40 +02:00
Message = StringLocalizer [ "Either your {0} wallet is not configured, or it is not a hot wallet. This processor cannot function until a hot wallet is configured in your store." , cryptoCode ] . Value
2022-04-24 05:19:34 +02:00
} ) ;
}
var activeProcessor =
( await _payoutProcessorService . GetProcessors (
new PayoutProcessorService . PayoutProcessorQuery ( )
{
Stores = new [ ] { storeId } ,
2023-01-06 14:18:07 +01:00
Processors = new [ ] { _onChainAutomatedPayoutSenderFactory . Processor } ,
2024-09-26 11:25:45 +09:00
PayoutMethods = new [ ]
2022-04-24 05:19:34 +02:00
{
2024-05-01 10:22:07 +09:00
PayoutTypes . CHAIN . GetPayoutMethodId ( cryptoCode )
2022-04-24 05:19:34 +02:00
}
} ) )
. FirstOrDefault ( ) ;
2023-01-06 14:18:07 +01:00
return View ( new OnChainTransferViewModel ( activeProcessor is null ? new OnChainAutomatedPayoutBlob ( ) : OnChainAutomatedPayoutProcessor . GetBlob ( activeProcessor ) ) ) ;
2022-04-24 05:19:34 +02:00
}
2023-01-06 14:18:07 +01:00
2022-04-24 05:19:34 +02:00
[HttpPost("~/stores/{storeId}/payout-processors/onchain-automated/{cryptocode}")]
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
public async Task < IActionResult > Configure ( string storeId , string cryptoCode , OnChainTransferViewModel automatedTransferBlob )
{
2023-04-26 18:24:46 +09:00
if ( ! ModelState . IsValid )
return View ( automatedTransferBlob ) ;
2024-05-01 10:22:07 +09:00
var id = GetPayoutMethod ( cryptoCode ) ;
if ( ! _onChainAutomatedPayoutSenderFactory . GetSupportedPayoutMethods ( ) . Any ( i = > id = = i ) )
2022-04-24 05:19:34 +02:00
{
2024-10-17 15:51:40 +02:00
TempData . SetStatusMessageModel ( new StatusMessageModel
2022-04-24 05:19:34 +02:00
{
Severity = StatusMessageModel . StatusSeverity . Error ,
2024-10-17 15:51:40 +02:00
Message = StringLocalizer [ "This processor cannot handle {0}." , cryptoCode ] . Value
2022-04-24 05:19:34 +02:00
} ) ;
return RedirectToAction ( "ConfigureStorePayoutProcessors" , "UiPayoutProcessors" ) ;
}
var activeProcessor =
( await _payoutProcessorService . GetProcessors (
new PayoutProcessorService . PayoutProcessorQuery ( )
{
Stores = new [ ] { storeId } ,
2023-01-06 14:18:07 +01:00
Processors = new [ ] { OnChainAutomatedPayoutSenderFactory . ProcessorName } ,
2024-09-26 11:25:45 +09:00
PayoutMethods = new [ ]
2022-04-24 05:19:34 +02:00
{
2024-05-01 10:22:07 +09:00
PayoutTypes . CHAIN . GetPayoutMethodId ( cryptoCode )
2022-04-24 05:19:34 +02:00
}
} ) )
. FirstOrDefault ( ) ;
activeProcessor ? ? = new PayoutProcessorData ( ) ;
2023-02-21 15:06:34 +09:00
activeProcessor . HasTypedBlob < OnChainAutomatedPayoutBlob > ( ) . SetBlob ( automatedTransferBlob . ToBlob ( ) ) ;
2022-04-24 05:19:34 +02:00
activeProcessor . StoreId = storeId ;
2024-09-06 13:24:33 +09:00
activeProcessor . PayoutMethodId = PayoutTypes . CHAIN . GetPayoutMethodId ( cryptoCode ) . ToString ( ) ;
2022-04-24 05:19:34 +02:00
activeProcessor . Processor = _onChainAutomatedPayoutSenderFactory . Processor ;
var tcs = new TaskCompletionSource ( ) ;
_eventAggregator . Publish ( new PayoutProcessorUpdated ( )
{
Data = activeProcessor ,
Id = activeProcessor . Id ,
Processed = tcs
} ) ;
2022-05-02 15:07:48 +02:00
TempData . SetStatusMessageModel ( new StatusMessageModel
2022-04-24 05:19:34 +02:00
{
Severity = StatusMessageModel . StatusSeverity . Success ,
2024-10-17 15:51:40 +02:00
Message = StringLocalizer [ "Processor updated." ] . Value
2022-04-24 05:19:34 +02:00
} ) ;
await tcs . Task ;
2023-01-06 14:18:07 +01:00
return RedirectToAction ( "ConfigureStorePayoutProcessors" , "UiPayoutProcessors" , new { storeId } ) ;
2022-04-24 05:19:34 +02:00
}
public class OnChainTransferViewModel
{
public OnChainTransferViewModel ( )
{
2023-01-06 14:18:07 +01:00
2022-04-24 05:19:34 +02:00
}
2022-08-23 12:35:20 +02:00
public OnChainTransferViewModel ( OnChainAutomatedPayoutBlob blob )
2022-04-24 05:19:34 +02:00
{
2023-07-20 15:05:14 +02:00
ProcessNewPayoutsInstantly = blob . ProcessNewPayoutsInstantly ;
2022-04-24 05:19:34 +02:00
IntervalMinutes = blob . Interval . TotalMinutes ;
2022-08-23 12:35:20 +02:00
FeeTargetBlock = blob . FeeTargetBlock ;
2023-07-20 15:05:14 +02:00
Threshold = blob . Threshold ;
2022-04-24 05:19:34 +02:00
}
2022-08-23 12:35:20 +02:00
2024-10-09 17:44:19 +09:00
[Display(Name = "Process approved payouts instantly")]
2023-07-20 15:05:14 +02:00
public bool ProcessNewPayoutsInstantly { get ; set ; }
2023-04-26 18:24:46 +09:00
[Range(1, 1000)]
2022-08-23 12:35:20 +02:00
public int FeeTargetBlock { get ; set ; }
2023-07-20 15:05:14 +02:00
public decimal Threshold { get ; set ; }
2022-08-23 12:35:20 +02:00
2023-04-26 18:24:46 +09:00
[Range(AutomatedPayoutConstants.MinIntervalMinutes, AutomatedPayoutConstants.MaxIntervalMinutes)]
2022-04-24 05:19:34 +02:00
public double IntervalMinutes { get ; set ; }
2022-08-23 12:35:20 +02:00
public OnChainAutomatedPayoutBlob ToBlob ( )
2022-04-24 05:19:34 +02:00
{
2022-08-23 12:35:20 +02:00
return new OnChainAutomatedPayoutBlob
{
2023-07-20 15:05:14 +02:00
ProcessNewPayoutsInstantly = ProcessNewPayoutsInstantly ,
2022-08-23 12:35:20 +02:00
FeeTargetBlock = FeeTargetBlock ,
2023-07-20 15:05:14 +02:00
Interval = TimeSpan . FromMinutes ( IntervalMinutes ) ,
Threshold = Threshold
2022-08-23 12:35:20 +02:00
} ;
2022-04-24 05:19:34 +02:00
}
}
}