Update portal_feed_poller.py — correct KoreID format + EventBus + v2 poller

This commit is contained in:
JA
2026-07-09 03:42:42 +00:00
parent 50218c28d5
commit ca3783f348

View File

@@ -1,43 +1,36 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Vector Zulu — Payment Mirror Adapter Vector Zulu — Portal Feed Poller v2.0
Polls KoreNet portal feeds for new payment events and executes the full Polls KoreNet portal feeds for new payment/settlement/deal events
payment mirror lifecycle via api.korenet.cloud. and executes the full payment mirror lifecycle.
Full lifecycle per VZ runbook: Key facts from VZ-Welcome-Pack FINAL v1.0 (2026-07-08):
INCOMING SWIFT MT103/PACS.008 - UETR comes FROM the payment feed (SWIFT gpi UUID v4) — never mint a new one
→ MINT mirror tokens - Auth-code format: AUTH-VZ-MINT-<period> e.g. AUTH-VZ-MINT-2026Q2
→ SETTLE T+0 - Lifecycle keyed by SAME UETR: mint → settle → redeem → burn-sell → close
→ REDEEM fiat - Every step LICK-signed
→ BURN-SELL via venue routing - KoreID validated via benjii-prime.korenet.cloud/api/v1/koreid/verify-lineage
→ CLOSE tranche - EventBus topic: integration-partners (VZ's own scoped topic)
→ ANCHOR to Ethereum (ISO 20022 proof)
→ POST confirmation KoreID back to KoreChain
Dependencies:
- vz_mtls_client.py (Bryan's official client)
- koreid.py (KoreID generator)
- Redis (event deduplication)
- Postgres (audit trail)
""" """
import os import os
import json import json
import time import time
import uuid
import logging import logging
import hashlib
import subprocess import subprocess
import requests import requests
import redis import redis
import psycopg2 import psycopg2
import urllib3 import urllib3
from datetime import datetime, timezone from datetime import datetime, timezone
from koreid import KoreIDGenerator, wrap_ethereum_event from koreid_new import KoreIDGenerator, KoreIDValidator, KoreIDParser, KoreType, KoreDomain, GENESIS_ROOT
from eventbus import EventBusClient, Severity, EventType
urllib3.disable_warnings() urllib3.disable_warnings()
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format='%(asctime)s [MIRROR] %(levelname)s %(message)s' format='%(asctime)s [POLLER-V2] %(levelname)s %(message)s'
) )
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -48,13 +41,10 @@ KEY = os.environ.get('VECTOR_ZULU_KEY', '/certs/vector-zulu-client.key
RAILS_URL = os.environ.get('VECTOR_ZULU_RAILS_URL', 'https://vector.korenet.cloud') RAILS_URL = os.environ.get('VECTOR_ZULU_RAILS_URL', 'https://vector.korenet.cloud')
API_URL = os.environ.get('VECTOR_ZULU_API_URL', 'https://api.korenet.cloud') API_URL = os.environ.get('VECTOR_ZULU_API_URL', 'https://api.korenet.cloud')
POLL_INTERVAL = int(os.environ.get('POLL_INTERVAL', '30')) POLL_INTERVAL = int(os.environ.get('POLL_INTERVAL', '30'))
AUTH_CODE = os.environ.get('VZ_MINT_AUTH_CODE', 'AUTH-VZ-MINT-2026Q2')
# Venue routing priority (per runbook) VZ_TENANT = 'vector-zulu'
VENUES = ['cryptohost', 'koreexchange', 'uniswap']
# VZ vault IDs
VZ_VAULTS = ['VZ-USD-VAULT', 'VZ-USDT-VAULT', 'VZ-BTC-VAULT'] VZ_VAULTS = ['VZ-USD-VAULT', 'VZ-USDT-VAULT', 'VZ-BTC-VAULT']
VENUES = ['cryptohost', 'koreexchange', 'uniswap']
# ── Infrastructure ──────────────────────────────────────────────────────────── # ── Infrastructure ────────────────────────────────────────────────────────────
@@ -64,7 +54,6 @@ def get_redis():
port=6379, decode_responses=True port=6379, decode_responses=True
) )
def get_pg(): def get_pg():
return psycopg2.connect( return psycopg2.connect(
host=os.environ.get('POSTGRES_HOST', 'localhost'), host=os.environ.get('POSTGRES_HOST', 'localhost'),
@@ -74,17 +63,15 @@ def get_pg():
connect_timeout=10 connect_timeout=10
) )
def rails_session():
def session():
s = requests.Session() s = requests.Session()
s.cert = (CERT, KEY) s.cert = (CERT, KEY)
s.verify = False s.verify = False
s.headers = {'X-Tenant-Id': 'vector-zulu'} s.headers = {'X-Tenant-Id': VZ_TENANT}
return s return s
def run_tool(*args) -> dict: def run_tool(*args) -> dict:
"""Run vz_mtls_client.py with given args, return parsed JSON.""" """Run vz_mtls_client.py, return parsed JSON."""
cmd = ['python3', 'tools/vz_mtls_client.py'] + list(args) cmd = ['python3', 'tools/vz_mtls_client.py'] + list(args)
try: try:
result = subprocess.run( result = subprocess.run(
@@ -92,24 +79,19 @@ def run_tool(*args) -> dict:
cwd=os.path.expanduser('~/vector-zulu'), cwd=os.path.expanduser('~/vector-zulu'),
timeout=30 timeout=30
) )
# Strip [OK]/[FAIL] prefix line lines = [l for l in result.stdout.strip().split('\n')
lines = result.stdout.strip().split('\n') if not l.startswith('[OK]') and not l.startswith('[FAIL]')]
json_lines = [l for l in lines if not l.startswith('[OK]') and not l.startswith('[FAIL]')] return json.loads('\n'.join(lines)) if lines else {}
return json.loads('\n'.join(json_lines))
except Exception as e: except Exception as e:
log.error(f"Tool error: {e}")
return {'error': str(e)} return {'error': str(e)}
# ── Feed polling ────────────────────────────────────────────────────────────── # ── Feed polling ──────────────────────────────────────────────────────────────
def poll_feed(path: str) -> list: def poll_feed(path: str) -> list:
"""Poll a KoreNet portal feed, return new items."""
try: try:
resp = session().get(f'{RAILS_URL}/{path}', timeout=15) resp = rails_session().get(f'{RAILS_URL}/{path}', timeout=15)
if resp.status_code == 200: if resp.status_code == 200:
data = resp.json() data = resp.json()
# Return whichever list field is present
for key in ['payments', 'settlements', 'deals']: for key in ['payments', 'settlements', 'deals']:
if key in data and data[key]: if key in data and data[key]:
return data[key] return data[key]
@@ -117,266 +99,279 @@ def poll_feed(path: str) -> list:
log.error(f"Feed poll error {path}: {e}") log.error(f"Feed poll error {path}: {e}")
return [] return []
def is_processed(r, event_id: str) -> bool: def is_processed(r, event_id: str) -> bool:
"""Check Redis deduplication cache."""
return r.exists(f'mirror:processed:{event_id}') == 1 return r.exists(f'mirror:processed:{event_id}') == 1
def mark_processed(r, event_id: str): def mark_processed(r, event_id: str):
"""Mark event as processed in Redis (24h TTL)."""
r.setex(f'mirror:processed:{event_id}', 86400, '1') r.setex(f'mirror:processed:{event_id}', 86400, '1')
# ── UETR validation ───────────────────────────────────────────────────────────
# ── Compliance checks ───────────────────────────────────────────────────────── def validate_uetr(uetr: str) -> str:
"""
Validate UETR is a proper UUID v4.
Per welcome pack: UETR comes from feed, VZ passes through.
Generate fresh UUID v4 ONLY if feed genuinely lacks one.
"""
if not uetr:
fresh = str(uuid.uuid4())
log.warning(f"Feed missing UETR — generated fresh: {fresh}")
return fresh
try:
val = uuid.UUID(uetr, version=4)
return str(val).lower()
except ValueError:
fresh = str(uuid.uuid4())
log.warning(f"Invalid UETR {uetr} — generated fresh: {fresh}")
return fresh
def sanctions_check(entity: str, jurisdiction: str = 'ZA') -> bool: # ── KoreID validation ─────────────────────────────────────────────────────────
def validate_inbound_koreid(koreid: str, validator: KoreIDValidator,
eb: EventBusClient, uetr: str) -> bool:
""" """
Run sanctions screening before any mirror operation. Validate inbound KoreID from KoreNet feed.
Returns True if CLEAR, False if HIT. Phase-4: must be genesis_anchored=True to proceed.
""" """
result = run_tool('oracle', 'sanctions', parser = KoreIDParser()
'--entity', entity, if not parser.is_valid_format(koreid):
'--jurisdiction', jurisdiction) log.error(f"Invalid KoreID format: {koreid}")
status = result.get('status', 'UNKNOWN') eb.emit_koreid_invalid(koreid, 'invalid_format', uetr)
if status == 'CLEAR':
log.info(f"Sanctions CLEAR: {entity}")
return True
else:
log.warning(f"Sanctions HIT: {entity}{status}")
return False return False
result = validator.verify_lineage(koreid)
if not result:
log.error(f"KoreID validation failed (no response): {koreid}")
eb.emit_koreid_invalid(koreid, 'validation_timeout', uetr)
return False
def entity_enrich(entity: str, entity_type: str = 'BENEFICIARY', if not result.get('phase4_compliant'):
jurisdiction: str = 'ZA') -> dict: reason = result.get('reason', 'unknown')
"""Enrich entity data before mirror mint.""" log.error(f"KoreID not Phase-4 compliant: {koreid}{reason}")
return run_tool('oracle', 'enrich', eb.emit_koreid_invalid(koreid, reason, uetr)
'--entity', entity, return False
'--type', entity_type,
'--jurisdiction', jurisdiction)
log.info(f"KoreID validated: {koreid} — genesis anchored ✓")
return True
# ── Payment mirror lifecycle ────────────────────────────────────────────────── # ── Mirror lifecycle ──────────────────────────────────────────────────────────
def mirror_mint(uetr: str, customer: str, asset: str, def mirror_mint(uetr: str, asset: str, amount: float,
amount: float, rail_ref: str, vault: str) -> dict: rail_ref: str, vault: str) -> dict:
""" log.info(f"MINT {amount} {asset} UETR:{uetr}")
Step 1: Mint mirror tokens against incoming SWIFT payment.
"""
log.info(f"MINT {amount} {asset} — UETR: {uetr}")
return run_tool('mirror', 'mint', return run_tool('mirror', 'mint',
'--uetr', uetr, '--uetr', uetr,
'--customer', customer, '--customer', VZ_TENANT,
'--asset', asset, '--asset', asset,
'--amount', str(amount), '--amount', str(amount),
'--rail-ref', rail_ref, '--rail-ref', rail_ref,
'--vault', vault) '--vault', vault)
def mirror_settle(uetr: str) -> dict: def mirror_settle(uetr: str) -> dict:
"""Step 2: Record T+0 settlement.""" log.info(f"SETTLE UETR:{uetr}")
log.info(f"SETTLE — UETR: {uetr}")
settled_at = datetime.now(timezone.utc).isoformat()
return run_tool('mirror', 'settle', return run_tool('mirror', 'settle',
'--uetr', uetr, '--uetr', uetr,
'--settled-at', settled_at) '--settled-at', datetime.now(timezone.utc).isoformat())
def mirror_redeem(uetr: str, amount: float) -> dict: def mirror_redeem(uetr: str, amount: float) -> dict:
"""Step 3: Redeem fiat from VZ vault.""" log.info(f"REDEEM {amount} UETR:{uetr}")
log.info(f"REDEEM {amount} — UETR: {uetr}")
return run_tool('mirror', 'redeem', return run_tool('mirror', 'redeem',
'--uetr', uetr, '--uetr', uetr,
'--amount', str(amount)) '--amount', str(amount))
def mirror_burn_sell(uetr: str, amount: float) -> dict: def mirror_burn_sell(uetr: str, amount: float) -> dict:
"""
Step 4: Burn-sell via venue routing.
Tries CryptoHost → KoreExchange → Uniswap per runbook.
"""
for venue in VENUES: for venue in VENUES:
log.info(f"BURN-SELL via {venue} UETR: {uetr}") log.info(f"BURN-SELL via {venue} UETR:{uetr}")
result = run_tool('mirror', 'burn-sell', result = run_tool('mirror', 'burn-sell',
'--uetr', uetr, '--uetr', uetr,
'--amount', str(amount), '--amount', str(amount),
'--venue', venue) '--venue', venue)
if 'error' not in result: if 'error' not in result:
log.info(f"Burn-sell success via {venue}")
return result return result
log.warning(f"Venue {venue} failed, trying next") log.warning(f"Venue {venue} failed")
return {'error': 'All venues failed'} return {'error': 'All venues failed'}
def mirror_close(uetr: str) -> dict: def mirror_close(uetr: str) -> dict:
"""Step 5: Close the tranche.""" log.info(f"CLOSE UETR:{uetr}")
log.info(f"CLOSE — UETR: {uetr}")
return run_tool('mirror', 'close', '--uetr', uetr) return run_tool('mirror', 'close', '--uetr', uetr)
# ── Ethereum anchoring ──────────────────────────────────────────────────────── # ── Ethereum anchoring ────────────────────────────────────────────────────────
def anchor_to_ethereum(kore_id: str, uetr: str, amount: float, def anchor_to_ethereum(koreid: str, uetr: str, amount: float,
currency: str, event_type: str) -> str: currency: str, step: str, gen: KoreIDGenerator) -> str:
""" """
Anchor KoreNet event to Ethereum mainnet. Anchor KoreNet event to Ethereum.
Returns Ethereum TX hash. Generates anchor KoreID linked to original.
TODO: Deploy KoreAnchor.sol contract and call it here. TODO: Call KoreAnchor.sol once deployed.
For now, stores in oracle transmit log.
""" """
payload = { import hashlib
'koreId': kore_id, anchor_kid = gen.for_ethereum_anchor(
'uetr': uetr, original_koreid=koreid,
'amount': amount, tx_hash=f"pending_{uetr}_{step}",
'currency': currency, block_number=0,
'eventType': event_type, event_type=step
'timestamp': datetime.now(timezone.utc).isoformat(), )
'hash': hashlib.sha256( log.info(f"Anchor KoreID: {anchor_kid['koreid']}{koreid}")
json.dumps({'koreId': kore_id, 'uetr': uetr, 'amount': amount},
sort_keys=True).encode()
).hexdigest()
}
log.info(f"Anchoring to Ethereum: {kore_id}{event_type}")
# TODO: Call KoreAnchor.sol contract # TODO: Call KoreAnchor.sol contract
# tx_hash = kore_anchor_contract.anchor(payload) # tx = anchor_contract.anchor(koreid, anchor_kid['hash'], amount)
# return tx_hash placeholder_hash = f"0x{hashlib.sha256(f'{koreid}{step}'.encode()).hexdigest()}"
return f"0x{payload['hash'][:64]}" # placeholder until contract deployed return placeholder_hash
def trigger_oracle_update(): def trigger_oracle_update():
"""Immediately trigger oracle transmit when VZ vault balance changes.""" """Immediately trigger oracle transmit when VZ vault balance changes."""
log.info("Triggering immediate oracle update") log.info("Triggering immediate oracle transmit")
try: try:
import subprocess
subprocess.Popen( subprocess.Popen(
['node', '/opt/eth-deploy-v21/manual_transmit.js'], ['node', '/opt/eth-deploy-v21/manual_transmit.js'],
stdout=open('/home/nigel/vz-transmit.log', 'a'), stdout=open('/home/nigel/vz-transmit.log', 'a'),
stderr=subprocess.STDOUT stderr=subprocess.STDOUT
) )
except Exception as e: except Exception as e:
log.error(f"Oracle update failed: {e}") log.error(f"Oracle trigger failed: {e}")
# ── Post confirmation to KoreChain ────────────────────────────────────────────
# ── KoreID confirmation ─────────────────────────────────────────────────────── def post_confirmation(original_koreid: str, tx_hash: str, uetr: str,
step: str, gen: KoreIDGenerator, r) -> str:
def post_confirmation(original_kore_id: str, tx_hash: str,
uetr: str, event_type: str, pg) -> dict:
""" """
Post Ethereum anchor confirmation back to KoreChain. Post Ethereum anchor confirmation back to KoreChain.
Generates a confirmation KoreID linked to the original. Queued in Redis until korechain.korenet.cloud is accessible.
TODO: POST to korechain.korenet.cloud/api/v1/anchor once G2 cert trusted.
""" """
gen = KoreIDGenerator(pg) anchor_kid = gen.for_ethereum_anchor(
payload = gen.generate( original_koreid=original_koreid,
event_type=f'{event_type}_CONFIRM', tx_hash=tx_hash,
currency='USD', block_number=0,
current_network='ETHEREUM', event_type=step
parent_network='KORECHAIN',
) )
confirmation = { confirmation = {
'koreid': payload['koreid'], 'koreid': anchor_kid['koreid'],
'linked_to': original_kore_id, 'linked_to': original_koreid,
'uetr': uetr, 'uetr': uetr,
'ethereum_tx': tx_hash, 'ethereum_tx': tx_hash,
'event_type': f'{event_type}_CONFIRM', 'step': step,
'anchored_at': datetime.now(timezone.utc).isoformat(), 'anchored_at': datetime.now(timezone.utc).isoformat(),
'proof': { 'genesis_root': GENESIS_ROOT,
'hash': tx_hash,
'network': 'ETHEREUM_MAINNET',
} }
}
log.info(f"Confirmation KoreID: {payload['koreid']}{original_kore_id}")
# TODO: POST to korechain.korenet.cloud once G2 cert trusted
# session().post('https://korechain.korenet.cloud/api/v1/anchor', json=confirmation)
# Queue for when endpoint is available
r = get_redis()
r.lpush('korechain:outbound_queue', json.dumps(confirmation)) r.lpush('korechain:outbound_queue', json.dumps(confirmation))
log.info(f"Queued confirmation: {anchor_kid['koreid']}")
return anchor_kid['koreid']
return confirmation # ── Main event processor ──────────────────────────────────────────────────────
def process_event(event: dict, r, pg,
gen: KoreIDGenerator,
validator: KoreIDValidator,
eb: EventBusClient):
"""Process a single payment/deal/settlement event."""
# ── Main processing ─────────────────────────────────────────────────────────── event_id = event.get('id') or event.get('dealId') or event.get('paymentId', '')
koreid = event.get('koreId') or event.get('kore_id', '')
def process_payment_event(event: dict, r, pg):
"""
Process a single payment/deal event from the KoreNet feed.
Executes full mirror lifecycle.
"""
event_id = event.get('id') or event.get('dealId') or event.get('uetr', '')
kore_id = event.get('koreId') or event.get('kore_id', '')
amount = float(event.get('amount', 0)) amount = float(event.get('amount', 0))
currency = event.get('currency', 'USD') currency = event.get('currency', 'USD')
entity = event.get('counterparty') or event.get('customer', 'UNKNOWN') entity = event.get('counterparty') or event.get('customer', 'UNKNOWN')
uetr = event.get('uetr') or event.get('railRef') or event_id
rail_ref = event.get('railRef') or event.get('reference', f'REF-{event_id}') rail_ref = event.get('railRef') or event.get('reference', f'REF-{event_id}')
vault = f"VZ-{currency}-VAULT" if f"VZ-{currency}-VAULT" in VZ_VAULTS else 'VZ-USD-VAULT' vault = f"VZ-{currency}-VAULT" if f"VZ-{currency}-VAULT" in VZ_VAULTS else 'VZ-USD-VAULT'
# UETR — comes from feed per welcome pack
uetr = validate_uetr(
event.get('uetr') or event.get('railRef') or event.get('swiftRef', '')
)
if not event_id or is_processed(r, event_id): if not event_id or is_processed(r, event_id):
return return
log.info(f"Processing event: {event_id} | {currency} {amount:,.2f} | KoreID: {kore_id}") log.info(f"Processing: {event_id} | {currency} {amount:,.2f} | UETR: {uetr}")
correlation_id = str(uuid.uuid4())
try: try:
# Step 0: Compliance # Step 0a: Validate inbound KoreID
if not sanctions_check(entity): if koreid and not validate_inbound_koreid(koreid, validator, eb, uetr):
log.error(f"SANCTIONS HIT — {entity} — rejecting {event_id}") log.error(f"Rejecting {event_id} — invalid KoreID")
mark_processed(r, event_id) mark_processed(r, event_id)
return return
# Step 1: Mint # Step 0b: Sanctions check
mint_result = mirror_mint(uetr, 'vector-zulu', currency, amount, rail_ref, vault) sanctions = run_tool('oracle', 'sanctions',
if 'error' in mint_result: '--entity', entity,
log.error(f"Mint failed: {mint_result}") '--jurisdiction', 'ZA')
if sanctions.get('status') != 'CLEAR':
log.error(f"SANCTIONS HIT — {entity}")
eb.emit_sanctions_hit(entity, 'ZA', uetr)
mark_processed(r, event_id)
return return
# Anchor MINT to Ethereum # Step 0c: Entity enrichment
tx_hash = anchor_to_ethereum(kore_id, uetr, amount, currency, 'MINT') run_tool('oracle', 'enrich', '--entity', entity,
post_confirmation(kore_id, tx_hash, uetr, 'MINT', pg) '--type', 'BENEFICIARY', '--jurisdiction', 'ZA')
# Step 1: Mint
mint_result = mirror_mint(uetr, currency, amount, rail_ref, vault)
if 'error' in mint_result:
eb.emit_mirror_failed('mint', uetr, str(mint_result.get('error')))
return
mint_kid = gen.for_mirror_mint(uetr, amount, currency, vault,
parent=koreid or GENESIS_ROOT)
tx = anchor_to_ethereum(mint_kid['koreid'], uetr, amount, currency, 'MINT', gen)
post_confirmation(mint_kid['koreid'], tx, uetr, 'MINT', gen, r)
eb.emit_mirror_success('mint', uetr, mint_kid['koreid'], amount, currency)
# Step 2: Settle # Step 2: Settle
settle_result = mirror_settle(uetr) settle_result = mirror_settle(uetr)
tx_hash = anchor_to_ethereum(kore_id, uetr, amount, currency, 'SETTLE') settle_kid = gen.for_mirror_settle(uetr, parent_koreid=mint_kid['koreid'])
post_confirmation(kore_id, tx_hash, uetr, 'SETTLE', pg) tx = anchor_to_ethereum(settle_kid['koreid'], uetr, amount, currency, 'SETTLE', gen)
post_confirmation(settle_kid['koreid'], tx, uetr, 'SETTLE', gen, r)
eb.emit_mirror_success('settle', uetr, settle_kid['koreid'], amount, currency)
# Step 3: Redeem # Step 3: Redeem
redeem_result = mirror_redeem(uetr, amount) redeem_result = mirror_redeem(uetr, amount)
tx_hash = anchor_to_ethereum(kore_id, uetr, amount, currency, 'REDEEM') redeem_kid = gen.for_mirror_redeem(uetr, amount, parent_koreid=settle_kid['koreid'])
post_confirmation(kore_id, tx_hash, uetr, 'REDEEM', pg) tx = anchor_to_ethereum(redeem_kid['koreid'], uetr, amount, currency, 'REDEEM', gen)
post_confirmation(redeem_kid['koreid'], tx, uetr, 'REDEEM', gen, r)
eb.emit_mirror_success('redeem', uetr, redeem_kid['koreid'], amount, currency)
# Trigger oracle update if VZ vault affected # Oracle update if VZ vault affected
if vault in VZ_VAULTS: if vault in VZ_VAULTS:
trigger_oracle_update() trigger_oracle_update()
# Step 4: Burn-sell # Step 4: Burn-sell
burn_result = mirror_burn_sell(uetr, amount) burn_result = mirror_burn_sell(uetr, amount)
tx_hash = anchor_to_ethereum(kore_id, uetr, amount, currency, 'BURN_SELL') venue = burn_result.get('venue', 'unknown')
post_confirmation(kore_id, tx_hash, uetr, 'BURN_SELL', pg) burn_kid = gen.for_mirror_burn(uetr, amount, venue,
parent_koreid=redeem_kid['koreid'])
tx = anchor_to_ethereum(burn_kid['koreid'], uetr, amount, currency, 'BURN', gen)
post_confirmation(burn_kid['koreid'], tx, uetr, 'BURN', gen, r)
eb.emit_mirror_success('burn', uetr, burn_kid['koreid'], amount, currency)
# Step 5: Close # Step 5: Close
close_result = mirror_close(uetr) close_result = mirror_close(uetr)
tx_hash = anchor_to_ethereum(kore_id, uetr, amount, currency, 'CLOSE') close_kid = gen.for_mirror_close(uetr, parent_koreid=burn_kid['koreid'])
post_confirmation(kore_id, tx_hash, uetr, 'CLOSE', pg) tx = anchor_to_ethereum(close_kid['koreid'], uetr, amount, currency, 'CLOSE', gen)
post_confirmation(close_kid['koreid'], tx, uetr, 'CLOSE', gen, r)
eb.emit_mirror_success('close', uetr, close_kid['koreid'], amount, currency)
mark_processed(r, event_id) mark_processed(r, event_id)
log.info(f"✓ Complete: {event_id} | {currency} {amount:,.2f}") log.info(f"✓ Complete: {event_id} | {currency} {amount:,.2f} | UETR: {uetr}")
except Exception as e: except Exception as e:
log.error(f"Processing error {event_id}: {e}") log.error(f"Processing error {event_id}: {e}")
eb.emit(EventType.ENDPOINT_DOWN,
{'event_id': event_id, 'error': str(e)},
Severity.HIGH)
def run(): def run():
log.info("Vector Zulu Payment Mirror Adapter starting...") log.info("VZ Portal Feed Poller v2.0 starting...")
log.info(f"Rails: {RAILS_URL} | API: {API_URL} | Poll: {POLL_INTERVAL}s") log.info(f"Rails: {RAILS_URL} | API: {API_URL} | Poll: {POLL_INTERVAL}s")
r = get_redis() r = get_redis()
pg = get_pg() pg = get_pg()
gen = KoreIDGenerator()
validator = KoreIDValidator(CERT, KEY)
eb = EventBusClient()
while True: while True:
# Poll all three feeds
payments = poll_feed('api/v1/tenants/portal/payments/feed') payments = poll_feed('api/v1/tenants/portal/payments/feed')
settlements = poll_feed('api/v1/tenants/portal/settlements/feed') settlements = poll_feed('api/v1/tenants/portal/settlements/feed')
deals = poll_feed('api/v1/tenants/deals/feed') deals = poll_feed('api/v1/tenants/deals/feed')
@@ -384,9 +379,9 @@ def run():
all_events = payments + settlements + deals all_events = payments + settlements + deals
if all_events: if all_events:
log.info(f"Found {len(all_events)} events to process") log.info(f"Found {len(all_events)} events")
for event in all_events: for event in all_events:
process_payment_event(event, r, pg) process_event(event, r, pg, gen, validator, eb)
else: else:
log.debug("No new events") log.debug("No new events")