niush / laravel-nano-to
Nano.to Payment Gateway in Laravel
Requires
- php: ^7.2|^8.0
- guzzlehttp/guzzle: ^7.3
- illuminate/support: ^6.0|^7.0|^8.0|^9.0
Requires (Dev)
- orchestra/testbench: ^7.0
- phpunit/phpunit: ^9.0
README
Easily integrate Nano.to Payment Gateway in Laravel Application, with full control.
Installation on Laravel
You can install the package via composer:
composer require niush/laravel-nano-to
Then publish the config file using artisan.
php artisan vendor:publish --provider="Niush\NanoTo\NanoToServiceProvider"
Update config file (config/nano-to.php
) with your desired settings. Use env
where ever required.
Configuration
Add Nano Webhook Secret in your env file. Make sure it is difficult to guess with random string. DO NOT USE SAME AS APP_ENV.
NANO_WEBHOOK_SECRET=
Go through the generated config file and update as required. Make sure the Nano address all belongs to you and is accessible. You can provide, default title and description.
Required Named Routes
For this to work properly, you must have these 3 named routes created to handle your business logic. The named route can always be customized in config file.
-
nano-to-success
: Redirected when Payment is successful. Do not confirm the payment using this route. The confirmation must be handled in webhook url.Route::get('/order/success/{id}', [OrderController::class, 'success'])->name('nano-to-success'); // E.g. Shows a static order success page.
-
nano-to-cancel
: Redirected when Payment is canceled, using back button. Useful to redirect back to cart page etc.Route::get('/order/cancel/{id}', [OrderController::class, 'cancel'])->name('nano-to-cancel'); // E.g. Redirects back to Cart Page
-
nano-to-webhook
: The POST route that is called by Nano.to when the payment is successfully processed. The request contains payment information, hash, webhook secret in headers. More information can be found down below.// PERFORM PAYMENT CONFIRMED BUSINESS LOGIC Route::post('/order/webhook/{id}', [OrderController::class, 'webhook'])->name('nano-to-webhook');
Using Full Route Instead:
By default the config accepts named route for webhook and success page. If you want to use full route, for cases like different domain and backend to handle webhook or success page. You can update the config files success_url
, cancel_url
and webhook_url
to be a full URL with domain name.
As, you have full control, it can easily be implemented via APIs also.
Usage
NOTE: Amount is always in USD Currency.
For initiating Payment process:
// 1) With Specific Amount return NanoTo::amount(10)->create($order->id, function($checkout_url) { // Do Something with $checkout_url if required. // For SPA send link as JSON response etc. })->send(); // 2) With Custom Info (Else uses title and description from config) return NanoTo::info("Payment for Subscription", "<i>Also accepts HTML</i>") ->amount(9.99) ->create($order->id)->send(); // 3) With Additional Metadata (Can be received in Webhook) return NanoTo::amount(9.99)->metadata([ "user_id" => $user->id, "order_id" => $order->id ])->create($order->id)->send(); // 4) For Suggest based payment. Useful in cases like Donation. return NanoTo::info("Donate Us") ->suggest([ ["name" => "Coffee", "price" => "10"], ["name" => "Meal", "price" => "50"] ]) ->create($uuid)->send(); // 5) Use RAW friendly Amount in QR Codes (e.g. for Natrium) return NanoTo::asRaw()->amount(9.99)->create($order->id)->send(); // 6) With Custom Image in Checkout page return NanoTo::withImage("full_url_of_image")->amount(9.99)->create($order->id)->send(); // 7) Or Simply, if no need to track anything. And, required routes do not need {id} param. return NanoTo::create(); // Receiving Nano Address will randomly be picked from config file. // The first parameter of create (e.g. $order->id) will be used as params in named routes.
You might want to use custom Webhook Secret. So that, it is always different for each checkout. So, instead of using same environment variable. You can do:
return NanoTo::amount(10)->secret( config("nano-to.webhook_secret") . $order->secret_id . $user->id )->create($order->id)->send();
Webhook Response Example
// Request Headers { "Accept": "application/json, text/plain, */*", "Connection": "close", "Content-Length": "1005", "Content-Type": "application/json", "Webhook-Secret": "XXXXXXXXXXXXXXXX" }
// You can get the Header and compare with your config secret. In Webhook Controller: $request->header('Webhook-Secret') == config("nano-to.webhook_secret") // Valid
// Request Body (JSON) { "id": "ffceexxxxxx", // Transaction ID of Nano.to "status": "complete", // Status must be complete "amount": "10", // Amount in USD "method": { "symbol": "nano", // Crypto Currency Used "address": "nano_3gxhq...", // Receiving Address "name": "Nano", "rate": "5.589960", // Currency Rate (Nano → USD) "amount": "1.788115", // Nano Received "value": "0.01", "raw": false }, "plan": { // If using Suggest mode "price": 10, "name": "Meal" }, "block": { // Block Information "type": "receive", // You must be receiving :) "representative": "nano_3chart...", "balance": "3.726479", "previous": "1922BFA40E86C....", "account": "nano_36qn7ydq...", // Sender Address "amount": "1.788115", // Nano Received "height": "37", "hash": "9829B0306E5269A9A0...", // Transaction Identifier (Most important piece to store.) "work": "210862fa...", "timestamp": "16319544..", "amount_raw": "1788115000000000000..." // RAW Nano "balance_raw": "372647920414...", "from": "nano_36qn7ydq..." "to": "nano_3gxhq..." "message": "" }, "metadata": { // All Additional Metadata sent "user_id": "my_meta" } }
// Compare the body, store required info in DB and finally update the order status. In Webhook Controller. $request->input('amount') == $order->amount_in_usd; $request->input('status') == "complete"; $request->input('block.type') == "receive"; // You can also compare receiver address is in config or not. $order->via = "nano"; $order->hash = $request->input('block.hash'); $order->status = "complete"; $order-save();
Full Example of Webhook Controller
Click to expand!
public function webhook(Request $request, Order $order) { if($request->header('Webhook-Secret') != config("nano-to.webhook_secret")) { $order->status = "failed"; // Webhook Secret is MALFORMED $order->remarks = "Payment Verification Malformed"; } else { if( $request->input('amount') == $order->amount_in_usd && $request->input('status') == "complete" && $request->input('block.type') == "receive" && $request->input('block.hash') ) { $order->status = "complete"; $order->hash = $request->input('block.hash'); $order->remarks = "Payment Complete from Address: " . $request->input('block.account') . " , with Amount: " . $request->input('method.amount'); $order->save(); } else { $order->status = "failed"; // Payment Amount is not correct or not complete etc. $order->remarks = "Payment Was Not Fully Completed"; } } // You can also utilize Metadata for verification: // $request->input('metadata.user_id') == $order->user_id; $order->save(); return ["success" => true]; }
Advanced Usage (API / Helpers)
View details and response here
use Niush\NanoTo\NanoToApi; // 1) Get CoinMarketCap conversion rate NanoToApi::getPrice("NANO", "USD"); NanoToApi::getPrice("XMR", "NPR"); NanoToApi::getPrice("NANO", "XMR"); // 2) Get Nano.to Custom Username alias information NanoToApi::getUsername("moon"); // 3) Get Nano Address Information (OR Nano.to alias info) NanoToApi::getNanoAddressInfo("nano_3xxxx"); // 4) Get Total Nano Balance from all nano address provided in config file NanoToApi::getTotalNanoBalance(); // 5) Get Pending Nano Blocks NanoToApi::getPendingNanoBlocks("nano_3xxxx"); // 6) Get Last 50+ Block History NanoToApi::getNanoAddressHistory("nano_3xxxx"); // 7) Get Nano Transaction by specific Amount (Amount must be in Nano decimal format) NanoToApi::getNanoTransactionByAmount("nano_3xxxx", "2.101"); // 8) Get Nano Transaction by block HASH NanoToApi::getNanoTransactionByHash("NANO_HASH"); // 9) Get JSON Representation of given checkout URL. Only has 12 hour lifespan. NanoToApi::getCheckoutUrlAsJson("https://nano.to/checkout/xxx"); // 10) Get List Of Public Representatives for Nano. And, Search by first parameter. NanoToApi::getListOfPublicRepresentatives("ninja"); // 11) Get List Of Nano.to known Usernames. And, Search by first parameter. NanoToApi::getListOfNanoUsernames("esteban"); // 12) Check if nanocrawler is down or unreachable. Returns boolean true if down. NanoToApi::isNanoCrawlerDown(); // 13) Check if Nano.to base_url is down or unreachable. Returns boolean true if down. NanoToApi::isNanoToDown();
Translation
Add translation for these messages if required.
nano-to.checkout-page-not-loaded
= "Unable to load Checkout Page."nano-to.no-receiver
= "Receiver Account was not available."
Testing
Contributions are welcome.
composer test
Changelog
Please see CHANGELOG for more information what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email author instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.
Nano.to is a product of Forward Miami, LLC. ⚡
Help me with Nano?
-
What is Nano?
Nano is a Fee-less, Eco-friendly, Instant digital money for the modern world.
-
How to verify or view block information of my transaction?
Show Support
nano_378shkx4k3wd5gxmj3xnjwuxtaf9xrehyz7ugakpiemh8arxq8w9a9xniush