Skip to content

Commit

Permalink
Initial commit, working release.
Browse files Browse the repository at this point in the history
  • Loading branch information
ndeet committed Jun 30, 2021
0 parents commit 51bf5bc
Show file tree
Hide file tree
Showing 5 changed files with 801 additions and 0 deletions.
136 changes: 136 additions & 0 deletions includes/ElementsClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

/**
* Implements a small subset of Elements RPC methods.
*
* @see https://elementsproject.org/en/doc/0.18.1.11/rpc/
*/
class ElementsClient {

protected $host;

protected $payload = [];

protected $args = [];

/**
* ElementsClient constructor.
*
* @param $rpcHost
* @param $rpcUser
* @param $rpcPass
*
* @throws Exception
*/
public function __construct($rpcHost, $rpcUser, $rpcPass) {
if (empty($rpcHost) || empty($rpcUser) || empty($rpcPass)) {
throw new \Exception("RPC Error: Make sure you configured all RPC credentials.");
}

$this->host = $rpcHost;

$this->args = [
'headers' => [
'Authorization' => 'Basic ' . base64_encode( "$rpcUser:$rpcPass" )
],
'timeout' => 20,
];

$this->payload = [
'jsonrpc' => '1.0',
'id' => 'wcla',
'method' => '',
'params' => []
];

}

/**
* Sends the RPC call to the elements RPC host.
*
* @return mixed
* @throws Exception
*/
public function send() {
// check if all data there
if (empty($this->payload['method'])) {
throw new \Exception('No elements RPC method called, aborting.');
}

// Prepare data structure, merge payload to args.
$this->args['body'] = json_encode($this->payload);

$response = wp_remote_post( $this->host, $this->args );

if (is_wp_error( $response )) {
throw new \Exception($response->get_error_message());
}

$response_code = wp_remote_retrieve_response_code( $response );
if ( $response_code !== 200) {
$response_data = json_decode(wp_remote_retrieve_body( $response ));
$error = '';
if (!empty($response_data->error)) {
$error = "({$response_data->error->code}) {$response_data->error->message}";
}
if (empty($error) && !empty($response['response']['message'])) {
$error = "({$response_code}) {$response['response']['message']}";
}
throw new \Exception('RPC error: ' . $error, $response_code);
}
return json_decode(wp_remote_retrieve_body( $response ));
}

/**
* Calls RPC getbalance method.
*
* @param string|null $assetId
* Liquid asset ID.
* @param int $minConf
* Minimum number of confirmations, defaults to 1.
*
* @return $this
*
* @see https://elementsproject.org/en/doc/0.18.1.11/rpc/wallet/getbalance/
*/
public function getBalance( $assetId = null, $minConf = 1) {
$this->payload['method'] = 'getbalance';
$this->payload['params'] = [ '*', $minConf, false, $assetId ];
return $this;
}

/**
* Calls RPC validateAddress method.
*
* @param $address
*
* @return $this
*
* @see https://elementsproject.org/en/doc/0.18.1.11/rpc/util/validateaddress/
*/
public function validateAddress( $address ) {
$this->payload['method'] = 'validateaddress';
$this->payload['params'] = [ $address ];
return $this;
}

/**
* Calls RPC sendToAddress method to send assets.
*
* @param string $address
* @param string $amount
* @param string $assetId
*
* @return $this
*
* @see https://elementsproject.org/en/doc/0.18.1.11/rpc/wallet/sendtoaddress/
*/
public function sendToAddress( $address, $amount, $assetId ) {
// Internally elements handles 1 token as 1 satoshi, e.g. 0.00000001
$amount = $amount * 0.00000001;
$this->payload['method'] = 'sendtoaddress';
$this->payload['params'] = [ $address, number_format($amount,8,'.',''), '', '', false, true, 1, 'UNSET', $assetId ];
return $this;
}

}
125 changes: 125 additions & 0 deletions includes/wcla-admin-settings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}

/**
* Add Liquid Assets settings page menu entry.
*/
function wcla_add_settings_page() {
add_submenu_page( 'woocommerce', 'Woocommerce Liquid Assets Settings', 'Liquid Assets Settings', 'manage_options', 'wcla-settings', 'wcla_render_settings_page' );
}
add_action( 'admin_menu', 'wcla_add_settings_page', 99 );

/**
* Render Liquid Assets settings page output.
*/
function wcla_render_settings_page() {
?>
<h2>Woocommerce Liquid Assets Settings</h2>
<form action="options.php" method="post">
<?php
settings_fields( 'wcla_plugin_options' );
do_settings_sections( 'wcla_plugin' ); ?>
<input name="submit" class="button button-primary" type="submit" value="<?php esc_attr_e( 'Save' ); ?>" />
</form>
<?php
}

