153 lines
6.1 KiB
PHP
153 lines
6.1 KiB
PHP
<?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>, 46–47 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>';
|
||
}
|