From a32ef1a05559b2922d814a9947daf399423bc359 Mon Sep 17 00:00:00 2001 From: cnohall Date: Mon, 2 Sep 2024 16:59:12 +0900 Subject: [PATCH 01/59] Init --- app/Models/CompanyGateway.php | 1 + app/Models/Gateway.php | 12 +- app/Models/PaymentType.php | 2 + app/Models/SystemLog.php | 4 +- .../Blockonomics/Blockonomics.php | 149 +++++++++++++++ .../BlockonomicsPaymentDriver.php | 174 ++++++++++++++++++ ...2024_08_27_230111_blockonomics_gateway.php | 47 +++++ database/seeders/PaymentLibrariesSeeder.php | 3 +- 8 files changed, 387 insertions(+), 5 deletions(-) create mode 100644 app/PaymentDrivers/Blockonomics/Blockonomics.php create mode 100644 app/PaymentDrivers/BlockonomicsPaymentDriver.php create mode 100644 database/migrations/2024_08_27_230111_blockonomics_gateway.php diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index ce561f31bf0c..e98e7f274d72 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -156,6 +156,7 @@ class CompanyGateway extends BaseModel '80af24a6a691230bbec33e930ab40666' => 323, 'vpyfbmdrkqcicpkjqdusgjfluebftuva' => 324, //BTPay '91be24c7b792230bced33e930ac61676' => 325, + 'wbhf02us6owgo7p4nfjd0ymssdshks4d' => 326, //Blockonomics ]; protected $touches = []; diff --git a/app/Models/Gateway.php b/app/Models/Gateway.php index 43bbfe8fa719..70fff30a46ad 100644 --- a/app/Models/Gateway.php +++ b/app/Models/Gateway.php @@ -107,7 +107,9 @@ class Gateway extends StaticModel $link = 'https://docs.btcpayserver.org/InvoiceNinja/'; } elseif ($this->id == 63) { $link = 'https://rotessa.com'; - } + } elseif ($this->id == 64) { + $link = 'https://blockonomics.co'; + } return $link; } @@ -226,8 +228,8 @@ class Gateway extends StaticModel return [ GatewayType::CRYPTO => ['refund' => true, 'token_billing' => false, 'webhooks' => ['confirmed', 'paid_out', 'failed', 'fulfilled']], ]; //BTCPay - case 63: - return [ + case 63: + return [ GatewayType::BANK_TRANSFER => [ 'refund' => false, 'token_billing' => true, @@ -235,6 +237,10 @@ class Gateway extends StaticModel ], GatewayType::ACSS => ['refund' => false, 'token_billing' => true, 'webhooks' => []] ]; // Rotessa + case 64: + return [ + GatewayType::CRYPTO => ['refund' => true, 'token_billing' => false, 'webhooks' => ['confirmed', 'paid_out', 'failed', 'fulfilled']], + ]; //Blockonomics default: return []; } diff --git a/app/Models/PaymentType.php b/app/Models/PaymentType.php index 9565c8cd9494..db772ccb8f93 100644 --- a/app/Models/PaymentType.php +++ b/app/Models/PaymentType.php @@ -81,6 +81,7 @@ class PaymentType extends StaticModel public const STRIPE_BANK_TRANSFER = 50; public const CASH_APP = 51; public const PAY_LATER = 52; + public const BLOCKONOMICS = 64; public array $type_names = [ self::BANK_TRANSFER => 'payment_type_Bank Transfer', @@ -129,6 +130,7 @@ class PaymentType extends StaticModel self::CASH_APP => 'payment_type_Cash App', self::VENMO => 'payment_type_Venmo', self::PAY_LATER => 'payment_type_Pay Later', + self::BLOCKONOMICS => 'payment_type_Blockonomics', ]; public static function parseCardType($cardName) diff --git a/app/Models/SystemLog.php b/app/Models/SystemLog.php index 10eb1f2629a8..5f826985af84 100644 --- a/app/Models/SystemLog.php +++ b/app/Models/SystemLog.php @@ -153,7 +153,9 @@ class SystemLog extends Model public const TYPE_BTC_PAY = 324; public const TYPE_ROTESSA = 325; - + + public const TYPE_BLOCKONOMICS = 326; + public const TYPE_QUOTA_EXCEEDED = 400; public const TYPE_UPSTREAM_FAILURE = 401; diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php new file mode 100644 index 000000000000..37e1ef050c16 --- /dev/null +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -0,0 +1,149 @@ +driver_class = $driver_class; + $this->driver_class->init(); + } + + public function paymentView($data) + { + $data['gateway'] = $this->driver_class; + $data['amount'] = $data['total']['amount_with_fee']; + $data['currency'] = $this->driver_class->client->getCurrencyCode(); + + return render('gateways.blockonomics.pay', $data); + } + + public function paymentResponse(PaymentResponseRequest $request) + { + + $request->validate([ + 'payment_hash' => ['required'], + 'amount' => ['required'], + 'currency' => ['required'], + ]); + + $drv = $this->driver_class; + if ( + strlen($drv->blockonomics_url) < 1 + || strlen($drv->api_key) < 1 + || strlen($drv->store_id) < 1 + || strlen($drv->webhook_secret) < 1 + ) { + throw new PaymentFailed('Blockonomics is not well configured'); + } + if (!filter_var($this->driver_class->blockonomics_url, FILTER_VALIDATE_URL)) { + throw new PaymentFailed('Wrong format for Blockonomics Url'); + } + + try { + $_invoice = collect($drv->payment_hash->data->invoices)->first(); + $cli = $drv->client; + + $metaData = [ + 'buyerName' => $cli->name, + 'buyerAddress1' => $cli->address1, + 'buyerAddress2' => $cli->address2, + 'buyerCity' => $cli->city, + 'buyerState' => $cli->state, + 'buyerZip' => $cli->postal_code, + 'buyerCountry' => $cli->country_id, + 'buyerPhone' => $cli->phone, + 'itemDesc' => "From InvoiceNinja", + 'InvoiceNinjaPaymentHash' => $drv->payment_hash->hash + ]; + + + $urlRedirect = redirect()->route('client.invoice.show', ['invoice' => $_invoice->invoice_id])->getTargetUrl(); + + $rep = $client->createInvoice( + $drv->store_id, + $request->currency, + $_invoice->invoice_number, + $cli->present()->email(), + $metaData, + $checkoutOptions + ); + + return redirect($rep->getCheckoutLink()); + } catch (\Throwable $e) { + PaymentFailureMailer::dispatch($drv->client, $drv->payment_hash->data, $drv->client->company, $request->amount); + throw new PaymentFailed('Error during Blockonomics payment : ' . $e->getMessage()); + } + } + + public function refund(Payment $payment, $amount) + { + try { + if ($amount == $payment->amount) { + $refundVariant = "Fiat"; + $refundPaymentMethod = "BTC"; + $refundDescription = "Full refund"; + $refundCustomCurrency = null; + $refundCustomAmount = null; + } else { + $refundVariant = "Custom"; + $refundPaymentMethod = ""; + $refundDescription = "Partial refund"; + $refundCustomCurrency = $payment->currency; + $refundCustomAmount = $amount; + } + App::setLocale($payment->company->getLocale()); + + $email_object = new EmailObject(); + $email_object->subject = ctrans('texts.blockonomics_refund_subject'); + $email_object->body = ctrans('texts.blockonomics_refund_body') . '
' . $refund->getViewLink(); + $email_object->text_body = ctrans('texts.blockonomics_refund_body') . '\n' . $refund->getViewLink(); + $email_object->company_key = $payment->company->company_key; + $email_object->html_template = 'email.template.generic'; + $email_object->to = [new Address($payment->client->present()->email(), $payment->client->present()->name())]; + $email_object->email_template_body = 'blockonomics_refund_subject'; + $email_object->email_template_subject = 'blockonomics_refund_body'; + + Email::dispatch($email_object, $payment->company); + + $data = [ + 'transaction_reference' => $refund->getId(), + 'transaction_response' => json_encode($refund), + 'success' => true, + 'description' => "Please follow this link to claim your refund: " . $refund->getViewLink(), + 'code' => 202, + ]; + + return $data; + } catch (\Throwable $e) { + throw new PaymentFailed('Error during Blockonomics refund : ' . $e->getMessage()); + } + } +} diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php new file mode 100644 index 000000000000..170d0c134998 --- /dev/null +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -0,0 +1,174 @@ + Blockonomics::class, //maps GatewayType => Implementation class + ]; + + public const SYSTEM_LOG_TYPE = SystemLog::TYPE_CHECKOUT; //define a constant for your gateway ie TYPE_YOUR_CUSTOM_GATEWAY - set the const in the SystemLog model + + public $blockonomics_url = ""; + public $api_key = ""; + public $store_id = ""; + public $webhook_secret = ""; + public $blockonomics; + + + public function init() + { + $this->blockonomics_url = $this->company_gateway->getConfigField('blockonomicsUrl'); + $this->api_key = $this->company_gateway->getConfigField('apiKey'); + $this->store_id = $this->company_gateway->getConfigField('storeId'); + $this->webhook_secret = $this->company_gateway->getConfigField('webhookSecret'); + return $this; /* This is where you boot the gateway with your auth credentials*/ + } + + /* Returns an array of gateway types for the payment gateway */ + public function gatewayTypes(): array + { + $types = []; + + $types[] = GatewayType::CRYPTO; + + return $types; + } + + public function setPaymentMethod($payment_method_id) + { + $class = self::$methods[$payment_method_id]; + $this->payment_method = new $class($this); + return $this; + } + + public function processPaymentView(array $data) + { + return $this->payment_method->paymentView($data); //this is your custom implementation from here + } + + public function processPaymentResponse($request) + { + return $this->payment_method->paymentResponse($request); + } + + public function processWebhookRequest() + { + $webhook_payload = file_get_contents('php://input'); + + /** @var \stdClass $blockonomicsRep */ + $blockonomicsRep = json_decode($webhook_payload); + if ($blockonomicsRep == null) { + throw new PaymentFailed('Empty data'); + } + if (true === empty($blockonomicsRep->invoiceId)) { + throw new PaymentFailed( + 'Invalid payment notification- did not receive invoice ID.' + ); + } + if ( + str_starts_with($blockonomicsRep->invoiceId, "__test__") + || $blockonomicsRep->type == "InvoiceProcessing" + || $blockonomicsRep->type == "InvoiceCreated" + ) { + return; + } + + $sig = ''; + $headers = getallheaders(); + foreach ($headers as $key => $value) { + if (strtolower($key) === 'blockonomics-sig') { + $sig = $value; + } + } + + $this->init(); + $webhookClient = new Webhook($this->blockonomics_url, $this->api_key); + + if (!$webhookClient->isIncomingWebhookRequestValid($webhook_payload, $sig, $this->webhook_secret)) { + throw new \RuntimeException( + 'Invalid payment notification message received - signature did not match.' + ); + } + + $this->setPaymentMethod(GatewayType::CRYPTO); + $this->payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$blockonomicsRep->metadata->InvoiceNinjaPaymentHash])->firstOrFail(); + $StatusId = Payment::STATUS_PENDING; + if ($this->payment_hash->payment_id == null) { + + $_invoice = Invoice::with('client')->withTrashed()->find($this->payment_hash->fee_invoice_id); + + $this->client = $_invoice->client; + + $dataPayment = [ + 'payment_method' => $this->payment_method, + 'payment_type' => PaymentType::CRYPTO, + 'amount' => $_invoice->amount, + 'gateway_type_id' => GatewayType::CRYPTO, + 'transaction_reference' => $blockonomicsRep->invoiceId + ]; + $payment = $this->createPayment($dataPayment, $StatusId); + } else { + /** @var \App\Models\Payment $payment */ + $payment = Payment::withTrashed()->find($this->payment_hash->payment_id); + $StatusId = $payment->status_id; + } + switch ($blockonomicsRep->type) { + case "InvoiceExpired": + $StatusId = Payment::STATUS_CANCELLED; + break; + case "InvoiceInvalid": + $StatusId = Payment::STATUS_FAILED; + break; + case "InvoiceSettled": + $StatusId = Payment::STATUS_COMPLETED; + break; + } + if ($payment->status_id != $StatusId) { + $payment->status_id = $StatusId; + $payment->save(); + } + } + + + public function refund(Payment $payment, $amount, $return_client_response = false) + { + $this->setPaymentMethod(GatewayType::CRYPTO); + return $this->payment_method->refund($payment, $amount); //this is your custom implementation from here + } +} diff --git a/database/migrations/2024_08_27_230111_blockonomics_gateway.php b/database/migrations/2024_08_27_230111_blockonomics_gateway.php new file mode 100644 index 000000000000..dcca0eeaffb6 --- /dev/null +++ b/database/migrations/2024_08_27_230111_blockonomics_gateway.php @@ -0,0 +1,47 @@ +blockonomicsUrl = ""; + $fields->apiKey = ""; + $fields->storeId = ""; + $fields->webhookSecret = ""; + + $gateway = new Gateway; + $gateway->id = 64; + $gateway->name = 'Blockonomics'; + $gateway->key = 'wbhf02us6owgo7p4nfjd0ymssdshks4d'; + $gateway->provider = 'Blockonomics'; + $gateway->is_offsite = true; + $gateway->fields = \json_encode($fields); + + + $gateway->visible = 1; + $gateway->site_url = 'https://blockonomics.co'; + $gateway->default_gateway_type_id = GatewayType::CRYPTO; + $gateway->save(); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; \ No newline at end of file diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index d85f47b782b3..fb61aebdd175 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -89,6 +89,7 @@ class PaymentLibrariesSeeder extends Seeder ['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'], ['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], ['id' => 63, 'name' => 'Rotessa', 'is_offsite' => false, 'sort_order' => 22, 'provider' => 'Rotessa', 'key' => '91be24c7b792230bced33e930ac61676', 'fields' => '{"apiKey":"", "testMode":""}'], + ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => '{"blockonomicsUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], ]; foreach ($gateways as $gateway) { @@ -105,7 +106,7 @@ class PaymentLibrariesSeeder extends Seeder Gateway::query()->update(['visible' => 0]); - Gateway::whereIn('id', [1, 3, 7, 11, 15, 20, 39, 46, 55, 50, 57, 52, 58, 59, 60, 62, 63])->update(['visible' => 1]); + Gateway::whereIn('id', [1, 3, 7, 11, 15, 20, 39, 46, 55, 50, 57, 52, 58, 59, 60, 62, 63, 64])->update(['visible' => 1]); if (Ninja::isHosted()) { Gateway::whereIn('id', [20, 49])->update(['visible' => 0]); From 7d29463833c3a111735a4dd8feb4310e813a2834 Mon Sep 17 00:00:00 2001 From: cnohall Date: Mon, 2 Sep 2024 17:24:29 +0900 Subject: [PATCH 02/59] add back functions --- app/PaymentDrivers/Blockonomics/Blockonomics.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 37e1ef050c16..7f67d7925ce7 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -36,6 +36,17 @@ class Blockonomics implements MethodInterface $this->driver_class->init(); } + public function authorizeView($data) + { + } + + public function authorizeRequest($request) + { + } + public function authorizeResponse($request) + { + } + public function paymentView($data) { $data['gateway'] = $this->driver_class; From f26b38d09d875b518bed618a370ccec656164b5e Mon Sep 17 00:00:00 2001 From: cnohall Date: Tue, 3 Sep 2024 10:04:27 +0900 Subject: [PATCH 03/59] adapt needed vars to be in line with what's needed for blockonomics --- .../Blockonomics/Blockonomics.php | 8 +---- .../BlockonomicsPaymentDriver.php | 32 +++++++++++++------ ...2024_08_27_230111_blockonomics_gateway.php | 4 +-- database/seeders/PaymentLibrariesSeeder.php | 2 +- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 7f67d7925ce7..9b6f5e282661 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -67,16 +67,10 @@ class Blockonomics implements MethodInterface $drv = $this->driver_class; if ( - strlen($drv->blockonomics_url) < 1 - || strlen($drv->api_key) < 1 - || strlen($drv->store_id) < 1 - || strlen($drv->webhook_secret) < 1 + strlen($drv->api_key) < 1 ) { throw new PaymentFailed('Blockonomics is not well configured'); } - if (!filter_var($this->driver_class->blockonomics_url, FILTER_VALIDATE_URL)) { - throw new PaymentFailed('Wrong format for Blockonomics Url'); - } try { $_invoice = collect($drv->payment_hash->data->invoices)->first(); diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index 170d0c134998..1660c56d0b28 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -28,7 +28,7 @@ class BlockonomicsPaymentDriver extends BaseDriver { use MakesHash; - public $refundable = true; //does this gateway support refunds? + public $refundable = false; //does this gateway support refunds? public $token_billing = false; //does this gateway support token billing? @@ -44,19 +44,31 @@ class BlockonomicsPaymentDriver extends BaseDriver public const SYSTEM_LOG_TYPE = SystemLog::TYPE_CHECKOUT; //define a constant for your gateway ie TYPE_YOUR_CUSTOM_GATEWAY - set the const in the SystemLog model - public $blockonomics_url = ""; - public $api_key = ""; - public $store_id = ""; - public $webhook_secret = ""; + public const api_key = ""; public $blockonomics; + public $BASE_URL = 'https://www.blockonomics.co'; + public $NEW_ADDRESS_URL = 'https://www.blockonomics.co/api/new_address'; + public $PRICE_URL = 'https://www.blockonomics.co/api/price'; + public $SET_CALLBACK_URL = 'https://www.blockonomics.co/api/update_callback'; + public $GET_CALLBACKS_URL = 'https://www.blockonomics.co/api/address?&no_balance=true&only_xpub=true&get_callback=true'; + public function get_callbacks($crypto) + { + $response = $this->get($GET_CALLBACKS_URL, $this->api_key); + return $response; + } + + public function get_callbackSecret() + { + return md5(uniqid(rand(), true)); + } + public function init() { - $this->blockonomics_url = $this->company_gateway->getConfigField('blockonomicsUrl'); + $response = $this->get_callbacks(); $this->api_key = $this->company_gateway->getConfigField('apiKey'); - $this->store_id = $this->company_gateway->getConfigField('storeId'); - $this->webhook_secret = $this->company_gateway->getConfigField('webhookSecret'); + $this->callback_url = $this->company_gateway->getConfigField('callbackUrl'); return $this; /* This is where you boot the gateway with your auth credentials*/ } @@ -118,11 +130,11 @@ class BlockonomicsPaymentDriver extends BaseDriver } $this->init(); - $webhookClient = new Webhook($this->blockonomics_url, $this->api_key); + $webhookClient = new Webhook($this->btcpay_url, $this->api_key); if (!$webhookClient->isIncomingWebhookRequestValid($webhook_payload, $sig, $this->webhook_secret)) { throw new \RuntimeException( - 'Invalid payment notification message received - signature did not match.' + 'Invalid BTCPayServer payment notification message received - signature did not match.' ); } diff --git a/database/migrations/2024_08_27_230111_blockonomics_gateway.php b/database/migrations/2024_08_27_230111_blockonomics_gateway.php index dcca0eeaffb6..0688903b8cdb 100644 --- a/database/migrations/2024_08_27_230111_blockonomics_gateway.php +++ b/database/migrations/2024_08_27_230111_blockonomics_gateway.php @@ -16,10 +16,8 @@ return new class extends Migration { $fields = new \stdClass; - $fields->blockonomicsUrl = ""; $fields->apiKey = ""; - $fields->storeId = ""; - $fields->webhookSecret = ""; + $fields->callbackUrl = ""; $gateway = new Gateway; $gateway->id = 64; diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index fb61aebdd175..0311a586a434 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -89,7 +89,7 @@ class PaymentLibrariesSeeder extends Seeder ['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'], ['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], ['id' => 63, 'name' => 'Rotessa', 'is_offsite' => false, 'sort_order' => 22, 'provider' => 'Rotessa', 'key' => '91be24c7b792230bced33e930ac61676', 'fields' => '{"apiKey":"", "testMode":""}'], - ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => '{"blockonomicsUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], + ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => '{"apiKey":"", "callbackUrl":""}'], ]; foreach ($gateways as $gateway) { From 5c1450861ae711cbf9b4cbbb5b3a11ea6257277a Mon Sep 17 00:00:00 2001 From: cnohall Date: Tue, 3 Sep 2024 10:26:32 +0900 Subject: [PATCH 04/59] add pay.blade.php for blockonomics --- .../gateways/blockonomics/pay.blade.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php new file mode 100644 index 000000000000..a53ac383fb09 --- /dev/null +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -0,0 +1,28 @@ +@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_Crypto'), 'card_title' => ctrans('texts.payment_type_Crypto')]) + +@section('gateway_content') + + + @include('portal.ninja2020.gateways.includes.payment_details') + +
+ @csrf + + + + + + + +
+ + @include('portal.ninja2020.gateways.includes.pay_now') +@endsection + +@push('footer') + +@endpush From bb088af766a1d4fb3e8c39017f2f4a3771fddb8a Mon Sep 17 00:00:00 2001 From: cnohall Date: Tue, 3 Sep 2024 10:42:44 +0900 Subject: [PATCH 05/59] remove unneeded param --- app/PaymentDrivers/BlockonomicsPaymentDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index 1660c56d0b28..cd4e86088508 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -53,7 +53,7 @@ class BlockonomicsPaymentDriver extends BaseDriver public $GET_CALLBACKS_URL = 'https://www.blockonomics.co/api/address?&no_balance=true&only_xpub=true&get_callback=true'; - public function get_callbacks($crypto) + public function get_callbacks() { $response = $this->get($GET_CALLBACKS_URL, $this->api_key); return $response; From eb46de98f1e95311b813b8acd7239a0de5fbea3c Mon Sep 17 00:00:00 2001 From: cnohall Date: Tue, 3 Sep 2024 11:30:10 +0900 Subject: [PATCH 06/59] update paymentdriver --- .../BlockonomicsPaymentDriver.php | 61 +++++++++++++------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index cd4e86088508..211ac2174b06 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -44,34 +44,61 @@ class BlockonomicsPaymentDriver extends BaseDriver public const SYSTEM_LOG_TYPE = SystemLog::TYPE_CHECKOUT; //define a constant for your gateway ie TYPE_YOUR_CUSTOM_GATEWAY - set the const in the SystemLog model - public const api_key = ""; public $blockonomics; public $BASE_URL = 'https://www.blockonomics.co'; public $NEW_ADDRESS_URL = 'https://www.blockonomics.co/api/new_address'; public $PRICE_URL = 'https://www.blockonomics.co/api/price'; public $SET_CALLBACK_URL = 'https://www.blockonomics.co/api/update_callback'; - public $GET_CALLBACKS_URL = 'https://www.blockonomics.co/api/address?&no_balance=true&only_xpub=true&get_callback=true'; - - - public function get_callbacks() - { - $response = $this->get($GET_CALLBACKS_URL, $this->api_key); - return $response; - } - - public function get_callbackSecret() - { - return md5(uniqid(rand(), true)); - } public function init() { - $response = $this->get_callbacks(); $this->api_key = $this->company_gateway->getConfigField('apiKey'); - $this->callback_url = $this->company_gateway->getConfigField('callbackUrl'); + $response = $this->get_callbacks($this->api_key); + $this->callback_url = $response; return $this; /* This is where you boot the gateway with your auth credentials*/ } + private function get($url, $apiKey) + { + // Initialize cURL session + $ch = curl_init(); + + // Set cURL options + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $apiKey, + 'Content-Type: application/json' + ]); + + // Execute cURL session and get the response + $response = curl_exec($ch); + + // Check for errors + if (curl_errno($ch)) { + throw new Exception(curl_error($ch)); + } + + // Close cURL session + curl_close($ch); + + // Return the response + return json_decode($response, true); + } + + public function get_callbacks($api_key) + { + $GET_CALLBACKS_URL = 'https://www.blockonomics.co/api/address?&no_balance=true&only_xpub=true&get_callback=true'; + $response = $this->get($GET_CALLBACKS_URL, $api_key); + return $response; + } + + // public function get_callbackSecret() + // { + // return md5(uniqid(rand(), true)); + // } + + /* Returns an array of gateway types for the payment gateway */ public function gatewayTypes(): array { @@ -130,7 +157,7 @@ class BlockonomicsPaymentDriver extends BaseDriver } $this->init(); - $webhookClient = new Webhook($this->btcpay_url, $this->api_key); + $webhookClient = new Webhook($this->callback_url , $this->api_key); if (!$webhookClient->isIncomingWebhookRequestValid($webhook_payload, $sig, $this->webhook_secret)) { throw new \RuntimeException( From bf9f8eb47e3e8f8a007443768596b6103c1abaa1 Mon Sep 17 00:00:00 2001 From: cnohall Date: Tue, 3 Sep 2024 19:48:59 +0900 Subject: [PATCH 07/59] update variables and simplify Blockonomics paymentdriver --- .../Blockonomics/Blockonomics.php | 55 ++----------------- ...2024_08_27_230111_blockonomics_gateway.php | 1 + database/seeders/PaymentLibrariesSeeder.php | 2 +- 3 files changed, 8 insertions(+), 50 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 9b6f5e282661..f4be7c5ae891 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -73,6 +73,11 @@ class Blockonomics implements MethodInterface } try { + // This is where the payment happens + // Will probably have to implement a curl request to the blockonomics API + // to create a new payment request + // Or potentially use an off-site solution + $_invoice = collect($drv->payment_hash->data->invoices)->first(); $cli = $drv->client; @@ -92,63 +97,15 @@ class Blockonomics implements MethodInterface $urlRedirect = redirect()->route('client.invoice.show', ['invoice' => $_invoice->invoice_id])->getTargetUrl(); - $rep = $client->createInvoice( - $drv->store_id, - $request->currency, - $_invoice->invoice_number, - $cli->present()->email(), - $metaData, - $checkoutOptions - ); - - return redirect($rep->getCheckoutLink()); } catch (\Throwable $e) { PaymentFailureMailer::dispatch($drv->client, $drv->payment_hash->data, $drv->client->company, $request->amount); throw new PaymentFailed('Error during Blockonomics payment : ' . $e->getMessage()); } } + // Not supported yet public function refund(Payment $payment, $amount) { - try { - if ($amount == $payment->amount) { - $refundVariant = "Fiat"; - $refundPaymentMethod = "BTC"; - $refundDescription = "Full refund"; - $refundCustomCurrency = null; - $refundCustomAmount = null; - } else { - $refundVariant = "Custom"; - $refundPaymentMethod = ""; - $refundDescription = "Partial refund"; - $refundCustomCurrency = $payment->currency; - $refundCustomAmount = $amount; - } - App::setLocale($payment->company->getLocale()); - $email_object = new EmailObject(); - $email_object->subject = ctrans('texts.blockonomics_refund_subject'); - $email_object->body = ctrans('texts.blockonomics_refund_body') . '
' . $refund->getViewLink(); - $email_object->text_body = ctrans('texts.blockonomics_refund_body') . '\n' . $refund->getViewLink(); - $email_object->company_key = $payment->company->company_key; - $email_object->html_template = 'email.template.generic'; - $email_object->to = [new Address($payment->client->present()->email(), $payment->client->present()->name())]; - $email_object->email_template_body = 'blockonomics_refund_subject'; - $email_object->email_template_subject = 'blockonomics_refund_body'; - - Email::dispatch($email_object, $payment->company); - - $data = [ - 'transaction_reference' => $refund->getId(), - 'transaction_response' => json_encode($refund), - 'success' => true, - 'description' => "Please follow this link to claim your refund: " . $refund->getViewLink(), - 'code' => 202, - ]; - - return $data; - } catch (\Throwable $e) { - throw new PaymentFailed('Error during Blockonomics refund : ' . $e->getMessage()); - } } } diff --git a/database/migrations/2024_08_27_230111_blockonomics_gateway.php b/database/migrations/2024_08_27_230111_blockonomics_gateway.php index 0688903b8cdb..3ad54dea306d 100644 --- a/database/migrations/2024_08_27_230111_blockonomics_gateway.php +++ b/database/migrations/2024_08_27_230111_blockonomics_gateway.php @@ -18,6 +18,7 @@ return new class extends Migration $fields = new \stdClass; $fields->apiKey = ""; $fields->callbackUrl = ""; + $fields->callbackSecret = md5(uniqid(rand(), true)); $gateway = new Gateway; $gateway->id = 64; diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index 0311a586a434..7a196039f20d 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -89,7 +89,7 @@ class PaymentLibrariesSeeder extends Seeder ['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'], ['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], ['id' => 63, 'name' => 'Rotessa', 'is_offsite' => false, 'sort_order' => 22, 'provider' => 'Rotessa', 'key' => '91be24c7b792230bced33e930ac61676', 'fields' => '{"apiKey":"", "testMode":""}'], - ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => '{"apiKey":"", "callbackUrl":""}'], + ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => '{"apiKey":"", "callbackUrl":"", "callbackSecret": ""}'], ]; foreach ($gateways as $gateway) { From c7d7e465821a42336b462c942e625897af4af6ae Mon Sep 17 00:00:00 2001 From: cnohall Date: Wed, 4 Sep 2024 09:44:41 +0900 Subject: [PATCH 08/59] test setting callbackUrl in migration --- .../migrations/2024_08_27_230111_blockonomics_gateway.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/database/migrations/2024_08_27_230111_blockonomics_gateway.php b/database/migrations/2024_08_27_230111_blockonomics_gateway.php index 3ad54dea306d..caa226950624 100644 --- a/database/migrations/2024_08_27_230111_blockonomics_gateway.php +++ b/database/migrations/2024_08_27_230111_blockonomics_gateway.php @@ -15,9 +15,12 @@ return new class extends Migration if(!Gateway::find(64)) { + $BLOCKONOMICS_BASE_URL = 'https://www.blockonomics.co'; + $BLOCKONOMICS_GET_CALLBACKS_URL = $BLOCKONOMICS_BASE_URL . '/api/address?&no_balance=true&only_xpub=true&get_callback=true'; $fields = new \stdClass; $fields->apiKey = ""; - $fields->callbackUrl = ""; + // insert call to get callback url and set callback url based on response + $fields->callbackUrl = config('ninja.app_url'); $fields->callbackSecret = md5(uniqid(rand(), true)); $gateway = new Gateway; From e220cb7a4e35b5e7e610b28c06294467e3354f2d Mon Sep 17 00:00:00 2001 From: cnohall Date: Wed, 4 Sep 2024 11:50:08 +0900 Subject: [PATCH 09/59] temp, still missing payment screen --- .../Blockonomics/Blockonomics.php | 37 +++++++------------ .../BlockonomicsPaymentDriver.php | 20 ++++++++-- ...2024_08_27_230111_blockonomics_gateway.php | 7 +--- database/seeders/PaymentLibrariesSeeder.php | 12 +++++- 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index f4be7c5ae891..64436a48e99e 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -13,6 +13,8 @@ namespace App\PaymentDrivers\Blockonomics; use App\Models\Payment; +use App\Models\PaymentType; +use App\Models\GatewayType; use App\PaymentDrivers\BlockonomicsPaymentDriver; use App\Utils\Traits\MakesHash; use App\PaymentDrivers\Common\MethodInterface; @@ -67,35 +69,24 @@ class Blockonomics implements MethodInterface $drv = $this->driver_class; if ( - strlen($drv->api_key) < 1 + strlen($drv->api_key) < 1 || + strlen($drv->callback_secret) < 1 || + strlen($drv->callback_url) < 1 ) { throw new PaymentFailed('Blockonomics is not well configured'); } try { - // This is where the payment happens - // Will probably have to implement a curl request to the blockonomics API - // to create a new payment request - // Or potentially use an off-site solution + // $data = [ + // 'payment_method' => '', + // 'payment_type' => PaymentType::CRYPTO, + // 'amount' => 200, + // 'transaction_reference' => 123, + // 'gateway_type_id' => GatewayType::CRYPTO, + // ]; - $_invoice = collect($drv->payment_hash->data->invoices)->first(); - $cli = $drv->client; - - $metaData = [ - 'buyerName' => $cli->name, - 'buyerAddress1' => $cli->address1, - 'buyerAddress2' => $cli->address2, - 'buyerCity' => $cli->city, - 'buyerState' => $cli->state, - 'buyerZip' => $cli->postal_code, - 'buyerCountry' => $cli->country_id, - 'buyerPhone' => $cli->phone, - 'itemDesc' => "From InvoiceNinja", - 'InvoiceNinjaPaymentHash' => $drv->payment_hash->hash - ]; - - - $urlRedirect = redirect()->route('client.invoice.show', ['invoice' => $_invoice->invoice_id])->getTargetUrl(); + // $payment = $this->createPayment($data, Payment::STATUS_COMPLETED); + return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey(6)]); } catch (\Throwable $e) { PaymentFailureMailer::dispatch($drv->client, $drv->payment_hash->data, $drv->client->company, $request->amount); diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index 211ac2174b06..f3abba427362 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -53,8 +53,8 @@ class BlockonomicsPaymentDriver extends BaseDriver public function init() { $this->api_key = $this->company_gateway->getConfigField('apiKey'); - $response = $this->get_callbacks($this->api_key); - $this->callback_url = $response; + $this->callback_secret = $this->company_gateway->getConfigField('callbackSecret'); + $this->callback_url = $this->company_gateway->getConfigField('callbackUrl'); return $this; /* This is where you boot the gateway with your auth credentials*/ } @@ -93,6 +93,20 @@ class BlockonomicsPaymentDriver extends BaseDriver return $response; } + public function getBTCPrice($id_currency) + { + $BLOCKONOMICS_BASE_URL = 'https://www.blockonomics.co'; + $BLOCKONOMICS_PRICE_URL = $BLOCKONOMICS_BASE_URL . '/api/price?currency='; + // Getting price + // $currency = new Currency((int) $id_currency); + // $options = ['http' => ['method' => 'GET']]; + // $context = stream_context_create($options); + // $contents = Tools::file_get_contents(Configuration::get('BLOCKONOMICS_PRICE_URL') . $currency->iso_code, false, $context); + // $priceObj = Tools::jsonDecode($contents); + + return $priceObj->price; + } + // public function get_callbackSecret() // { // return md5(uniqid(rand(), true)); @@ -161,7 +175,7 @@ class BlockonomicsPaymentDriver extends BaseDriver if (!$webhookClient->isIncomingWebhookRequestValid($webhook_payload, $sig, $this->webhook_secret)) { throw new \RuntimeException( - 'Invalid BTCPayServer payment notification message received - signature did not match.' + 'Invalid blockonomics payment notification message received - signature did not match.' ); } diff --git a/database/migrations/2024_08_27_230111_blockonomics_gateway.php b/database/migrations/2024_08_27_230111_blockonomics_gateway.php index caa226950624..bfe34514151c 100644 --- a/database/migrations/2024_08_27_230111_blockonomics_gateway.php +++ b/database/migrations/2024_08_27_230111_blockonomics_gateway.php @@ -15,13 +15,10 @@ return new class extends Migration if(!Gateway::find(64)) { - $BLOCKONOMICS_BASE_URL = 'https://www.blockonomics.co'; - $BLOCKONOMICS_GET_CALLBACKS_URL = $BLOCKONOMICS_BASE_URL . '/api/address?&no_balance=true&only_xpub=true&get_callback=true'; $fields = new \stdClass; $fields->apiKey = ""; - // insert call to get callback url and set callback url based on response - $fields->callbackUrl = config('ninja.app_url'); - $fields->callbackSecret = md5(uniqid(rand(), true)); + $fields->callbackUrl = ""; + $fields->callbackSecret = ""; $gateway = new Gateway; $gateway->id = 64; diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index 7a196039f20d..fa650e0620b4 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -24,6 +24,16 @@ class PaymentLibrariesSeeder extends Seeder { Model::unguard(); + // TODO: use get callbacks API to get the callback URL + $callbackUrl = config('ninja.app_url') . '/payment/callback'; + $callbackSecret = md5(uniqid(rand(), true)); + $blockonomics_fields = "{ + \"apiKey\": \"\", + \"callbackUrl\": \"$callbackUrl\", + \"callbackSecret\": \"$callbackSecret\" + }"; + + $gateways = [ ['id' => 1, 'name' => 'Authorize.Net', 'provider' => 'Authorize', 'sort_order' => 5, 'key' => '3b6621f970ab18887c4f6dca78d3f8bb', 'fields' => '{"apiLoginId":"","transactionKey":"","testMode":false,"developerMode":false,"liveEndpoint":"https:\/\/api2.authorize.net\/xml\/v1\/request.api","developerEndpoint":"https:\/\/apitest.authorize.net\/xml\/v1\/request.api"} '], @@ -89,7 +99,7 @@ class PaymentLibrariesSeeder extends Seeder ['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'], ['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], ['id' => 63, 'name' => 'Rotessa', 'is_offsite' => false, 'sort_order' => 22, 'provider' => 'Rotessa', 'key' => '91be24c7b792230bced33e930ac61676', 'fields' => '{"apiKey":"", "testMode":""}'], - ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => '{"apiKey":"", "callbackUrl":"", "callbackSecret": ""}'], + ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => "$blockonomics_fields"], ]; foreach ($gateways as $gateway) { From 915bbd96f263512c709f038586f4533e278ff648 Mon Sep 17 00:00:00 2001 From: cnohall Date: Wed, 4 Sep 2024 13:44:39 +0900 Subject: [PATCH 10/59] add comment for QR code --- .../views/portal/ninja2020/gateways/blockonomics/pay.blade.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index a53ac383fb09..1c2c22885166 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -4,6 +4,8 @@ @include('portal.ninja2020.gateways.includes.payment_details') + +
this is where the blockonomics QR code goes, or if needed we can redirect them to an offsite url and handle the payment there
@csrf From f3d12fb977fb27b875654daa0a54813fa5b01c1f Mon Sep 17 00:00:00 2001 From: cnohall Date: Thu, 5 Sep 2024 09:39:32 +0900 Subject: [PATCH 11/59] Now correctly displaying btc amount --- .../Blockonomics/Blockonomics.php | 19 ++++++++++++- .../BlockonomicsPaymentDriver.php | 27 ++++++------------- .../gateways/blockonomics/pay.blade.php | 15 +++++++---- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 64436a48e99e..0ad56f1fcc55 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -25,6 +25,7 @@ use Illuminate\Mail\Mailables\Address; use App\Services\Email\EmailObject; use App\Services\Email\Email; use Illuminate\Support\Facades\App; +use App\Models\Invoice; class Blockonomics implements MethodInterface { @@ -36,6 +37,8 @@ class Blockonomics implements MethodInterface { $this->driver_class = $driver_class; $this->driver_class->init(); + // TODO: set invoice_id + $this->invoice_id = "123"; } public function authorizeView($data) @@ -49,12 +52,25 @@ class Blockonomics implements MethodInterface { } + public function getBTCPrice() + { + $currency_code = $this->driver_class->client->getCurrencyCode(); + $BLOCKONOMICS_BASE_URL = 'https://www.blockonomics.co'; + $BLOCKONOMICS_PRICE_URL = $BLOCKONOMICS_BASE_URL . '/api/price?currency='; + $response = file_get_contents($BLOCKONOMICS_PRICE_URL . $currency_code); + $data = json_decode($response, true); + // TODO: handle error + return $data['price']; + } + public function paymentView($data) { $data['gateway'] = $this->driver_class; $data['amount'] = $data['total']['amount_with_fee']; $data['currency'] = $this->driver_class->client->getCurrencyCode(); - + $btc_amount = $data['amount'] / $this->getBTCPrice(); + $data['btc_amount'] = round($btc_amount, 10); + $data['invoice_id'] = $this->invoice_id; return render('gateways.blockonomics.pay', $data); } @@ -65,6 +81,7 @@ class Blockonomics implements MethodInterface 'payment_hash' => ['required'], 'amount' => ['required'], 'currency' => ['required'], + 'btc_amount' => ['required'], ]); $drv = $this->driver_class; diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index f3abba427362..77f5ddf2e439 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -58,7 +58,7 @@ class BlockonomicsPaymentDriver extends BaseDriver return $this; /* This is where you boot the gateway with your auth credentials*/ } - private function get($url, $apiKey) + public function get($url, $apiKey = null) { // Initialize cURL session $ch = curl_init(); @@ -66,10 +66,13 @@ class BlockonomicsPaymentDriver extends BaseDriver // Set cURL options curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'Authorization: Bearer ' . $apiKey, - 'Content-Type: application/json' - ]); + + // Set HTTP headers + $headers = ['Content-Type: application/json']; + if ($apiKey) { + $headers[] = 'Authorization: Bearer ' . $apiKey; + } + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // Execute cURL session and get the response $response = curl_exec($ch); @@ -93,20 +96,6 @@ class BlockonomicsPaymentDriver extends BaseDriver return $response; } - public function getBTCPrice($id_currency) - { - $BLOCKONOMICS_BASE_URL = 'https://www.blockonomics.co'; - $BLOCKONOMICS_PRICE_URL = $BLOCKONOMICS_BASE_URL . '/api/price?currency='; - // Getting price - // $currency = new Currency((int) $id_currency); - // $options = ['http' => ['method' => 'GET']]; - // $context = stream_context_create($options); - // $contents = Tools::file_get_contents(Configuration::get('BLOCKONOMICS_PRICE_URL') . $currency->iso_code, false, $context); - // $priceObj = Tools::jsonDecode($contents); - - return $priceObj->price; - } - // public function get_callbackSecret() // { // return md5(uniqid(rand(), true)); diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index 1c2c22885166..95571376f4e1 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -3,9 +3,14 @@ @section('gateway_content') - @include('portal.ninja2020.gateways.includes.payment_details') + -
this is where the blockonomics QR code goes, or if needed we can redirect them to an offsite url and handle the payment there
+
Invoice #{{$invoice_id}}
+
To pay, send exactly this BTC amount
+ +
To this bitcoin address
+ + @csrf @@ -18,13 +23,13 @@ - @include('portal.ninja2020.gateways.includes.pay_now') + @endsection -@push('footer') + From 2be83cb897665bb6a56e0b8f1fe76f45a4f76622 Mon Sep 17 00:00:00 2001 From: cnohall Date: Thu, 5 Sep 2024 09:49:46 +0900 Subject: [PATCH 12/59] show btc_address --- .../Blockonomics/Blockonomics.php | 35 ++++++++++++++++++- .../gateways/blockonomics/pay.blade.php | 2 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 0ad56f1fcc55..a9010ddef96f 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -52,6 +52,39 @@ class Blockonomics implements MethodInterface { } + public function getBTCAddress() + { + $api_key = $this->driver_class->api_key; + $url = 'https://www.blockonomics.co/api/new_address'; + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); + + $header = "Authorization: Bearer " . $api_key; + $headers = array(); + $headers[] = $header; + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + + $contents = curl_exec($ch); + if (curl_errno($ch)) { + echo "Error:" . curl_error($ch); + } + + $responseObj = json_decode($contents); + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close ($ch); + + if ($status == 200) { + return $responseObj->address; + } else { + echo "ERROR: " . $status . ' ' . $responseObj->message; + } + return "Something went wrong"; + } + public function getBTCPrice() { $currency_code = $this->driver_class->client->getCurrencyCode(); @@ -70,6 +103,7 @@ class Blockonomics implements MethodInterface $data['currency'] = $this->driver_class->client->getCurrencyCode(); $btc_amount = $data['amount'] / $this->getBTCPrice(); $data['btc_amount'] = round($btc_amount, 10); + $data['btc_address'] = $this->getBTCAddress(); $data['invoice_id'] = $this->invoice_id; return render('gateways.blockonomics.pay', $data); } @@ -81,7 +115,6 @@ class Blockonomics implements MethodInterface 'payment_hash' => ['required'], 'amount' => ['required'], 'currency' => ['required'], - 'btc_amount' => ['required'], ]); $drv = $this->driver_class; diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index 95571376f4e1..a881e69fbac5 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -9,7 +9,7 @@
To pay, send exactly this BTC amount
To this bitcoin address
- +
From 3de0e6367fec5f2a3f1865614dc95f2f4d869fd8 Mon Sep 17 00:00:00 2001 From: cnohall Date: Thu, 5 Sep 2024 10:06:44 +0900 Subject: [PATCH 13/59] add timer --- .../Blockonomics/Blockonomics.php | 8 +++++ .../gateways/blockonomics/pay.blade.php | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index a9010ddef96f..6078290f1f93 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -85,6 +85,13 @@ class Blockonomics implements MethodInterface return "Something went wrong"; } + public function getTenMinutesCountDownEndTime() + { + $duration_in_sec = 10 * 60; // 10 minutes in seconds + $current_time = time(); + return $current_time + $duration_in_sec; + } + public function getBTCPrice() { $currency_code = $this->driver_class->client->getCurrencyCode(); @@ -105,6 +112,7 @@ class Blockonomics implements MethodInterface $data['btc_amount'] = round($btc_amount, 10); $data['btc_address'] = $this->getBTCAddress(); $data['invoice_id'] = $this->invoice_id; + $data['end_time'] = $this->getTenMinutesCountDownEndTime(); return render('gateways.blockonomics.pay', $data); } diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index a881e69fbac5..9bc92b773877 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -10,7 +10,36 @@
To this bitcoin address
+
+ @csrf From 3e5d598d53a8277ee3cd2cd65f38c24871086c49 Mon Sep 17 00:00:00 2001 From: cnohall Date: Thu, 5 Sep 2024 12:33:28 +0900 Subject: [PATCH 14/59] update UI on checkout page --- .../gateways/blockonomics/pay.blade.php | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index 9bc92b773877..f2574eb7a596 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -4,13 +4,26 @@ - -
Invoice #{{$invoice_id}}
-
To pay, send exactly this BTC amount
- -
To this bitcoin address
- -
+
+
Invoice #{{$invoice_id}}
+
To pay, send exactly this BTC amount
+ +
To this bitcoin address
+ +
+
+ + + @csrf + + + + + + + + + -
- @csrf - - - - - - - -
+ @endsection From 886d1af8245cbf66bd71a2ab4acbd6be5b1ee2c3 Mon Sep 17 00:00:00 2001 From: cnohall Date: Thu, 5 Sep 2024 14:29:16 +0900 Subject: [PATCH 15/59] setup callback logic --- .../Blockonomics/Blockonomics.php | 52 ++++++++++++++++++- .../BlockonomicsPaymentDriver.php | 1 - database/seeders/PaymentLibrariesSeeder.php | 3 +- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 6078290f1f93..e5cc5c72812b 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -52,10 +52,58 @@ class Blockonomics implements MethodInterface { } + public function doCurlCall($url, $post_content = '') + { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + if ($post_content) { + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_content); + } + curl_setopt($ch, CURLOPT_TIMEOUT, 60); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $this->driver_class->api_key, + 'Content-type: application/x-www-form-urlencoded', + ]); + + $contents = curl_exec($ch); + if (curl_errno($ch)) { + echo "Error:" . curl_error($ch); + } + $responseObj = json_decode($contents); + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close ($ch); + + if ($status != 200) { + echo "ERROR: " . $status . ' ' . $responseObj->message; + } else { + echo "Success: " . $status; + echo json_encode($responseObj); + } + + return $responseObj; + } + + public function setCallbackUrl() + { + $GET_CALLBACKS_URL = 'https://www.blockonomics.co/api/address?&no_balance=true&only_xpub=true&get_callback=true'; + $SET_CALLBACK_URL = 'https://www.blockonomics.co/api/update_callback'; + $get_callback_response = $this->doCurlCall($GET_CALLBACKS_URL); + + $callback_url = $this->driver_class->callback_url; + $xpub = $get_callback_response[0]->address; + $post_content = '{"callback": "' . $callback_url . '", "xpub": "' . $xpub . '"}'; + + $responseObj = $this->doCurlCall($SET_CALLBACK_URL, $post_content); + return $responseObj; + } + public function getBTCAddress() { $api_key = $this->driver_class->api_key; - $url = 'https://www.blockonomics.co/api/new_address'; + // TODO: remove ?reset=1 before marking PR as ready + $url = 'https://www.blockonomics.co/api/new_address?reset=1'; $ch = curl_init(); @@ -113,12 +161,12 @@ class Blockonomics implements MethodInterface $data['btc_address'] = $this->getBTCAddress(); $data['invoice_id'] = $this->invoice_id; $data['end_time'] = $this->getTenMinutesCountDownEndTime(); + $data['callback_url'] = $this->setCallbackUrl(); return render('gateways.blockonomics.pay', $data); } public function paymentResponse(PaymentResponseRequest $request) { - $request->validate([ 'payment_hash' => ['required'], 'amount' => ['required'], diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index 77f5ddf2e439..e71273879bd4 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -48,7 +48,6 @@ class BlockonomicsPaymentDriver extends BaseDriver public $BASE_URL = 'https://www.blockonomics.co'; public $NEW_ADDRESS_URL = 'https://www.blockonomics.co/api/new_address'; public $PRICE_URL = 'https://www.blockonomics.co/api/price'; - public $SET_CALLBACK_URL = 'https://www.blockonomics.co/api/update_callback'; public function init() { diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index fa650e0620b4..2137e2ce9035 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -24,8 +24,7 @@ class PaymentLibrariesSeeder extends Seeder { Model::unguard(); - // TODO: use get callbacks API to get the callback URL - $callbackUrl = config('ninja.app_url') . '/payment/callback'; + $callbackUrl = config('ninja.app_url') . '/client/payments/process/?secret='; $callbackSecret = md5(uniqid(rand(), true)); $blockonomics_fields = "{ \"apiKey\": \"\", From 67379d7c4f1d13d28a925faa945bb85c0cf4a32e Mon Sep 17 00:00:00 2001 From: cnohall Date: Fri, 6 Sep 2024 09:52:21 +0900 Subject: [PATCH 16/59] incorporate websocket --- .../Blockonomics/Blockonomics.php | 27 +++++++++---------- .../BlockonomicsPaymentDriver.php | 1 + .../gateways/blockonomics/pay.blade.php | 24 +++++++++++++++++ 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index e5cc5c72812b..3fa41439a4c4 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -77,11 +77,7 @@ class Blockonomics implements MethodInterface if ($status != 200) { echo "ERROR: " . $status . ' ' . $responseObj->message; - } else { - echo "Success: " . $status; - echo json_encode($responseObj); } - return $responseObj; } @@ -157,11 +153,14 @@ class Blockonomics implements MethodInterface $data['amount'] = $data['total']['amount_with_fee']; $data['currency'] = $this->driver_class->client->getCurrencyCode(); $btc_amount = $data['amount'] / $this->getBTCPrice(); - $data['btc_amount'] = round($btc_amount, 10); - $data['btc_address'] = $this->getBTCAddress(); + $data['btc_amount'] = number_format($btc_amount, 10, '.', ''); + $btc_address = $this->getBTCAddress(); + $data['btc_address'] = $btc_address; $data['invoice_id'] = $this->invoice_id; $data['end_time'] = $this->getTenMinutesCountDownEndTime(); $data['callback_url'] = $this->setCallbackUrl(); + + $data['websocket_url'] = 'wss://www.blockonomics.co/payment/' . $btc_address; return render('gateways.blockonomics.pay', $data); } @@ -183,15 +182,13 @@ class Blockonomics implements MethodInterface } try { - // $data = [ - // 'payment_method' => '', - // 'payment_type' => PaymentType::CRYPTO, - // 'amount' => 200, - // 'transaction_reference' => 123, - // 'gateway_type_id' => GatewayType::CRYPTO, - // ]; - - // $payment = $this->createPayment($data, Payment::STATUS_COMPLETED); + $data = [ + 'payment_method' => '', + 'payment_type' => PaymentType::CRYPTO, + 'amount' => 200, + 'transaction_reference' => 123, + 'gateway_type_id' => GatewayType::CRYPTO, + ]; return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey(6)]); } catch (\Throwable $e) { diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index e71273879bd4..9d954cf9ce48 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -125,6 +125,7 @@ class BlockonomicsPaymentDriver extends BaseDriver public function processPaymentResponse($request) { + echo "It reached the processPaymentResponse"; return $this->payment_method->paymentResponse($request); } diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index f2574eb7a596..1151140f120a 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -54,6 +54,30 @@ var x = setInterval(updateCountdown, 1000); + + From 3380378ec66e119f22df4d78a3324731339ac310 Mon Sep 17 00:00:00 2001 From: cnohall Date: Fri, 6 Sep 2024 16:19:52 +0900 Subject: [PATCH 23/59] update the payment UI with copying functionality and icons --- .../gateways/blockonomics/pay.blade.php | 68 +++++++++++++------ 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index c9908f6569e8..f1a491040ec1 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -3,15 +3,18 @@ @section('gateway_content') -
Invoice #{{$invoice_number}}
To pay, send exactly this BTC amount
-
+
{{$btc_amount}} BTC ≈ {{$amount}} {{$currency}} + ') }}" class="icon" alt="Copy Icon">
To this bitcoin address
- +
+ + ') }}" class="icon" alt="Copy Icon"> +
@@ -47,14 +50,37 @@ var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); var seconds = Math.floor((distance % (1000 * 60)) / 1000); - document.getElementById("countdown").innerHTML = - "0" + minutes + ":" + - (seconds < 10 ? "0" : "") + seconds + " min"; + document.getElementById("countdown").innerHTML = minutes + "m " + seconds + "s "; } + setInterval(updateCountdown, 1000); + + - From f1f64c277c9d026ed59589396b3f66e60d693432 Mon Sep 17 00:00:00 2001 From: cnohall Date: Fri, 6 Sep 2024 16:25:13 +0900 Subject: [PATCH 24/59] fix bug when icon blocks input text on small devices with small viewports --- .../views/portal/ninja2020/gateways/blockonomics/pay.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index f1a491040ec1..0b0ca221c20b 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -129,7 +129,7 @@ .full-width-input { width: 100%; margin: 10px 0; - padding: 10px; + padding: 10px 40px 10px 10px; text-align: center; border: 1px solid #ccc; border-radius: 5px; From 2ac42b4caf8380eb0dac0c1ef6ec82b5b4d8f0eb Mon Sep 17 00:00:00 2001 From: cnohall Date: Sat, 7 Sep 2024 08:52:30 +0900 Subject: [PATCH 25/59] add unconfirmed payment initial message --- .../gateways/blockonomics/pay.blade.php | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index 0b0ca221c20b..59e25c5d110c 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -4,6 +4,10 @@
+
+ The payment is unconfirmed but in progress, please stay tuned. +
+
Invoice #{{$invoice_number}}
To pay, send exactly this BTC amount
@@ -16,6 +20,7 @@ ') }}" class="icon" alt="Copy Icon">
+
@@ -94,7 +99,14 @@ ws.onmessage = function(event) { const data = JSON.parse(event.data); console.log('Payment status:', data.status); - const isPaymentConfirmed = data.status == 2; + const isPaymentUnconfirmed = data.status === 0; + const isPaymentConfirmed = data.status === 2; + if (isPaymentUnconfirmed) { + // Hide all existing content + document.querySelector('.initial-state').style.display = 'none'; + document.querySelector('.progress-message').style.display = 'block'; + return; + } if (isPaymentConfirmed) { document.querySelector('input[name="txid"]').value = data.txid || ''; document.getElementById('server-response').submit(); @@ -120,6 +132,11 @@ margin-bottom: 20px; } .blockonomics-payment-wrapper { + padding: 12px; + display: flex; + justify-content: center; + } + .initial-state { justify-content: center; display: flex; flex-direction: column; @@ -148,6 +165,12 @@ transform: translateY(-50%); cursor: pointer; } + .progress-message { + display: none; + margin: 120px 0; + font-weight: bold; + font-size: 18px; + } From 0762915ecca9016d5e69a4598d9d80642e1552c1 Mon Sep 17 00:00:00 2001 From: cnohall Date: Sun, 8 Sep 2024 19:24:25 +0900 Subject: [PATCH 26/59] Add updated copy --- .../views/portal/ninja2020/gateways/blockonomics/pay.blade.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index 59e25c5d110c..985f712576ff 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -5,7 +5,8 @@
- The payment is unconfirmed but in progress, please stay tuned. + + Your payment txid has been recieved. The invoice will be marked as paid automatically once the payment is confirmed.
Invoice #{{$invoice_number}}
From 9ec5a1c1543d4c1c30c91d872acfd7919fd83a0e Mon Sep 17 00:00:00 2001 From: cnohall Date: Sun, 8 Sep 2024 19:50:29 +0900 Subject: [PATCH 27/59] add link that takes the user to the invoice on unconfirmed transaction --- .../Blockonomics/Blockonomics.php | 1 + .../gateways/blockonomics/pay.blade.php | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 55fe0f4b8190..6c90cc8150db 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -161,6 +161,7 @@ class Blockonomics implements MethodInterface $data['invoice_number'] = $_invoice->invoice_number; $data['end_time'] = $this->getTenMinutesCountDownEndTime(); $data['callback_url'] = $this->setCallbackUrl(); + $data['invoice_redirect_url'] = "/client/invoices/{$_invoice->invoice_id}"; $data['websocket_url'] = 'wss://www.blockonomics.co/payment/' . $btc_address; return render('gateways.blockonomics.pay', $data); diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index 985f712576ff..3777b1a69c2d 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -5,8 +5,10 @@
- - Your payment txid has been recieved. The invoice will be marked as paid automatically once the payment is confirmed. + Your payment txid has been recieved. + +

+ The invoice will be marked as paid automatically once the payment is confirmed.
Invoice #{{$invoice_number}}
@@ -106,6 +108,7 @@ // Hide all existing content document.querySelector('.initial-state').style.display = 'none'; document.querySelector('.progress-message').style.display = 'block'; + document.getElementById('txid').innerText = data.txid || ''; return; } if (isPaymentConfirmed) { @@ -168,9 +171,14 @@ } .progress-message { display: none; - margin: 120px 0; - font-weight: bold; - font-size: 18px; + margin: 90px 0; + max-width: 400px; + font-size: 16px; + text-align: center; + } + #link { + color: #007bff; + text-decoration: underline; } From 5a5e0960c3f92bc83f7d61660e28df69585f54a9 Mon Sep 17 00:00:00 2001 From: cnohall Date: Sun, 8 Sep 2024 20:24:13 +0900 Subject: [PATCH 28/59] implement payment pending --- .../Blockonomics/Blockonomics.php | 4 +- .../BlockonomicsPaymentDriver.php | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 6c90cc8150db..6199ce569f3d 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -186,8 +186,8 @@ class Blockonomics implements MethodInterface $data['transaction_reference'] = "payment hash: " . $request->payment_hash . " txid: " . $request->txid; $data['txid'] = $request->txid; - $payment = $this->blockonomics->createPayment($data); - echo "Payment successful"; + $statusId = Payment::STATUS_PENDING; + $payment = $this->blockonomics->createPayment($data, $statusId); SystemLogger::dispatch( ['response' => $payment, 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index 94d1fa935fcc..abb89bc7504f 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -130,6 +130,72 @@ class BlockonomicsPaymentDriver extends BaseDriver public function processWebhookRequest() { + // Get the callback parameters + $txid = $_GET['txid']; + $value = $_GET['value']; + $status = $_GET['status']; + $addr = $_GET['addr']; + $receivedSecret = $_GET['secret']; + + // Initialize the Webhook client (assuming it can be used for validation) + $webhookClient = new Webhook($this->blockonomics_url, $this->api_key); + + // Validate the webhook request + if (!$webhookClient->isValidRequest($_GET, $receivedSecret)) { + throw new PaymentFailed('Invalid webhook request'); + } + + // Only accept confirmed transactions + if ($status != 2) { + throw new PaymentFailed('Transaction not confirmed'); + } + + // Connect to the database + $db = new SQLite3('payments_db.sqlite', SQLITE3_OPEN_READWRITE); + + // Find the payment hash in the database + $this->payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$addr])->firstOrFail(); + + // Set the payment method to cryptocurrency + $this->setPaymentMethod(GatewayType::CRYPTO); + + // Determine the payment status + $StatusId = Payment::STATUS_PENDING; + if ($this->payment_hash->payment_id == null) { + $_invoice = Invoice::with('client')->withTrashed()->find($this->payment_hash->fee_invoice_id); + $this->client = $_invoice->client; + + $dataPayment = [ + 'payment_method' => $this->payment_method, + 'payment_type' => PaymentType::CRYPTO, + 'amount' => $_invoice->amount, + 'gateway_type_id' => GatewayType::CRYPTO, + 'transaction_reference' => $txid + ]; + $payment = $this->createPayment($dataPayment, $StatusId); + } else { + $payment = Payment::withTrashed()->find($this->payment_hash->payment_id); + $StatusId = $payment->status_id; + } + + // Update the payment status based on the transaction status + switch ($status) { + case 0: + $StatusId = Payment::STATUS_PENDING; + break; + case 1: + $StatusId = Payment::STATUS_PENDING; + break; + case 2: + $StatusId = Payment::STATUS_COMPLETED; + break; + } + + // Save the updated payment status + if ($payment->status_id != $StatusId) { + $payment->status_id = $StatusId; + $payment->save(); + } } From 3cbe4518786bd34e64d91243a4578273b2183223 Mon Sep 17 00:00:00 2001 From: cnohall Date: Tue, 10 Sep 2024 15:02:55 +0900 Subject: [PATCH 29/59] combine use of websocket and callback --- .../Blockonomics/Blockonomics.php | 46 +----- .../BlockonomicsPaymentDriver.php | 139 +++++++++--------- .../gateways/blockonomics/pay.blade.php | 11 +- routes/api.php | 2 + tests/cypress/support/routes.json | 9 ++ 5 files changed, 82 insertions(+), 125 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 6199ce569f3d..313063921fe6 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -52,48 +52,6 @@ class Blockonomics implements MethodInterface { } - public function doCurlCall($url, $post_content = '') - { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - if ($post_content) { - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $post_content); - } - curl_setopt($ch, CURLOPT_TIMEOUT, 60); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'Authorization: Bearer ' . $this->blockonomics->api_key, - 'Content-type: application/x-www-form-urlencoded', - ]); - - $contents = curl_exec($ch); - if (curl_errno($ch)) { - echo "Error:" . curl_error($ch); - } - $responseObj = json_decode($contents); - $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close ($ch); - - if ($status != 200) { - echo "ERROR: " . $status . ' ' . $responseObj->message; - } - return $responseObj; - } - - public function setCallbackUrl() - { - $GET_CALLBACKS_URL = 'https://www.blockonomics.co/api/address?&no_balance=true&only_xpub=true&get_callback=true'; - $SET_CALLBACK_URL = 'https://www.blockonomics.co/api/update_callback'; - $get_callback_response = $this->doCurlCall($GET_CALLBACKS_URL); - - $callback_url = $this->blockonomics->callback_url; - $xpub = $get_callback_response[0]->address; - $post_content = '{"callback": "' . $callback_url . '", "xpub": "' . $xpub . '"}'; - - $responseObj = $this->doCurlCall($SET_CALLBACK_URL, $post_content); - return $responseObj; - } public function getBTCAddress() { @@ -160,7 +118,6 @@ class Blockonomics implements MethodInterface $data['invoice_id'] = $_invoice->invoice_id; $data['invoice_number'] = $_invoice->invoice_number; $data['end_time'] = $this->getTenMinutesCountDownEndTime(); - $data['callback_url'] = $this->setCallbackUrl(); $data['invoice_redirect_url'] = "/client/invoices/{$_invoice->invoice_id}"; $data['websocket_url'] = 'wss://www.blockonomics.co/payment/' . $btc_address; @@ -169,12 +126,11 @@ class Blockonomics implements MethodInterface public function paymentResponse(PaymentResponseRequest $request) { + echo "Payment response received"; $request->validate([ 'payment_hash' => ['required'], 'amount' => ['required'], 'currency' => ['required'], - 'payment_method_id' => ['required'], - 'txid' => ['required'], ]); try { diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index abb89bc7504f..651aeedfe31d 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -54,51 +54,73 @@ class BlockonomicsPaymentDriver extends BaseDriver $this->api_key = $this->company_gateway->getConfigField('apiKey'); $this->callback_secret = $this->company_gateway->getConfigField('callbackSecret'); $this->callback_url = $this->company_gateway->getConfigField('callbackUrl'); + // $this->setCallbackUrl(); return $this; /* This is where you boot the gateway with your auth credentials*/ } - public function get($url, $apiKey = null) + public function doCurlCall($url, $post_content = '') { - // Initialize cURL session $ch = curl_init(); - - // Set cURL options curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - // Set HTTP headers - $headers = ['Content-Type: application/json']; - if ($apiKey) { - $headers[] = 'Authorization: Bearer ' . $apiKey; + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + if ($post_content) { + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_content); } - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_TIMEOUT, 60); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $this->api_key, + 'Content-type: application/x-www-form-urlencoded', + ]); - // Execute cURL session and get the response - $response = curl_exec($ch); - - // Check for errors + $contents = curl_exec($ch); if (curl_errno($ch)) { - throw new Exception(curl_error($ch)); + echo "Error:" . curl_error($ch); } + $responseObj = json_decode($contents); + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close ($ch); - // Close cURL session - curl_close($ch); - - // Return the response - return json_decode($response, true); + if ($status != 200) { + echo "ERROR: " . $status . ' ' . $responseObj->message; + } + return $responseObj; } - public function get_callbacks($api_key) + public function setCallbackUrl() { $GET_CALLBACKS_URL = 'https://www.blockonomics.co/api/address?&no_balance=true&only_xpub=true&get_callback=true'; - $response = $this->get($GET_CALLBACKS_URL, $api_key); - return $response; + $SET_CALLBACK_URL = 'https://www.blockonomics.co/api/update_callback'; + $get_callback_response = $this->doCurlCall($GET_CALLBACKS_URL); + + $callback_url = $this->callback_url; + $xpub = $get_callback_response[0]->address; + $post_content = '{"callback": "' . $callback_url . '", "xpub": "' . $xpub . '"}'; + + $responseObj = $this->doCurlCall($SET_CALLBACK_URL, $post_content); + return $responseObj; } - // public function get_callbackSecret() - // { - // return md5(uniqid(rand(), true)); - // } + public function findPaymentByTxid($txid) + { + return Payment::whereRaw('BINARY `transaction_reference` LIKE ? AND BINARY `transaction_reference` LIKE ?', [ + "%payment hash:%", + "%txid: " . $txid . "%" + ])->firstOrFail(); + } + + public function findPaymentHashInTransactionReference($transaction_reference) + { + $pattern = '/payment hash:\s*([a-zA-Z0-9]+)/'; + // Perform the regex match + if (preg_match($pattern, $transaction_reference, $matches)) { + // Return the matched payment hash + return $matches[1]; + } else { + // Return null if no match is found + return null; + } + } /* Returns an array of gateway types for the payment gateway */ @@ -130,70 +152,43 @@ class BlockonomicsPaymentDriver extends BaseDriver public function processWebhookRequest() { - // Get the callback parameters + // TODO: Figure out why init does not work + // $this->init(); + // $secret = $this->company_gateway->getConfigField('callbackSecret'); + // //Match secret for security + // if ($_GET['secret'] != $secret) { + // echo "Invalid Secret"; + // return; + // } + $txid = $_GET['txid']; $value = $_GET['value']; $status = $_GET['status']; $addr = $_GET['addr']; - $receivedSecret = $_GET['secret']; - - // Initialize the Webhook client (assuming it can be used for validation) - $webhookClient = new Webhook($this->blockonomics_url, $this->api_key); - - // Validate the webhook request - if (!$webhookClient->isValidRequest($_GET, $receivedSecret)) { - throw new PaymentFailed('Invalid webhook request'); - } // Only accept confirmed transactions if ($status != 2) { throw new PaymentFailed('Transaction not confirmed'); } + + $payment = $this->findPaymentByTxid($txid); + $payment_hash = $this->findPaymentHashInTransactionReference($payment->transaction_reference); - // Connect to the database - $db = new SQLite3('payments_db.sqlite', SQLITE3_OPEN_READWRITE); - - // Find the payment hash in the database - $this->payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$addr])->firstOrFail(); - - // Set the payment method to cryptocurrency - $this->setPaymentMethod(GatewayType::CRYPTO); - - // Determine the payment status - $StatusId = Payment::STATUS_PENDING; - if ($this->payment_hash->payment_id == null) { - $_invoice = Invoice::with('client')->withTrashed()->find($this->payment_hash->fee_invoice_id); - $this->client = $_invoice->client; - - $dataPayment = [ - 'payment_method' => $this->payment_method, - 'payment_type' => PaymentType::CRYPTO, - 'amount' => $_invoice->amount, - 'gateway_type_id' => GatewayType::CRYPTO, - 'transaction_reference' => $txid - ]; - $payment = $this->createPayment($dataPayment, $StatusId); - } else { - $payment = Payment::withTrashed()->find($this->payment_hash->payment_id); - $StatusId = $payment->status_id; - } - - // Update the payment status based on the transaction status switch ($status) { case 0: - $StatusId = Payment::STATUS_PENDING; + $statusId = Payment::STATUS_PENDING; break; case 1: - $StatusId = Payment::STATUS_PENDING; + $statusId = Payment::STATUS_PENDING; break; case 2: - $StatusId = Payment::STATUS_COMPLETED; + $statusId = Payment::STATUS_COMPLETED; break; } // Save the updated payment status - if ($payment->status_id != $StatusId) { - $payment->status_id = $StatusId; + if ($payment->status_id != $statusId) { + $payment->status_id = $statusId; $payment->save(); } } diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index 3777b1a69c2d..34e1e480db65 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -103,15 +103,10 @@ const data = JSON.parse(event.data); console.log('Payment status:', data.status); const isPaymentUnconfirmed = data.status === 0; + const isPaymentPartiallyConfirmed = data.status === 1; const isPaymentConfirmed = data.status === 2; - if (isPaymentUnconfirmed) { - // Hide all existing content - document.querySelector('.initial-state').style.display = 'none'; - document.querySelector('.progress-message').style.display = 'block'; - document.getElementById('txid').innerText = data.txid || ''; - return; - } - if (isPaymentConfirmed) { + const shouldSubmitForm = isPaymentUnconfirmed || isPaymentConfirmed || isPaymentPartiallyConfirmed; + if (shouldSubmitForm) { document.querySelector('input[name="txid"]').value = data.txid || ''; document.getElementById('server-response').submit(); } diff --git a/routes/api.php b/routes/api.php index 2a5a2350f191..e27dbc4f072c 100644 --- a/routes/api.php +++ b/routes/api.php @@ -63,6 +63,7 @@ use App\Http\Controllers\Bank\YodleeController; use App\Http\Controllers\CompanyUserController; use App\Http\Controllers\PaymentTermController; use App\PaymentDrivers\PayPalPPCPPaymentDriver; +use App\PaymentDrivers\BlockonomicsPaymentDriver; use App\Http\Controllers\EmailHistoryController; use App\Http\Controllers\GroupSettingController; use App\Http\Controllers\OneTimeTokenController; @@ -458,5 +459,6 @@ Route::post('api/v1/yodlee/balance', [YodleeController::class, 'balanceWebhook'] Route::get('api/v1/protected_download/{hash}', [ProtectedDownloadController::class, 'index'])->name('protected_download')->middleware('throttle:300,1'); Route::post('api/v1/ppcp/webhook', [PayPalPPCPPaymentDriver::class, 'processWebhookRequest'])->middleware('throttle:1000,1'); +Route::get('api/v1/blockonomics/callback', [BlockonomicsPaymentDriver::class, 'processWebhookRequest'])->middleware('throttle:1000,1'); Route::fallback([BaseController::class, 'notFound'])->middleware('throttle:404'); diff --git a/tests/cypress/support/routes.json b/tests/cypress/support/routes.json index b8b5c8b622d6..f86ea641a97d 100644 --- a/tests/cypress/support/routes.json +++ b/tests/cypress/support/routes.json @@ -5622,5 +5622,14 @@ "GET", "HEAD" ] + }, + "generated::aB3xYz9KlmN7Pq8R": { + "name": "generated::aB3xYz9KlmN7Pq8R", + "domain": null, + "action": "App\\Http\\Controllers\\BlockonomicsPaymentDriver@processWebhookRequest", + "uri": "api/v1/blockonomics/callback", + "method": [ + "GET" + ] } } \ No newline at end of file From 5d07317cfacc913ce2d155482cf4365ec2427e44 Mon Sep 17 00:00:00 2001 From: cnohall Date: Tue, 10 Sep 2024 15:19:09 +0900 Subject: [PATCH 30/59] add success http message --- app/PaymentDrivers/BlockonomicsPaymentDriver.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index 651aeedfe31d..01c245a8c74f 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -191,6 +191,10 @@ class BlockonomicsPaymentDriver extends BaseDriver $payment->status_id = $statusId; $payment->save(); } + + header('HTTP/1.1 200 OK'); + echo 'SUCCESS'; + return; } From f1c25e678e9ad7376bf640da0ab0c6d058efd92b Mon Sep 17 00:00:00 2001 From: cnohall Date: Tue, 10 Sep 2024 15:37:53 +0900 Subject: [PATCH 31/59] change the payment screen --- .../ninja2020/gateways/blockonomics/pay.blade.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index 34e1e480db65..baf8bc44ac71 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -4,12 +4,11 @@
-
+

The invoice will be marked as paid automatically once the payment is confirmed. -
+
-->
Invoice #{{$invoice_number}}
To pay, send exactly this BTC amount
@@ -104,9 +103,9 @@ console.log('Payment status:', data.status); const isPaymentUnconfirmed = data.status === 0; const isPaymentPartiallyConfirmed = data.status === 1; - const isPaymentConfirmed = data.status === 2; - const shouldSubmitForm = isPaymentUnconfirmed || isPaymentConfirmed || isPaymentPartiallyConfirmed; - if (shouldSubmitForm) { + // TODO: Do we need to handle Payment confirmed status? + // This usually takes too long to happen, so we can just wait for the unconfirmed status? + if (isPaymentUnconfirmed || isPaymentPartiallyConfirmed) { document.querySelector('input[name="txid"]').value = data.txid || ''; document.getElementById('server-response').submit(); } @@ -164,7 +163,7 @@ transform: translateY(-50%); cursor: pointer; } - .progress-message { + /* .progress-message { display: none; margin: 90px 0; max-width: 400px; @@ -174,7 +173,7 @@ #link { color: #007bff; text-decoration: underline; - } + } */ From bd4b4a6712ad509c327c099db9280eda10f8a649 Mon Sep 17 00:00:00 2001 From: cnohall Date: Tue, 10 Sep 2024 18:30:48 +0900 Subject: [PATCH 32/59] comment out old code and update callbackUrl --- .../BlockonomicsPaymentDriver.php | 107 +++++++++--------- database/seeders/PaymentLibrariesSeeder.php | 4 +- 2 files changed, 53 insertions(+), 58 deletions(-) diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index 01c245a8c74f..70fc1cf56c14 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -52,75 +52,70 @@ class BlockonomicsPaymentDriver extends BaseDriver public function init() { $this->api_key = $this->company_gateway->getConfigField('apiKey'); - $this->callback_secret = $this->company_gateway->getConfigField('callbackSecret'); $this->callback_url = $this->company_gateway->getConfigField('callbackUrl'); // $this->setCallbackUrl(); return $this; /* This is where you boot the gateway with your auth credentials*/ } - public function doCurlCall($url, $post_content = '') - { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - if ($post_content) { - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $post_content); - } - curl_setopt($ch, CURLOPT_TIMEOUT, 60); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'Authorization: Bearer ' . $this->api_key, - 'Content-type: application/x-www-form-urlencoded', - ]); + // public function doCurlCall($url, $post_content = '') + // { + // $ch = curl_init(); + // curl_setopt($ch, CURLOPT_URL, $url); + // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + // if ($post_content) { + // curl_setopt($ch, CURLOPT_POST, 1); + // curl_setopt($ch, CURLOPT_POSTFIELDS, $post_content); + // } + // curl_setopt($ch, CURLOPT_TIMEOUT, 60); + // curl_setopt($ch, CURLOPT_HTTPHEADER, [ + // 'Authorization: Bearer ' . $this->api_key, + // 'Content-type: application/x-www-form-urlencoded', + // ]); + // $contents = curl_exec($ch); + // if (curl_errno($ch)) { + // echo "Error:" . curl_error($ch); + // } + // $responseObj = json_decode($contents); + // $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + // curl_close ($ch); + // if ($status != 200) { + // echo "ERROR: " . $status . ' ' . $responseObj->message; + // } + // return $responseObj; + // } - $contents = curl_exec($ch); - if (curl_errno($ch)) { - echo "Error:" . curl_error($ch); - } - $responseObj = json_decode($contents); - $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close ($ch); + // public function setCallbackUrl() + // { + // $GET_CALLBACKS_URL = 'https://www.blockonomics.co/api/address?&no_balance=true&only_xpub=true&get_callback=true'; + // $SET_CALLBACK_URL = 'https://www.blockonomics.co/api/update_callback'; + // $get_callback_response = $this->doCurlCall($GET_CALLBACKS_URL); - if ($status != 200) { - echo "ERROR: " . $status . ' ' . $responseObj->message; - } - return $responseObj; - } + // $callback_url = $this->callback_url; + // $xpub = $get_callback_response[0]->address; + // $post_content = '{"callback": "' . $callback_url . '", "xpub": "' . $xpub . '"}'; - public function setCallbackUrl() - { - $GET_CALLBACKS_URL = 'https://www.blockonomics.co/api/address?&no_balance=true&only_xpub=true&get_callback=true'; - $SET_CALLBACK_URL = 'https://www.blockonomics.co/api/update_callback'; - $get_callback_response = $this->doCurlCall($GET_CALLBACKS_URL); + // $responseObj = $this->doCurlCall($SET_CALLBACK_URL, $post_content); + // return $responseObj; + // } - $callback_url = $this->callback_url; - $xpub = $get_callback_response[0]->address; - $post_content = '{"callback": "' . $callback_url . '", "xpub": "' . $xpub . '"}'; - - $responseObj = $this->doCurlCall($SET_CALLBACK_URL, $post_content); - return $responseObj; - } + // public function findPaymentHashInTransactionReference($transaction_reference) + // { + // $pattern = '/payment hash:\s*([a-zA-Z0-9]+)/'; + // // Perform the regex match + // if (preg_match($pattern, $transaction_reference, $matches)) { + // // Return the matched payment hash + // return $matches[1]; + // } else { + // // Return null if no match is found + // return null; + // } + // } public function findPaymentByTxid($txid) { - return Payment::whereRaw('BINARY `transaction_reference` LIKE ? AND BINARY `transaction_reference` LIKE ?', [ - "%payment hash:%", - "%txid: " . $txid . "%" - ])->firstOrFail(); + return Payment::whereRaw('BINARY `transaction_reference` LIKE ?', ["%txid: " . $txid])->firstOrFail(); } - public function findPaymentHashInTransactionReference($transaction_reference) - { - $pattern = '/payment hash:\s*([a-zA-Z0-9]+)/'; - // Perform the regex match - if (preg_match($pattern, $transaction_reference, $matches)) { - // Return the matched payment hash - return $matches[1]; - } else { - // Return null if no match is found - return null; - } - } /* Returns an array of gateway types for the payment gateway */ @@ -172,7 +167,7 @@ class BlockonomicsPaymentDriver extends BaseDriver } $payment = $this->findPaymentByTxid($txid); - $payment_hash = $this->findPaymentHashInTransactionReference($payment->transaction_reference); + // $payment_hash = $this->findPaymentHashInTransactionReference($payment->transaction_reference); switch ($status) { case 0: diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index 2137e2ce9035..964b81864909 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -24,12 +24,12 @@ class PaymentLibrariesSeeder extends Seeder { Model::unguard(); - $callbackUrl = config('ninja.app_url') . '/client/payments/process/?secret='; $callbackSecret = md5(uniqid(rand(), true)); + $callbackUrl = config('ninja.app_url') . "/api/v1/blockonomics/callback/?secret=$callbackSecret"; $blockonomics_fields = "{ \"apiKey\": \"\", \"callbackUrl\": \"$callbackUrl\", - \"callbackSecret\": \"$callbackSecret\" + \"callbackSecret\": \"$callbackSecret\", }"; From 97e3881017518feb67dbc0f0a1cfc284c5ea03f4 Mon Sep 17 00:00:00 2001 From: cnohall Date: Wed, 11 Sep 2024 10:03:51 +0900 Subject: [PATCH 33/59] temp --- .../Blockonomics/Blockonomics.php | 2 +- .../BlockonomicsPaymentDriver.php | 183 +++++++++--------- database/seeders/PaymentLibrariesSeeder.php | 8 +- .../gateways/blockonomics/pay.blade.php | 6 +- 4 files changed, 103 insertions(+), 96 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 313063921fe6..3da7a37815a9 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -33,7 +33,7 @@ class Blockonomics implements MethodInterface { use MakesHash; - protected BlockonomicsPaymentDriver $blockonomics; + public $driver_class; public function __construct(BlockonomicsPaymentDriver $driver_class) { diff --git a/app/PaymentDrivers/BlockonomicsPaymentDriver.php b/app/PaymentDrivers/BlockonomicsPaymentDriver.php index 70fc1cf56c14..3438c0f6bc58 100644 --- a/app/PaymentDrivers/BlockonomicsPaymentDriver.php +++ b/app/PaymentDrivers/BlockonomicsPaymentDriver.php @@ -53,10 +53,102 @@ class BlockonomicsPaymentDriver extends BaseDriver { $this->api_key = $this->company_gateway->getConfigField('apiKey'); $this->callback_url = $this->company_gateway->getConfigField('callbackUrl'); + $this->callback_secret = $this->company_gateway->getConfigField('callbackSecret'); // $this->setCallbackUrl(); return $this; /* This is where you boot the gateway with your auth credentials*/ } + + public function findPaymentByTxid($txid) + { + return Payment::whereRaw('BINARY `transaction_reference` LIKE ?', ["%txid: " . $txid])->firstOrFail(); + } + + + + /* Returns an array of gateway types for the payment gateway */ + public function gatewayTypes(): array + { + $types = []; + + $types[] = GatewayType::CRYPTO; + + return $types; + } + + public function setPaymentMethod($payment_method_id) + { + $class = self::$methods[$payment_method_id]; + $this->payment_method = new $class($this); + return $this; + } + + public function processPaymentView(array $data) + { + return $this->payment_method->paymentView($data); //this is your custom implementation from here + } + + public function processPaymentResponse($request) + { + return $this->payment_method->paymentResponse($request); + } + + public function processWebhookRequest() + { + // TODO: Figure out why init does not work + $this->init(); + $secret = $this->callback_secret; + //Match secret for security + if ($_GET['secret'] != $secret) { + echo "Invalid Secret"; + return; + } + + $txid = $_GET['txid']; + $value = $_GET['value']; + $status = $_GET['status']; + $addr = $_GET['addr']; + + // Only accept confirmed transactions + if ($status != 2) { + throw new PaymentFailed('Transaction not confirmed'); + } + + $payment = $this->findPaymentByTxid($txid); + // $payment_hash = $this->findPaymentHashInTransactionReference($payment->transaction_reference); + + switch ($status) { + case 0: + $statusId = Payment::STATUS_PENDING; + break; + case 1: + $statusId = Payment::STATUS_PENDING; + break; + case 2: + $statusId = Payment::STATUS_COMPLETED; + break; + } + + // Save the updated payment status + if ($payment->status_id != $statusId) { + $payment->status_id = $statusId; + $payment->save(); + } + + header('HTTP/1.1 200 OK'); + echo 'SUCCESS'; + return; + } + + + public function refund(Payment $payment, $amount, $return_client_response = false) + { + $this->setPaymentMethod(GatewayType::CRYPTO); + return $this->payment_method->refund($payment, $amount); //this is your custom implementation from here + } +} + + // public function doCurlCall($url, $post_content = '') // { // $ch = curl_init(); @@ -109,93 +201,4 @@ class BlockonomicsPaymentDriver extends BaseDriver // // Return null if no match is found // return null; // } - // } - - public function findPaymentByTxid($txid) - { - return Payment::whereRaw('BINARY `transaction_reference` LIKE ?', ["%txid: " . $txid])->firstOrFail(); - } - - - - /* Returns an array of gateway types for the payment gateway */ - public function gatewayTypes(): array - { - $types = []; - - $types[] = GatewayType::CRYPTO; - - return $types; - } - - public function setPaymentMethod($payment_method_id) - { - $class = self::$methods[$payment_method_id]; - $this->payment_method = new $class($this); - return $this; - } - - public function processPaymentView(array $data) - { - return $this->payment_method->paymentView($data); //this is your custom implementation from here - } - - public function processPaymentResponse($request) - { - return $this->payment_method->paymentResponse($request); - } - - public function processWebhookRequest() - { - // TODO: Figure out why init does not work - // $this->init(); - // $secret = $this->company_gateway->getConfigField('callbackSecret'); - // //Match secret for security - // if ($_GET['secret'] != $secret) { - // echo "Invalid Secret"; - // return; - // } - - $txid = $_GET['txid']; - $value = $_GET['value']; - $status = $_GET['status']; - $addr = $_GET['addr']; - - // Only accept confirmed transactions - if ($status != 2) { - throw new PaymentFailed('Transaction not confirmed'); - } - - $payment = $this->findPaymentByTxid($txid); - // $payment_hash = $this->findPaymentHashInTransactionReference($payment->transaction_reference); - - switch ($status) { - case 0: - $statusId = Payment::STATUS_PENDING; - break; - case 1: - $statusId = Payment::STATUS_PENDING; - break; - case 2: - $statusId = Payment::STATUS_COMPLETED; - break; - } - - // Save the updated payment status - if ($payment->status_id != $statusId) { - $payment->status_id = $statusId; - $payment->save(); - } - - header('HTTP/1.1 200 OK'); - echo 'SUCCESS'; - return; - } - - - public function refund(Payment $payment, $amount, $return_client_response = false) - { - $this->setPaymentMethod(GatewayType::CRYPTO); - return $this->payment_method->refund($payment, $amount); //this is your custom implementation from here - } -} + // } \ No newline at end of file diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index 964b81864909..84ba32556b4e 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -25,11 +25,11 @@ class PaymentLibrariesSeeder extends Seeder Model::unguard(); $callbackSecret = md5(uniqid(rand(), true)); - $callbackUrl = config('ninja.app_url') . "/api/v1/blockonomics/callback/?secret=$callbackSecret"; + $callbackUrl = config('ninja.app_url') . '/api/v1/blockonomics/callback/?secret=' . $callbackSecret; $blockonomics_fields = "{ - \"apiKey\": \"\", + \"apiKey\": \"PleaseEnterYourApiKeyHere\", \"callbackUrl\": \"$callbackUrl\", - \"callbackSecret\": \"$callbackSecret\", + \"callbackSecret\": \"$callbackSecret\" }"; @@ -98,7 +98,7 @@ class PaymentLibrariesSeeder extends Seeder ['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'], ['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], ['id' => 63, 'name' => 'Rotessa', 'is_offsite' => false, 'sort_order' => 22, 'provider' => 'Rotessa', 'key' => '91be24c7b792230bced33e930ac61676', 'fields' => '{"apiKey":"", "testMode":""}'], - ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => "$blockonomics_fields"], + ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => $blockonomics_fields], ]; foreach ($gateways as $gateway) { diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index baf8bc44ac71..ca6030019cfa 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -21,7 +21,7 @@ ') }}" class="icon" alt="Copy Icon">
-
+
@@ -163,6 +163,10 @@ transform: translateY(-50%); cursor: pointer; } + .icon-refresh::before { + content: '\e903'; + cursor: pointer; + } /* .progress-message { display: none; margin: 90px 0; From 191388951176725162b5adaaefb7d853092c5a8d Mon Sep 17 00:00:00 2001 From: cnohall Date: Wed, 11 Sep 2024 12:37:41 +0900 Subject: [PATCH 34/59] remove apikey placeholder --- database/seeders/PaymentLibrariesSeeder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index 84ba32556b4e..e052bb087ee6 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -27,7 +27,7 @@ class PaymentLibrariesSeeder extends Seeder $callbackSecret = md5(uniqid(rand(), true)); $callbackUrl = config('ninja.app_url') . '/api/v1/blockonomics/callback/?secret=' . $callbackSecret; $blockonomics_fields = "{ - \"apiKey\": \"PleaseEnterYourApiKeyHere\", + \"apiKey\": \"\", \"callbackUrl\": \"$callbackUrl\", \"callbackSecret\": \"$callbackSecret\" }"; @@ -98,7 +98,7 @@ class PaymentLibrariesSeeder extends Seeder ['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'], ['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], ['id' => 63, 'name' => 'Rotessa', 'is_offsite' => false, 'sort_order' => 22, 'provider' => 'Rotessa', 'key' => '91be24c7b792230bced33e930ac61676', 'fields' => '{"apiKey":"", "testMode":""}'], - ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => $blockonomics_fields], + ['id' => 64, 'name' => 'Blockonomics', 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => "$blockonomics_fields"], ]; foreach ($gateways as $gateway) { From 9044f3239ce9f35332bc7d972efbc3c2fdd51e3f Mon Sep 17 00:00:00 2001 From: cnohall Date: Wed, 11 Sep 2024 13:00:25 +0900 Subject: [PATCH 35/59] restructure UI --- .../gateways/blockonomics/pay.blade.php | 65 ++++++++++--------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index ca6030019cfa..e708d8dc9d0d 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -11,17 +11,20 @@
-->
Invoice #{{$invoice_number}}
-
To pay, send exactly this BTC amount
-
- {{$btc_amount}} BTC ≈ {{$amount}} {{$currency}} - ') }}" class="icon" alt="Copy Icon"> -
-
To this bitcoin address
-
- - ') }}" class="icon" alt="Copy Icon"> -
-
+
To pay, send bitcoin to this address:
+ + + ') }}" class="icon" alt="Copy Icon"> + +
Amount of bitcoin (BTC) to send:
+ +
+ {{$btc_amount}} +
+ ') }}" class="icon" alt="Copy Icon"> + +
+ 1 BTC = {{$amount}} {{$currency}}, updates in
@@ -39,25 +42,27 @@ @@ -130,7 +135,6 @@ margin-bottom: 20px; } .blockonomics-payment-wrapper { - padding: 12px; display: flex; justify-content: center; } @@ -138,13 +142,19 @@ justify-content: center; display: flex; flex-direction: column; - align-items: center; + text-align: center; padding: 12px; } + .input-wrapper { + display: flex; + justify-content: center; + align-items: center; + flex-direction: row; + } .full-width-input { width: 100%; - margin: 10px 0; - padding: 10px 40px 10px 10px; + margin: 10px; + padding: 10px; text-align: center; border: 1px solid #ccc; border-radius: 5px; @@ -152,20 +162,13 @@ cursor: pointer; position: relative; } - .input-wrapper { - position: relative; - width: 100%; - } .icon { - position: absolute; - right: 10px; - top: 50%; - transform: translateY(-50%); cursor: pointer; } .icon-refresh::before { - content: '\e903'; + content: '\27F3'; cursor: pointer; + margin-left: 5px; } /* .progress-message { display: none; From 34830bc9abe3f29c83838468c6d83d554f708096 Mon Sep 17 00:00:00 2001 From: cnohall Date: Wed, 11 Sep 2024 17:07:43 +0900 Subject: [PATCH 36/59] update UI and make refreshing price possible --- .../Gateways/BlockonomicsController.php | 32 +++++ .../Blockonomics/Blockonomics.php | 4 +- .../gateways/blockonomics/pay.blade.php | 134 ++++++++++++++---- routes/api.php | 2 + tests/cypress/support/routes.json | 9 ++ 5 files changed, 154 insertions(+), 27 deletions(-) create mode 100644 app/Http/Controllers/Gateways/BlockonomicsController.php diff --git a/app/Http/Controllers/Gateways/BlockonomicsController.php b/app/Http/Controllers/Gateways/BlockonomicsController.php new file mode 100644 index 000000000000..5f451a49c0fb --- /dev/null +++ b/app/Http/Controllers/Gateways/BlockonomicsController.php @@ -0,0 +1,32 @@ +query('currency'); + $response = Http::get("https://www.blockonomics.co/api/price?currency={$currency}"); + + if ($response->successful()) { + return response()->json(['price' => $response->json('price')]); + } + + return response()->json(['error' => 'Unable to fetch BTC price'], 500); + } +} \ No newline at end of file diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 3da7a37815a9..13c40fbd12d4 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -111,10 +111,12 @@ class Blockonomics implements MethodInterface $data['gateway'] = $this->blockonomics; $data['amount'] = $data['total']['amount_with_fee']; $data['currency'] = $this->blockonomics->client->getCurrencyCode(); - $btc_amount = $data['amount'] / $this->getBTCPrice(); + $btc_price = $this->getBTCPrice(); + $btc_amount = $data['amount'] / $btc_price; $data['btc_amount'] = number_format($btc_amount, 10, '.', ''); $btc_address = $this->getBTCAddress(); $data['btc_address'] = $btc_address; + $data['btc_price'] = $btc_price; $data['invoice_id'] = $_invoice->invoice_id; $data['invoice_number'] = $_invoice->invoice_number; $data['end_time'] = $this->getTenMinutesCountDownEndTime(); diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index e708d8dc9d0d..029f12c681e2 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -10,21 +10,24 @@ The invoice will be marked as paid automatically once the payment is confirmed.
-->
-
Invoice #{{$invoice_number}}
-
To pay, send bitcoin to this address:
+
+
Invoice #{{$invoice_number}}
+
{{$amount}} {{$currency}}
+
+ To pay, send bitcoin to this address: - - ') }}" class="icon" alt="Copy Icon"> + + ') }}" class="icon" alt="Copy Icon"> -
Amount of bitcoin (BTC) to send:
+ Amount of bitcoin (BTC) to send: -
+
{{$btc_amount}}
') }}" class="icon" alt="Copy Icon"> - + - 1 BTC = {{$amount}} {{$currency}}, updates in +
1 BTC = {{$btc_price}} {{$currency}}, updates in
@@ -41,19 +44,22 @@ + + + + - - @endsection - From cfe26d06ecab374472e5ca55adb85ad764c43f98 Mon Sep 17 00:00:00 2001 From: cnohall Date: Fri, 13 Sep 2024 12:26:22 +0900 Subject: [PATCH 41/59] clean up functions --- .../Blockonomics/Blockonomics.php | 31 +++++++------------ .../gateways/blockonomics/pay.blade.php | 8 +++-- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/app/PaymentDrivers/Blockonomics/Blockonomics.php b/app/PaymentDrivers/Blockonomics/Blockonomics.php index 408b5b6b319d..46519b9f961c 100644 --- a/app/PaymentDrivers/Blockonomics/Blockonomics.php +++ b/app/PaymentDrivers/Blockonomics/Blockonomics.php @@ -83,13 +83,6 @@ class Blockonomics implements MethodInterface return "Something went wrong"; } - public function getTenMinutesCountDownEndTime() - { - $duration_in_sec = 10 * 60; // 10 minutes in seconds - $current_time = time(); - return $current_time + $duration_in_sec; - } - public function getBTCPrice() { $currency_code = $this->blockonomics->client->getCurrencyCode(); @@ -103,22 +96,19 @@ class Blockonomics implements MethodInterface public function paymentView($data) { + $btc_price = $this->getBTCPrice(); + $btc_address = $this->getBTCAddress(); + $fiat_amount = $data['total']['amount_with_fee']; + $btc_amount = $fiat_amount / $btc_price; $_invoice = collect($this->blockonomics->payment_hash->data->invoices)->first(); $data['gateway'] = $this->blockonomics; - $data['amount'] = $data['total']['amount_with_fee']; + $data['company_gateway_id'] = $this->blockonomics->getCompanyGatewayId(); + $data['amount'] = $fiat_amount; $data['currency'] = $this->blockonomics->client->getCurrencyCode(); - $btc_price = $this->getBTCPrice(); - $btc_amount = $data['amount'] / $btc_price; $data['btc_amount'] = number_format($btc_amount, 10, '.', ''); - $btc_address = $this->getBTCAddress(); $data['btc_address'] = $btc_address; $data['btc_price'] = $btc_price; - $data['invoice_id'] = $_invoice->invoice_id; $data['invoice_number'] = $_invoice->invoice_number; - $data['end_time'] = $this->getTenMinutesCountDownEndTime(); - $data['invoice_redirect_url'] = "/client/invoices/{$_invoice->invoice_id}"; - - $data['websocket_url'] = 'wss://www.blockonomics.co/payment/' . $btc_address; return render('gateways.blockonomics.pay', $data); } @@ -129,16 +119,19 @@ class Blockonomics implements MethodInterface 'payment_hash' => ['required'], 'amount' => ['required'], 'currency' => ['required'], + 'txid' => ['required'], + 'payment_method_id' => ['required'], ]); try { $data = []; - $data['amount'] = $request->amount; + $fiat_amount = $request->btc_price * $request->btc_amount; + $data['amount'] = $fiat_amount; + $data['currency'] = $request->currency; $data['payment_method_id'] = $request->payment_method_id; $data['payment_type'] = PaymentType::CRYPTO; $data['gateway_type_id'] = GatewayType::CRYPTO; - $data['transaction_reference'] = "payment hash: " . $request->payment_hash . " txid: " . $request->txid; - $data['txid'] = $request->txid; + $data['transaction_reference'] = "payment hash: " . $request->payment_hash . " txid: " . $request->txid . " BTC amount: " . $request->btc_amount; $statusId = Payment::STATUS_PENDING; $payment = $this->blockonomics->createPayment($data, $statusId); diff --git a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php index d6b228463a32..34832f228a0c 100644 --- a/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/blockonomics/pay.blade.php @@ -43,10 +43,11 @@
@csrf - + + @@ -54,7 +55,7 @@