/**
* Register Liquid Assets plugin options and fields.
*/
function wcla_register_settings() {
register_setting( 'wcla_plugin_options', 'wcla_plugin_options' );
// Switch to choose between coinos.io or Elements node RPC.
add_settings_section( 'general', 'General', 'wcla_plugin_general_section_text', 'wcla_plugin' );
add_settings_field( 'wcla_plugin_setting_mode', 'Active configuration', 'wcla_plugin_setting_mode', 'wcla_plugin', 'general' );
add_settings_field( 'wcla_plugin_setting_admin_mails', 'Admin notification mails', 'wcla_plugin_setting_admin_mails', 'wcla_plugin', 'general' );

// coinos.io settings.
add_settings_section( 'api_settings', 'Coinos.io API Settings', 'wcla_plugin_coinos_section_text', 'wcla_plugin' );
add_settings_field( 'wcla_plugin_setting_coinos_api_key', 'API Key (JWT token)', 'wcla_plugin_setting_coinos_api_key', 'wcla_plugin', 'api_settings' );
// Elements Node RPC settings.
add_settings_section( 'rpc_settings', 'Elements node RPC Settings', 'wcla_plugin_rpc_section_text', 'wcla_plugin' );
add_settings_field( 'wcla_plugin_setting_rpc_host', 'RPC Host', 'wcla_plugin_setting_rpc_host', 'wcla_plugin', 'rpc_settings' );
add_settings_field( 'wcla_plugin_setting_rpc_user', 'RPC User', 'wcla_plugin_setting_rpc_user', 'wcla_plugin', 'rpc_settings' );
add_settings_field( 'wcla_plugin_setting_rpc_pass', 'RPC Password', 'wcla_plugin_setting_rpc_pass', 'wcla_plugin', 'rpc_settings' );
}
add_action( 'admin_init', 'wcla_register_settings' );

/**
* Callback to render the settings section text.
*/
function wcla_plugin_general_section_text() {
echo '<p>Select which settings should be active and add emails that get notified in case of an error.</p>';
}

/**
* Callback to render settings mode dropdown.
*/
function wcla_plugin_setting_mode() {
$selected_option = get_option( 'wcla_plugin_options' )['wcla_plugin_setting_mode'];
$items = [
'coinos' => 'coinos.io API',
'elements' => 'Elements RPC',
];
echo "<select id='wcla_plugin_setting_mode' name='wcla_plugin_options[wcla_plugin_setting_mode]'>";
foreach ( $items as $id => $value ) {
$selected = ( $selected_option == $id ) ? 'selected="selected"' : '';
echo "<option value='$id' $selected>$value</option>";
}
echo "</select>";
}

/**
* Callback to render the admin emails text input field.
*/
function wcla_plugin_setting_admin_mails() {
echo "<input id='wcla_plugin_setting_admin_mails' name='wcla_plugin_options[admin_mails]' type='text' size='120' value='" . esc_attr( get_option( 'wcla_plugin_options' )['admin_mails'] ) . "' />";
echo "<p>Enter a single or comma separated list of emails to get notifications on errors. e.g. [email protected],[email protected]</p>";
}

/**
* Callback to render the settings section text.
*/
function wcla_plugin_coinos_section_text() {
echo '<p>Put your <a href="https://coinos.io" target="_blank">coinos.io</a> API settings here. Leave empty if you want to use Elements node RPC settings below.</p>';
}

/**
* Callback to render the coinos.io API key text input field.
*/
function wcla_plugin_setting_coinos_api_key() {
echo "<input id='wcla_plugin_setting_coinos_api_key' name='wcla_plugin_options[coinos_api_key]' type='text' size='120' value='" . esc_attr( get_option( 'wcla_plugin_options' )['coinos_api_key'] ) . "' />";
}

/**
* Callback to render the rpc settings section text.
*/
function wcla_plugin_rpc_section_text() {
echo '<p>Enter your Elements node RPC settings to communicate directly with your node.</p>';
echo '<p>Please make sure the nodes wallet has enough funds for the configured product assets and L-BTC for the fees.</p>';
}

/**
* Callback to render the rpc host text input field.
*/
function wcla_plugin_setting_rpc_host() {
echo "<input id='wcla_plugin_setting_rpc_host' name='wcla_plugin_options[rpc_host]' type='text' size='60' value='" . esc_attr( get_option( 'wcla_plugin_options' )['rpc_host'] ) . "' />";
echo "<p>e.g. https://rpc.somehost.tld:7041/</p>";
}

