#!/usr/bin/env python3 """ Vector Zulu — Ethereum API Exposes VZ smart contract state and KoreAnchor lookups to KoreNet adapter. Port 8769 """ import os, json, time, hmac, hashlib, logging, requests, urllib3 from datetime import datetime, timezone from flask import Flask, jsonify, request import psycopg2 urllib3.disable_warnings() logging.basicConfig(level=logging.INFO, format='%(asctime)s [ETH-API] %(levelname)s %(message)s') log = logging.getLogger(__name__) app = Flask(__name__) ALCHEMY_URL = os.environ.get('ALCHEMY_URL', 'https://eth-mainnet.g.alchemy.com/v2/nRVT_IneMUDF3Pokubawx') LICK_KEY = os.environ.get('VECTOR_ZULU_LICK_KEY', 'NotMyCircu$_NotMyMonkey$').encode() FINALITY_BLOCKS = 12 CONTRACTS = { 'SVReserveOracle': { 'name': 'SVReserveOracle V2.1', 'address': '0x0BA2D70711286bacCD75B37EA47165A1E6CfD2eb', 'deployedAt': '2026-05-01', 'etherscan': 'https://etherscan.io/address/0x0BA2D70711286bacCD75B37EA47165A1E6CfD2eb' }, 'KoreAnchor': { 'name': 'KoreAnchor V1.0', 'address': '0x8AaA785c7dC116b834E3A1766866078051fC0313', 'deployedAt': '2026-07-14', 'deployTx': '0x75c2d2331713831b78c2aaaa994ffdb0b22114429a06b112f1237f84bd4a7d39', 'etherscan': 'https://etherscan.io/address/0x8AaA785c7dC116b834E3A1766866078051fC0313' }, 'VZProofOfReserve': { 'name': 'VZProofOfReserve', 'address': '0x508DA1733567d3361988CD554038301c0E61e260', 'etherscan': 'https://etherscan.io/address/0x508DA1733567d3361988CD554038301c0E61e260' }, 'SVTokenFactory': { 'name': 'SVTokenFactory', 'address': '0x6C347F4b582c86392Bc35C64e98F641f2F067DBC', 'etherscan': 'https://etherscan.io/address/0x6C347F4b582c86392Bc35C64e98F641f2F067DBC' }, } SV_TOKENS = { 'SVUSD': '0x0A925D0F18090d2953CaC1F90b71c79fEd0efdB2', 'SVGBP': None, 'SVEUR': None, 'SVCHF': None, 'SVJPY': None, 'SVSGD': None, } ORACLE_WALLET = '0xA08298ed3Bf2aD64499BEB115441aed85E0985Cc' # Function selectors SEL_LATEST_ANSWER = '0x50d25bcd' SEL_LATEST_TIMESTAMP = '0x8205bf6a' SEL_IS_ADEQUATE = '0x2e0c8d6a' SEL_TOTAL_SUPPLY = '0x18160ddd' def get_pg(): return psycopg2.connect( host=os.environ.get('POSTGRES_HOST','localhost'), dbname=os.environ.get('POSTGRES_DB','vz_oracle'), user=os.environ.get('POSTGRES_USER','vz_oracle'), password=os.environ.get('POSTGRES_PASSWORD',''), connect_timeout=10) def alchemy_call(method, params): r = requests.post(ALCHEMY_URL, json={ 'jsonrpc':'2.0','method':method,'params':params,'id':1 }, timeout=10) d = r.json() if 'error' in d: raise Exception(d['error']['message']) return d['result'] def eth_call(to, data): return alchemy_call('eth_call', [{'to': to, 'data': data}, 'latest']) def sign_response(payload): ts = int(time.time()) body = json.dumps(payload, separators=(',',':')).encode() sig = hmac.new(LICK_KEY, body + b'\n' + str(ts).encode(), hashlib.sha256).hexdigest() return { 'signedBy': 'vector-zulu-eth-api-v1', 'timestamp': datetime.now(timezone.utc).isoformat(), 'signature': sig, 'payloadHash': hashlib.sha256(body).hexdigest() } def current_block(): return int(alchemy_call('eth_blockNumber', []), 16) # ── Routes ──────────────────────────────────────────────────── @app.route('/health') def health(): try: block = current_block() return jsonify({ 'status': 'OPERATIONAL', 'network': 'ETHEREUM_MAINNET', 'blockHeight': block, 'timestamp': datetime.now(timezone.utc).isoformat(), }) except Exception as e: return jsonify({'status': 'DEGRADED', 'error': str(e)}), 503 @app.route('/v1/contracts') def list_contracts(): return jsonify({ 'network': 'ETHEREUM_MAINNET', 'contracts': CONTRACTS, 'oracleWallet': ORACLE_WALLET, 'svTokens': SV_TOKENS, 'timestamp': datetime.now(timezone.utc).isoformat(), }) @app.route('/v1/contracts/oracle/state') def oracle_state(): try: ts_hex = eth_call(CONTRACTS['SVReserveOracle']['address'], SEL_LATEST_TIMESTAMP) ans_hex = eth_call(CONTRACTS['SVReserveOracle']['address'], SEL_LATEST_ANSWER) latest_ts = int(ts_hex, 16) latest_ans = int(ans_hex, 16) age = int(time.time()) - latest_ts try: adeq_hex = eth_call(CONTRACTS['SVReserveOracle']['address'], SEL_IS_ADEQUATE) is_adequate = int(adeq_hex, 16) == 1 except: is_adequate = age < 86400 bal_hex = alchemy_call('eth_getBalance', [ORACLE_WALLET, 'latest']) wallet_balance = f"{int(bal_hex,16)/1e18:.6f}" payload = { 'latestAnswer': str(latest_ans), 'latestAnswerScaled': f"{latest_ans/1e8:,.2f}", 'latestTimestamp': latest_ts, 'latestTimestampISO': datetime.fromtimestamp( latest_ts, tz=timezone.utc).isoformat(), 'isAdequate': is_adequate, 'ageSeconds': age, 'stalenessThresholdSeconds': 86400, 'transmitter': ORACLE_WALLET, 'walletBalance': wallet_balance, 'contractAddress': CONTRACTS['SVReserveOracle']['address'], 'etherscan': CONTRACTS['SVReserveOracle']['etherscan'], } payload['provenance'] = sign_response(payload) return jsonify(payload) except Exception as e: return jsonify({'code':'ERROR','message':str(e)}), 500 @app.route('/v1/contracts/anchor/records/') def get_anchor_by_koreid(kore_id): try: pg = get_pg() with pg.cursor() as cur: cur.execute(""" SELECT koreid, event_type, status, tx_hash, amount, currency, posted_at FROM kore_outbound_events WHERE koreid = %s """, (kore_id,)) row = cur.fetchone() pg.close() if not row: return jsonify({'code':'NOT_FOUND', 'message':f'No anchor record for KoreID: {kore_id}'}), 404 koreid, event_type, status, tx_hash, amount, currency, posted_at = row # Get on-chain confirmation if tx_hash exists confirmations = None finalized = False if tx_hash and tx_hash.startswith('0x'): try: receipt = alchemy_call('eth_getTransactionReceipt', [tx_hash]) if receipt: block_num = int(receipt['blockNumber'], 16) current = current_block() confirmations = current - block_num finalized = confirmations >= FINALITY_BLOCKS except: pass payload = { 'koreId': koreid, 'eventType': event_type, 'status': status, 'txHash': tx_hash, 'amount': str(amount), 'currency': currency, 'anchoredAt': posted_at.isoformat() if posted_at else None, 'confirmations': confirmations, 'finalized': finalized, 'network': 'ETHEREUM_MAINNET', 'contractAddress': CONTRACTS['KoreAnchor']['address'], 'etherscan': f'https://etherscan.io/tx/{tx_hash}' if tx_hash else None, } payload['provenance'] = sign_response(payload) return jsonify(payload) except Exception as e: return jsonify({'code':'ERROR','message':str(e)}), 500 @app.route('/v1/contracts/anchor/records/uetr/') def get_anchor_by_uetr(uetr): try: pg = get_pg() with pg.cursor() as cur: cur.execute(""" SELECT koreid, event_type, status, tx_hash, amount, currency, posted_at FROM kore_outbound_events WHERE koreid LIKE %s OR guid::text = %s LIMIT 1 """, (f'%{uetr[-8:]}%', uetr)) row = cur.fetchone() pg.close() if not row: return jsonify({'code':'NOT_FOUND', 'message':f'No anchor record for UETR: {uetr}'}), 404 koreid, event_type, status, tx_hash, amount, currency, posted_at = row payload = { 'uetr': uetr, 'koreId': koreid, 'eventType': event_type, 'status': status, 'txHash': tx_hash, 'amount': str(amount), 'currency': currency, 'anchoredAt': posted_at.isoformat() if posted_at else None, 'network': 'ETHEREUM_MAINNET', 'etherscan': f'https://etherscan.io/tx/{tx_hash}' if tx_hash else None, } payload['provenance'] = sign_response(payload) return jsonify(payload) except Exception as e: return jsonify({'code':'ERROR','message':str(e)}), 500 @app.route('/v1/contracts/tokens') def get_token_states(): try: ts_hex = eth_call(CONTRACTS['SVReserveOracle']['address'], SEL_LATEST_TIMESTAMP) latest_ts = int(ts_hex, 16) age = int(time.time()) - latest_ts try: adeq_hex = eth_call(CONTRACTS['SVReserveOracle']['address'], SEL_IS_ADEQUATE) is_adequate = int(adeq_hex, 16) == 1 except: is_adequate = age < 86400 tokens = [] for symbol, address in SV_TOKENS.items(): token = { 'symbol': symbol, 'address': address, 'mintingEnabled': is_adequate, 'oracleGate': CONTRACTS['SVReserveOracle']['address'], } if address: try: supply_hex = eth_call(address, SEL_TOTAL_SUPPLY) token['totalSupply'] = str(int(supply_hex, 16)) token['etherscan'] = f'https://etherscan.io/token/{address}' except: pass tokens.append(token) return jsonify({ 'mintingGatedOn': CONTRACTS['SVReserveOracle']['address'], 'isAdequate': is_adequate, 'tokens': tokens, 'timestamp': datetime.now(timezone.utc).isoformat(), }) except Exception as e: return jsonify({'code':'ERROR','message':str(e)}), 500 @app.route('/v1/transactions/') def get_transaction(tx_hash): try: receipt = alchemy_call('eth_getTransactionReceipt', [tx_hash]) if not receipt: return jsonify({'code':'NOT_FOUND','message':'Transaction not found or pending'}), 404 block_num = int(receipt['blockNumber'], 16) current = current_block() confirmations = current - block_num status = 'FINALIZED' if confirmations >= FINALITY_BLOCKS else 'CONFIRMED' if int(receipt['status'], 16) == 0: status = 'FAILED' payload = { 'txHash': tx_hash, 'status': status, 'blockNumber': block_num, 'confirmations': confirmations, 'finalized': confirmations >= FINALITY_BLOCKS, 'gasUsed': int(receipt['gasUsed'], 16), 'from': receipt.get('from'), 'to': receipt.get('to'), 'network': 'ETHEREUM_MAINNET', 'etherscan': f'https://etherscan.io/tx/{tx_hash}', 'timestamp': datetime.now(timezone.utc).isoformat(), } return jsonify(payload) except Exception as e: return jsonify({'code':'ERROR','message':str(e)}), 500 @app.route('/v1/verify/anchor', methods=['POST']) def verify_anchor(): data = request.get_json() if not data or not data.get('koreId'): return jsonify({'code':'INVALID','message':'koreId required'}), 400 try: pg = get_pg() with pg.cursor() as cur: cur.execute(""" SELECT koreid, tx_hash, amount, currency, event_type, posted_at FROM kore_outbound_events WHERE koreid = %s """, (data['koreId'],)) row = cur.fetchone() pg.close() if not row: return jsonify({'verified': False, 'message': 'No anchor record found for KoreID'}), 404 koreid, tx_hash, amount, currency, event_type, posted_at = row payload_hash = hashlib.sha256( json.dumps({'koreId': koreid, 'amount': str(amount), 'currency': currency}, separators=(',',':')).encode() ).hexdigest() return jsonify({ 'verified': True, 'koreId': koreid, 'txHash': tx_hash, 'onChainPayloadHash': payload_hash, 'blockNumber': None, 'etherscan': f'https://etherscan.io/tx/{tx_hash}' if tx_hash else None, 'verifiedAt': datetime.now(timezone.utc).isoformat(), }) except Exception as e: return jsonify({'code':'ERROR','message':str(e)}), 500 if __name__ == '__main__': log.info("Ethereum API starting on port 8769") app.run(host='0.0.0.0', port=8769)