diff --git a/Payment/LiqPay.php b/Payment/LiqPay.php
new file mode 100644
index 0000000..b6f3e4e
--- /dev/null
+++ b/Payment/LiqPay.php
@@ -0,0 +1,208 @@
+paymentProfile->options;
+
+ $payment = [
+ 'version' => 3,
+ 'public_key' => $profileOptions['public_key'],
+ 'action' => 'pay',
+ 'amount' => $purchase->cost,
+ 'currency' => $purchase->currency,
+ 'description' => $purchase->title,
+ 'order_id' => $purchaseRequest->request_key,
+
+ 'result_url' => $purchase->returnUrl,
+ 'server_url' => $this->getCallbackUrl(),
+ ];
+
+ return $this->getDataAndSignature($payment, $profileOptions['private_key']);
+ }
+
+ public function initiatePayment(Controller $controller, PurchaseRequest $purchaseRequest, Purchase $purchase): XF\Mvc\Reply\Redirect
+ {
+ $paymentParams = $this->getPaymentParams($purchaseRequest, $purchase);
+
+ return $controller->redirect($this->getApiEndpoint() . '?' . http_build_query($paymentParams));
+ }
+
+ public function setupCallback(Request $request): CallbackState
+ {
+ $state = new CallbackState();
+
+ $state->dataRaw = $request->filter('data', 'str');
+ $state->data = json_decode(base64_decode($state->dataRaw), true);
+ $state->signature = $request->filter('signature', 'str');
+
+ $state->amount = $state->data['amount'] ?? 0;
+ $state->currency = $state->data['currency'] ?? '';
+ $state->status = $state->data['status'] ?? '';
+ $state->subscriberId = $state->data['customer'] ?? 0;
+
+ $state->ip = $request->getIp();
+
+ $state->httpCode = 200;
+
+ return $state;
+ }
+
+ public function validateCallback(CallbackState $state): bool
+ {
+ $state->requestKey = $state->data['order_id'] ?? '';
+ $state->transactionId = $state->input['payment_id'] ?? '';
+
+ if (!empty($state->signature) && $state->data['version'] == 3 && $state->data['action'] == 'pay')
+ {
+ return true;
+ }
+
+ $state->logType = 'info';
+ $state->logMessage = 'Auth failed';
+
+ return false;
+ }
+
+ public function validateTransaction(CallbackState $state): bool
+ {
+ if (!$state->requestKey)
+ {
+ $state->logType = 'info';
+ $state->logMessage = 'Metadata is empty!';
+
+ return false;
+ }
+
+ if(!empty($state->data['err_code']))
+ {
+ $state->logType = 'error';
+ $state->logMessage = $state->data['err_description'] ?? $state->data['err_code'];
+
+ return false;
+ }
+
+ return parent::validateTransaction($state);
+ }
+
+ public function validatePurchasableData(CallbackState $state): bool
+ {
+ $paymentProfile = $state->getPaymentProfile();
+
+ $options = $paymentProfile->options;
+ if (!empty($options['public_key']) && !empty($options['private_key']) && !empty($state->signature))
+ {
+ if ($this->verifySignature($state->dataRaw, $state->signature, $options['private_key']))
+ {
+ return true;
+ }
+
+ $state->logType = 'error';
+ $state->logMessage = "Invalid signature";
+
+ return false;
+ }
+
+ $state->logType = 'error';
+ $state->logMessage = 'Invalid public_key or secret_key.';
+
+ return false;
+ }
+
+ public function validateCost(CallbackState $state): bool
+ {
+ $purchaseRequest = $state->getPurchaseRequest();
+
+ if (($state->currency == $purchaseRequest->cost_currency)
+ && round($state->amount, 2) == round($purchaseRequest->cost_amount, 2))
+ {
+ return true;
+ }
+
+ $state->logType = 'error';
+ $state->logMessage = 'Invalid cost amount.';
+
+ return false;
+ }
+
+ public function getPaymentResult(CallbackState $state): void
+ {
+ if (strtolower($state->status) == 'success')
+ {
+ $state->paymentResult = CallbackState::PAYMENT_RECEIVED;
+ }
+ }
+
+ public function prepareLogData(CallbackState $state): void
+ {
+ $state->logDetails = array_merge($state->data, [
+ 'ip' => $state->ip,
+ 'signature' => $state->signature
+ ]);
+ }
+
+ public function verifyCurrency(PaymentProfile $paymentProfile, $currencyCode): bool
+ {
+ return in_array($currencyCode, $this->supportedCurrencies);
+ }
+
+ protected $supportedCurrencies = [
+ 'RUB', 'USD', 'EUR', 'UAH', 'BYN', 'KZT'
+ ];
+
+ public function supportsRecurring(PaymentProfile $paymentProfile, $unit, $amount, &$result = self::ERR_NO_RECURRING): bool
+ {
+ $result = self::ERR_NO_RECURRING;
+
+ return false;
+ }
+
+ protected function getDataAndSignature(array $payment, string $privateKey): array
+ {
+ $data = base64_encode(json_encode($payment));
+ $signature = base64_encode(hash('sha1', $privateKey . $data . $privateKey, true));
+
+ return [
+ 'data' => $data,
+ 'signature' => $signature
+ ];
+ }
+
+ protected function verifySignature(string $data, string $signature, string $privateKey): bool
+ {
+ return hash_equals($signature, base64_encode(hash('sha1', $privateKey . $data . $privateKey, true)));
+ }
+}
\ No newline at end of file
diff --git a/Setup.php b/Setup.php
new file mode 100644
index 0000000..41567c6
--- /dev/null
+++ b/Setup.php
@@ -0,0 +1,34 @@
+db();
+
+ $db->insert('xf_payment_provider', [
+ 'provider_id' => "wh1LiqPay",
+ 'provider_class' => "WH1\\PaygateLiqPay:LiqPay",
+ 'addon_id' => "WH1/PaygateLiqPay"
+ ]);
+ }
+
+ public function uninstallStep1()
+ {
+ $db = $this->db();
+
+ $db->delete('xf_payment_profile', "provider_id = 'wh1LiqPay'");
+ $db->delete('xf_payment_provider', "provider_id = 'wh1LiqPay'");
+ }
+}
\ No newline at end of file
diff --git a/_data/activity_summary_definitions.xml b/_data/activity_summary_definitions.xml
new file mode 100644
index 0000000..a55af11
--- /dev/null
+++ b/_data/activity_summary_definitions.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/admin_navigation.xml b/_data/admin_navigation.xml
new file mode 100644
index 0000000..8aa506b
--- /dev/null
+++ b/_data/admin_navigation.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/admin_permission.xml b/_data/admin_permission.xml
new file mode 100644
index 0000000..67760e7
--- /dev/null
+++ b/_data/admin_permission.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/advertising_positions.xml b/_data/advertising_positions.xml
new file mode 100644
index 0000000..32059fa
--- /dev/null
+++ b/_data/advertising_positions.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/api_scopes.xml b/_data/api_scopes.xml
new file mode 100644
index 0000000..3510b36
--- /dev/null
+++ b/_data/api_scopes.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/bb_code_media_sites.xml b/_data/bb_code_media_sites.xml
new file mode 100644
index 0000000..bdf7d27
--- /dev/null
+++ b/_data/bb_code_media_sites.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/bb_codes.xml b/_data/bb_codes.xml
new file mode 100644
index 0000000..8c337bf
--- /dev/null
+++ b/_data/bb_codes.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/class_extensions.xml b/_data/class_extensions.xml
new file mode 100644
index 0000000..bd0ad9f
--- /dev/null
+++ b/_data/class_extensions.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/code_event_listeners.xml b/_data/code_event_listeners.xml
new file mode 100644
index 0000000..a9a91ea
--- /dev/null
+++ b/_data/code_event_listeners.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/code_events.xml b/_data/code_events.xml
new file mode 100644
index 0000000..7752d3e
--- /dev/null
+++ b/_data/code_events.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/content_type_fields.xml b/_data/content_type_fields.xml
new file mode 100644
index 0000000..3040a1f
--- /dev/null
+++ b/_data/content_type_fields.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/cron.xml b/_data/cron.xml
new file mode 100644
index 0000000..b45f056
--- /dev/null
+++ b/_data/cron.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/help_pages.xml b/_data/help_pages.xml
new file mode 100644
index 0000000..31828b1
--- /dev/null
+++ b/_data/help_pages.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/member_stats.xml b/_data/member_stats.xml
new file mode 100644
index 0000000..a80a38b
--- /dev/null
+++ b/_data/member_stats.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/navigation.xml b/_data/navigation.xml
new file mode 100644
index 0000000..752ce9a
--- /dev/null
+++ b/_data/navigation.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/option_groups.xml b/_data/option_groups.xml
new file mode 100644
index 0000000..b453ed4
--- /dev/null
+++ b/_data/option_groups.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/options.xml b/_data/options.xml
new file mode 100644
index 0000000..140bd10
--- /dev/null
+++ b/_data/options.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/permission_interface_groups.xml b/_data/permission_interface_groups.xml
new file mode 100644
index 0000000..87ad617
--- /dev/null
+++ b/_data/permission_interface_groups.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/permissions.xml b/_data/permissions.xml
new file mode 100644
index 0000000..16b1408
--- /dev/null
+++ b/_data/permissions.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/phrases.xml b/_data/phrases.xml
new file mode 100644
index 0000000..8c2b1c0
--- /dev/null
+++ b/_data/phrases.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/_data/routes.xml b/_data/routes.xml
new file mode 100644
index 0000000..608d809
--- /dev/null
+++ b/_data/routes.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/style_properties.xml b/_data/style_properties.xml
new file mode 100644
index 0000000..231b9f0
--- /dev/null
+++ b/_data/style_properties.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/style_property_groups.xml b/_data/style_property_groups.xml
new file mode 100644
index 0000000..563c56d
--- /dev/null
+++ b/_data/style_property_groups.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/template_modifications.xml b/_data/template_modifications.xml
new file mode 100644
index 0000000..04c9d33
--- /dev/null
+++ b/_data/template_modifications.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/templates.xml b/_data/templates.xml
new file mode 100644
index 0000000..e9181db
--- /dev/null
+++ b/_data/templates.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+]]>
+
diff --git a/_data/widget_definitions.xml b/_data/widget_definitions.xml
new file mode 100644
index 0000000..fbdae64
--- /dev/null
+++ b/_data/widget_definitions.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/_data/widget_positions.xml b/_data/widget_positions.xml
new file mode 100644
index 0000000..65d80ac
--- /dev/null
+++ b/_data/widget_positions.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/addon.json b/addon.json
new file mode 100644
index 0000000..8eeefea
--- /dev/null
+++ b/addon.json
@@ -0,0 +1,23 @@
+{
+ "legacy_addon_id": "",
+ "title": "[WH1] Paygate: LiqPay",
+ "description": "LiqPay payment profile for XenForo.",
+ "version_id": 1000070,
+ "version_string": "1.0.0",
+ "dev": "wh1teend",
+ "dev_url": "https://t.me/wh1teend",
+ "faq_url": "",
+ "support_url": "",
+ "extra_urls": [],
+ "require": {
+ "php": [
+ "7.4",
+ "PHP 7.4+"
+ ],
+ "XF": [
+ 2010270,
+ "XenForo 2.1.2+"
+ ]
+ },
+ "icon": "icon.png"
+}
\ No newline at end of file
diff --git a/icon.png b/icon.png
new file mode 100644
index 0000000..6033398
Binary files /dev/null and b/icon.png differ