Add koreid.py
This commit is contained in:
289
koreid.py
Normal file
289
koreid.py
Normal file
@@ -0,0 +1,289 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Vector Zulu — KoreID Generator
|
||||
Generates KoreID display numbers per the KoreID Display Generation Specification.
|
||||
|
||||
Format: <S1>/<S2>-<S3>-<S4>-<S5>-<S6>
|
||||
Example: 061925a1/b231f4e5-3487-0a1b-03e8-001540009abc
|
||||
|
||||
S1 (8) = DDMMYY (6-digit UTC date) + CT (2-hex ID-type)
|
||||
S2 (8) = PT (2-hex parent ID-type) + T (1-hex parent treasury) + PNNNNN (5-hex parent network)
|
||||
S3 (4) = CCC (3-hex ISO currency) + CK (1-hex XOR checksum)
|
||||
S4 (4) = First 4 hex of current 8-hex network code
|
||||
S5 (4) = Last 4 hex of current 8-hex network code
|
||||
S6 (12) = PPPP (4-hex parent monthly seq) + T (1-hex current treasury) + CCCC (4-hex current monthly seq) + RRR (3-hex nonce)
|
||||
"""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import hashlib
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from functools import reduce
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# ── Lookup tables (placeholders — populate from Bryan's full spec) ────────────
|
||||
|
||||
# kore_id_type: maps event type names to 2-hex codes
|
||||
# TODO: replace with values from Bryan's kore_id_type SQL table
|
||||
ID_TYPES = {
|
||||
'MINT': 'a1', # SV token mint event
|
||||
'BURN': 'a2', # SV token burn/redemption event
|
||||
'TRANSFER': 'a3', # SV token transfer event
|
||||
'RESERVE': 'a4', # Reserve oracle update
|
||||
'SWAP': 'a5', # Uniswap swap event
|
||||
'ONRAMP': 'a6', # Fiat on-ramp
|
||||
'OFFRAMP': 'a7', # Fiat off-ramp
|
||||
'EXTERNAL': 'b1', # Generic external response
|
||||
}
|
||||
|
||||
# kore_treasury: maps treasury names to 1-hex codes
|
||||
# TODO: replace with values from Bryan's kore_treasury SQL table
|
||||
TREASURIES = {
|
||||
'VECTOR_ZULU': '1',
|
||||
'SOVEREIGN_GLOBAL': '2',
|
||||
'KORE_COLLECTIVE': '3',
|
||||
'MERIDIAN': '4',
|
||||
}
|
||||
|
||||
# kore_network: maps network names to 5-hex parent network codes
|
||||
# TODO: replace with values from Bryan's kore_network SQL table
|
||||
PARENT_NETWORKS = {
|
||||
'KORECHAIN': 'f4e50',
|
||||
'ETHEREUM': '0a1b0',
|
||||
'AMITIS': '03e80',
|
||||
'TRON': '00154',
|
||||
}
|
||||
|
||||
# kore_network_current: maps network names to 8-hex current network codes
|
||||
# TODO: replace with values from Bryan's kore_network_current SQL table
|
||||
CURRENT_NETWORKS = {
|
||||
'ETHEREUM': '0a1b03e8',
|
||||
'AMITIS': '03e80015',
|
||||
'KORECHAIN': 'f4e5b231',
|
||||
'TRON': '001540ab',
|
||||
}
|
||||
|
||||
# kore_currency: maps ISO currency codes to 3-hex values
|
||||
# TODO: replace with values from Bryan's kore_currency SQL table
|
||||
CURRENCIES = {
|
||||
'USD': '001',
|
||||
'GBP': '002',
|
||||
'EUR': '003',
|
||||
'CHF': '004',
|
||||
'JPY': '005',
|
||||
'SGD': '006',
|
||||
'BTC': '010',
|
||||
'ETH': '011',
|
||||
'USDT': '012',
|
||||
'USDC': '013',
|
||||
'GPSC': '020',
|
||||
'AMTS': '030',
|
||||
}
|
||||
|
||||
# Parent ID type for VZ as a child of KoreChain
|
||||
PARENT_ID_TYPE = 'b2' # TODO: confirm with Bryan
|
||||
|
||||
|
||||
class KoreIDGenerator:
|
||||
"""
|
||||
Generates KoreID display numbers for events originating from Vector Zulu.
|
||||
Requires a sequence store (Postgres) for monthly sequence tracking.
|
||||
"""
|
||||
|
||||
def __init__(self, pg_conn=None):
|
||||
self.pg = pg_conn
|
||||
|
||||
def _xor_checksum(self, hex_string: str) -> str:
|
||||
"""XOR all bytes of a hex string, return 1-hex result."""
|
||||
bytes_list = [int(hex_string[i:i+2], 16) for i in range(0, len(hex_string), 2)]
|
||||
result = reduce(lambda a, b: a ^ b, bytes_list, 0)
|
||||
return format(result & 0xF, 'x')
|
||||
|
||||
def _get_sequence(self, mmyy: str, id_type: str, treasury: str,
|
||||
network: str, currency: str) -> tuple[int, int]:
|
||||
"""
|
||||
Get or create monthly sequence entry.
|
||||
Returns (parent_seq, current_seq) — increments current_seq.
|
||||
Falls back to random if no DB connection.
|
||||
"""
|
||||
if not self.pg:
|
||||
import random
|
||||
return (random.randint(0, 0xFFFF), random.randint(0, 0xFFFF))
|
||||
|
||||
try:
|
||||
with self.pg.cursor() as cur:
|
||||
cur.execute("""
|
||||
INSERT INTO kore_sequence (mmyy, ct, t, net, ccc, parent_seq, current_seq)
|
||||
VALUES (%s, %s, %s, %s, %s, 0, 1)
|
||||
ON CONFLICT (mmyy, ct, t, net, ccc)
|
||||
DO UPDATE SET current_seq = kore_sequence.current_seq + 1
|
||||
RETURNING parent_seq, current_seq
|
||||
""", (mmyy, id_type, treasury, network, currency))
|
||||
row = cur.fetchone()
|
||||
self.pg.commit()
|
||||
return (row[0], row[1])
|
||||
except Exception as e:
|
||||
log.error(f"Sequence DB error: {e}")
|
||||
import random
|
||||
return (random.randint(0, 0xFFFF), random.randint(0, 0xFFFF))
|
||||
|
||||
def generate(
|
||||
self,
|
||||
event_type: str,
|
||||
currency: str,
|
||||
current_network: str = 'ETHEREUM',
|
||||
parent_network: str = 'KORECHAIN',
|
||||
treasury: str = 'VECTOR_ZULU',
|
||||
parent_treasury: str = 'KORE_COLLECTIVE',
|
||||
nonce: str = None,
|
||||
) -> dict:
|
||||
"""
|
||||
Generate a KoreID for a Vector Zulu event.
|
||||
|
||||
Returns dict with:
|
||||
- koreid: the display ID string
|
||||
- guid: UUIDv4 for internal storage
|
||||
- metadata: all components for traceability
|
||||
"""
|
||||
now = datetime.now(timezone.utc)
|
||||
mmyy = now.strftime('%m%y')
|
||||
ddmmyy = now.strftime('%d%m%y')
|
||||
|
||||
# Resolve codes
|
||||
ct = ID_TYPES.get(event_type.upper(), 'ff')
|
||||
pt = PARENT_ID_TYPE
|
||||
t = TREASURIES.get(treasury.upper(), '0')
|
||||
pt_val = TREASURIES.get(parent_treasury.upper(), '0')
|
||||
pnnnnn = PARENT_NETWORKS.get(parent_network.upper(), '00000')
|
||||
ccc = CURRENCIES.get(currency.upper(), '000')
|
||||
net8 = CURRENT_NETWORKS.get(current_network.upper(), '00000000')
|
||||
|
||||
# S1: DDMMYY + CT
|
||||
s1 = ddmmyy + ct # 8 chars
|
||||
|
||||
# S2: PT + T(parent) + PNNNNN
|
||||
s2 = pt + pt_val + pnnnnn # 8 chars
|
||||
|
||||
# S3: CCC + checksum
|
||||
ck = self._xor_checksum(ccc + '0') # XOR of currency bytes
|
||||
s3 = ccc + ck # 4 chars
|
||||
|
||||
# S4 / S5: split current network code
|
||||
s4 = net8[:4] # 4 chars
|
||||
s5 = net8[4:] # 4 chars
|
||||
|
||||
# S6: PPPP + T(current) + CCCC + RRR
|
||||
parent_seq, current_seq = self._get_sequence(mmyy, ct, t, pnnnnn, ccc)
|
||||
pppp = format(parent_seq & 0xFFFF, '04x')
|
||||
cccc = format(current_seq & 0xFFFF, '04x')
|
||||
|
||||
if nonce is None:
|
||||
import random
|
||||
nonce = format(random.randint(0, 0xFFF), '03x')
|
||||
|
||||
s6 = pppp + t + cccc + nonce # 12 chars
|
||||
|
||||
koreid = f"{s1}/{s2}-{s3}-{s4}-{s5}-{s6}"
|
||||
guid = str(uuid.uuid4())
|
||||
|
||||
return {
|
||||
'koreid': koreid,
|
||||
'guid': guid,
|
||||
'components': {
|
||||
's1': s1, 's2': s2, 's3': s3,
|
||||
's4': s4, 's5': s5, 's6': s6,
|
||||
},
|
||||
'metadata': {
|
||||
'event_type': event_type,
|
||||
'currency': currency,
|
||||
'current_network': current_network,
|
||||
'parent_network': parent_network,
|
||||
'treasury': treasury,
|
||||
'generated_at': now.isoformat(),
|
||||
'id_type_code': ct,
|
||||
'parent_seq': parent_seq,
|
||||
'current_seq': current_seq,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def wrap_ethereum_event(
|
||||
event_type: str,
|
||||
amount: float,
|
||||
currency: str,
|
||||
tx_hash: str,
|
||||
block_number: int,
|
||||
from_address: str,
|
||||
to_address: str,
|
||||
token_symbol: str,
|
||||
koreid_generator: KoreIDGenerator,
|
||||
linked_koreid: str = None,
|
||||
) -> dict:
|
||||
"""
|
||||
Convert an Ethereum event into a KoreID-formatted payload
|
||||
for posting back to KoreChain via KoreOracle.
|
||||
|
||||
Preserves full traceability per Bryan's spec:
|
||||
- KoreID reference
|
||||
- hash (TX hash)
|
||||
- signature (block + tx proof)
|
||||
- chain linkage
|
||||
"""
|
||||
kid = koreid_generator.generate(
|
||||
event_type=event_type,
|
||||
currency=currency,
|
||||
current_network='ETHEREUM',
|
||||
parent_network='KORECHAIN',
|
||||
)
|
||||
|
||||
payload = {
|
||||
'koreid': kid['koreid'],
|
||||
'guid': kid['guid'],
|
||||
'value': amount,
|
||||
'proof': {
|
||||
'hash': tx_hash,
|
||||
'block_number': block_number,
|
||||
'chain_reference': kid['koreid'],
|
||||
'network': 'ETHEREUM',
|
||||
'network_code': CURRENT_NETWORKS.get('ETHEREUM'),
|
||||
},
|
||||
'source': {
|
||||
'type': 'ETHEREUM_EVENT',
|
||||
'event_type': event_type,
|
||||
'token': token_symbol,
|
||||
'from_address': from_address,
|
||||
'to_address': to_address,
|
||||
'tx_hash': tx_hash,
|
||||
},
|
||||
'linked_to': linked_koreid,
|
||||
'generated_at': datetime.now(timezone.utc).isoformat(),
|
||||
}
|
||||
|
||||
return payload
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Test generation
|
||||
gen = KoreIDGenerator()
|
||||
result = gen.generate('MINT', 'GBP', 'ETHEREUM', 'KORECHAIN', 'VECTOR_ZULU')
|
||||
print("Generated KoreID:", result['koreid'])
|
||||
print("GUID:", result['guid'])
|
||||
print("Components:", result['components'])
|
||||
|
||||
# Test event wrapping
|
||||
payload = wrap_ethereum_event(
|
||||
event_type='MINT',
|
||||
amount=1000000.00,
|
||||
currency='GBP',
|
||||
tx_hash='0xabc123def456',
|
||||
block_number=25375588,
|
||||
from_address='0x0000000000000000000000000000000000000000',
|
||||
to_address='0x8B59352944134D6c2e175d92Bb07b25443163A53',
|
||||
token_symbol='SVGBP',
|
||||
koreid_generator=gen,
|
||||
)
|
||||
import json
|
||||
print("\nWrapped payload:")
|
||||
print(json.dumps(payload, indent=2))
|
||||
Reference in New Issue
Block a user