/**
* Callback to render the rpc user text input field.
*/
function wcla_plugin_setting_rpc_user() {
echo "<input id='wcla_plugin_setting_rpc_user' name='wcla_plugin_options[rpc_user]' type='text' size='60' value='" . esc_attr( get_option( 'wcla_plugin_options' )['rpc_user'] ) . "' />";
}

/**
* Callback to render the rpc user text input field.
*/
function wcla_plugin_setting_rpc_pass() {
echo "<input id='wcla_plugin_setting_rpc_pass' name='wcla_plugin_options[rpc_pass]' type='text' size='60' value='" . esc_attr( get_option( 'wcla_plugin_options' )['rpc_pass'] ) . "' />";
}
8 changes: 8 additions & 0 deletions license.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Copyright 2021 Andreas Tasch

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

90 changes: 90 additions & 0 deletions readme.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
=== WooCommerce Liquid Assets ===

Contributors: ndeet
Tags: WooCommerce, Liquid Network, Bitcoin, cryptocurrency
Requires at least: 4.9
Tested up to: 5.7
Requires PHP: 7.3
Stable tag: 1.7
License: MIT

Configure your products to reference your own Liquid Assets. The plugin will send Liquid Assets (coinos.io and your Elements RPC node supported) to customers after successful payment.


== Description ==

With this plugin you are able to sell your own special Liquid Assets to customers [(learn more about Liquid Network)](https://help.blockstream.com/hc/en-us/articles/900001543146-What-are-Liquid-assets-). Which they can then later use to pay for a product using [BTCPay Server WooCommerce plugin](https://wordpress.org/plugins/btcpay-for-woocommerce/). Think of it like a voucher or gift card.

You can configure Liquid Asset relationship on a per product basis and during checkout the user will be asked to enter their Liquid address. After payment has been completed the token will be sent to the user through coinos.io or your own Elements node.

= Plugin Configuration =
go to WooCommerce -> Liquid Assets Settings

**General:**
choose Elements RPC or coinos.io mode (depending on that continue with the matching section)
Enter the email recipients that should receive notifications in case of errors on either RPC or coinos mode. You can enter one or more separated by comma.

**Coinos.io:**
add your coinos.io API key (JWT token) here (can be found on coinos.io profile settings page)

**Elements RPC:**
RPC Host: enter the host or proxy accepting Elements RPC requests
RPC User: the configured RPC user (as configured in elements.conf)
RPC Pass: the password (as configured in elements.conf)

= Product configuration =

On the product edit form you have 2 new fields in the “General” data tab:
* **Liquid Asset ID:** enter Liquid Asset ID here you want to send to customer
* **Customer Liquid address:** the text entered here will be shown on the frontend product page as label.

= Product page / Add to cart form (frontend) styling =

If you enter above mentioned new product fields you will now see the label and a input text field on the product page, here the user can add their Liquid address.

The examples here apply for the default WordPress theme “twentytwentyone”. You might also need the following classes to adjust the styling of the input field and label for your custom theme.

**Example:**
`
.wcla-liquid-address-wrapper {
margin-bottom: 30px;
}

.wcla-liquid-address-label {
display: block;
}

input#wcla-liquid-address {
width: 100%;
}
`

= Orders and orders notes =

On the orders line item you will see the users Liquid address in case anything went wrong with the coinos.io API. You will also get some order notes in case there was a problem with coinos.io and their API (or Elements RPC) response was not status 200 OK or the request timed out. If you configured the admin notification mails those recipients will get also emails in case there was an error.

Make also sure your coinos.io account / Elements node has enough funds of Liquid Assets and L-BTC for the fees to send.


== Installation ==

= Minimum Requirements =
* WooCommerce 4.5 or greater
* WordPress 5.2 or greater

= Automatic installation =
This is the easiest option as you can click through everything in the WordPress admin interface. Log in to your WordPress admin panel, navigate to the Plugins menu and click [Add New].

In the search field type "WooCommerce Liquid Assets". You can install it by simply clicking [Install Now]. After clicking that link you will be asked if you're sure you want to install the plugin. Click yes and WordPress will automatically complete the installation. After installation has finished, click the [activate plugin] link.

= Manual installation via the WordPress interface =
1. Download the plugin zip file to your computer
2. Go to the WordPress admin panel menu Plugins > Add New
3. Choose upload
4. Upload the plugin zip file, the plugin will now be installed
5. After installation has finished, click the 'activate plugin' link

= Manual installation via FTP =
1. Download the plugin file to your computer and unzip it
2. Using an FTP program, or your hosting control panel, upload the unzipped plugin folder to your WordPress installation's wp-content/plugins/ directory.
3. Activate the plugin from the Plugins menu within the WordPress admin.
Loading

0 comments on commit 51bf5bc

Please sign in to comment.