Files
kane-diagnostics/hubzilla/addon/g1wallet/g1wallet_renderer.php
2026-06-14 07:45:02 -04:00

153 lines
6.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* g1wallet_renderer.php — All HTML rendering for g1wallet.
*/
// -----------------------------------------------------------------------------
// ACCESS WALL
// -----------------------------------------------------------------------------
function g1wallet_render_access_wall() {
$directory_url = g1wallet_h(z_root() . '/channel/theron');
$hostname = g1wallet_h(App::get_hostname());
return '
<div class="g1wallet-content">
<div class="alert alert-info" role="alert">
<strong>SASE verification required to access the Ğ1 Wallet.</strong>
This feature is available to verified HOA participants only.
Visit <a href="' . $directory_url . '">' . $hostname . '</a> to begin the verification process.
</div>
</div>
';
}
// -----------------------------------------------------------------------------
// LANDING PAGE
// -----------------------------------------------------------------------------
function g1wallet_render_landing($access) {
$channel_id = local_channel();
$stored_addr = $channel_id ? get_pconfig($channel_id, 'g1wallet', 'g1_address') : '';
$balance = '';
// If address is stored, fetch balance via cry01 chain query.
if ($stored_addr) {
$balance = g1wallet_fetch_balance($stored_addr);
}
$out = '<div class="g1wallet-content">';
$out .= '<h2>Ğ1 Wallet</h2>';
$out .= '<p class="text-muted">Register your Ğ1 address to display your balance and participate in cost-bearing civic actions.</p>';
// Optional notice
$out .= '<div class="alert alert-light border small mb-3">';
$out .= '<strong>Optional.</strong> The Ğ1 Wallet is not required for browsing or submitting diagnostic records. ';
$out .= 'However, future actions such as Scenario submission will require a small Ğ1 payment. ';
$out .= 'The transaction record serves as proof of participation and is included in the attestation record.';
$out .= '</div>';
// Current address + balance
if ($stored_addr) {
$out .= '<div class="g1wallet-address-display mb-4">';
$out .= '<h5>Registered Address</h5>';
$out .= '<p class="font-monospace small text-break">' . g1wallet_h($stored_addr) . '</p>';
if ($balance !== '') {
$out .= '<p class="mb-1"><strong>Balance:</strong> ' . g1wallet_h($balance) . ' Ğ1</p>';
} else {
$out .= '<p class="text-muted small">Balance unavailable.</p>';
}
$out .= '</div>';
}
// Address registration form
$out .= '<div class="g1wallet-address-form">';
$out .= '<h5>' . ($stored_addr ? 'Update Address' : 'Register Your Ğ1 Address') . '</h5>';
$out .= '<p class="text-muted small">Paste your Ğ1 address (starts with <code>g1</code>, 4647 characters). ';
$out .= 'You can find it in the Ğecko app or any Ğ1 wallet application.</p>';
$out .= '<form method="post" action="/g1wallet/address">';
$out .= g1wallet_csrf_token();
$out .= '<div class="mb-3">';
$out .= '<label class="form-label" for="g1wallet-address">Ğ1 Address <span class="text-danger">*</span></label>';
$out .= '<input type="text" class="form-control font-monospace" id="g1wallet-address" name="g1_address"';
$out .= ' value="' . g1wallet_h($stored_addr) . '"';
$out .= ' placeholder="g1..." autocomplete="off" spellcheck="false" maxlength="48">';
$out .= '</div>';
$out .= '<button type="submit" class="btn btn-primary">Save Address</button>';
$out .= '</form>';
$out .= '</div>';
$out .= '</div>';
return $out;
}
// -----------------------------------------------------------------------------
// BALANCE FETCH
// -----------------------------------------------------------------------------
function g1wallet_fetch_balance($g1_address) {
// Delegates to cry01 chain query via the orchestrator RPC endpoint.
// Returns formatted balance string (e.g. "12.50") or empty string on failure.
// Reuses the same config/RPC path as cry01.
$cry01_config_raw = @file_get_contents('addon/cry01/config.json');
if ($cry01_config_raw === false) return '';
$cry01_config = json_decode($cry01_config_raw, true);
if (json_last_error() !== JSON_ERROR_NONE) return '';
$rpc_endpoint = rtrim($cry01_config['g1_rpc_endpoint'] ?? '', '/');
if (!$rpc_endpoint) return '';
// Decode SS58 address to 32-byte account ID, build storage key, query RPC.
// These functions live in cry01_substrate.php and cry01_chain.php.
if (!function_exists('cry01_ss58_decode')) {
require_once 'addon/cry01/cry01_substrate.php';
}
if (!function_exists('cry01_storage_key')) {
require_once 'addon/cry01/cry01_chain.php';
}
$account_id = cry01_ss58_decode($g1_address);
if (!$account_id) return '';
$storage_key = cry01_storage_key($account_id);
$raw_result = cry01_rpc_state_get_storage($rpc_endpoint, $storage_key);
if ($raw_result === null) return '';
$account_info = cry01_decode_account_info($raw_result);
if (!$account_info) return '';
// Balance is in centimes (100 units = 1 Ğ1).
$free_centimes = $account_info['free'] ?? '0';
return cry01_format_balance($free_centimes);
}
function cry01_format_balance($centimes_string) {
// Converts centimes string to "X.XX" Ğ1 string using string arithmetic.
if (!function_exists('cry01_decimal_string_add')) {
require_once 'addon/cry01/cry01_substrate.php';
}
// Integer division by 100 via string — avoid bcmath dependency.
$len = strlen($centimes_string);
if ($len <= 2) {
$whole = '0';
$frac = str_pad($centimes_string, 2, '0', STR_PAD_LEFT);
} else {
$whole = substr($centimes_string, 0, $len - 2);
$frac = substr($centimes_string, $len - 2);
}
return $whole . '.' . $frac;
}
// -----------------------------------------------------------------------------
// ERROR
// -----------------------------------------------------------------------------
function g1wallet_render_error($message) {
return '<div class="g1wallet-content"><div class="alert alert-danger">'
. g1wallet_h($message)
. '</div></div>';
}