Transaction Details
Transaction Hash
bba16bc2085a06d97aec9257a4115d484be8ba6590513db02898f37e44d15206
↗ Base Sepolia
From
0xe1288759446298f250c3bce5616706d25525ba7f
Transaction Data
{'p': 'zentest3', 'f': 'function_snippet', 'a': ['# Paillier helpers + privacy transfer flow (ZIP23)\n\ndef _egcd(a, b):\n x0, y0 = 1, 0\n x1, y1 = 0, 1\n while b != 0:\n q = a // b\n a, b = b, a % b\n x0, x1 = x1, x0 - q * x1\n y0, y1 = y1, y0 - q * y1\n return a, x0, y0\n\ndef _modinv(a, n):\n g, x, _ = _egcd(a, n)\n assert g == 1\n return x % n\n\ndef _homomorphic_add(pub, c1, c2):\n n = pub\n n2 = n * n\n return (c1 * c2) % n2\n\ndef _homomorphic_sub(pub, c1, c2):\n n = pub\n n2 = n * n\n inv = _modinv(c2, n2)\n return (c1 * inv) % n2\n\n\n# Elliptic Curve parameters for secp256k1\nP = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F\nA = 0\nB = 7\nGx = 55066263022277343669578718895168534326250603453777594175500187360389116729240\nGy = 32670510020758816978083085130507043184471273380659243275938904335757337482424\nG = (Gx, Gy)\nN = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141\n\ndef _inverse_mod(k, p):\n if k == 0:\n raise\n return pow(k, p - 2, p)\n\ndef _is_on_curve(point):\n if point is None:\n return True\n x, y = point\n return (y * y - (x * x * x + A * x + B)) % P == 0\n\ndef _point_add(point1, point2):\n if point1 is None:\n return point2\n if point2 is None:\n return point1\n x1, y1 = point1\n x2, y2 = point2\n if x1 == x2 and y1 != y2:\n return None\n if x1 == x2:\n m = (3 * x1 * x1 + A) * _inverse_mod(2 * y1, P)\n else:\n m = (y2 - y1) * _inverse_mod(x2 - x1, P)\n m %= P\n x3 = (m * m - x1 - x2) % P\n y3 = (m * (x1 - x3) - y1) % P\n return (x3, y3)\n\ndef _scalar_mult(k, point):\n result = None\n addend = point\n while k:\n if k & 1:\n result = _point_add(result, addend)\n addend = _point_add(addend, addend)\n k >>= 1\n return result\n\ndef _ecdsa_verify(msg_hash_hex, signature_hex, public_key_hex):\n assert msg_hash_hex.startswith(\'0x\')\n assert signature_hex.startswith(\'0x\')\n assert public_key_hex.startswith(\'0x\')\n r = int(signature_hex[2:66], 16)\n s = int(signature_hex[66:130], 16)\n if not (1 <= r < N and 1 <= s < N):\n return False\n point = (int(public_key_hex[2:66], 16), int(public_key_hex[66:], 16))\n e = int(msg_hash_hex[2:], 16)\n w = _inverse_mod(s, N)\n u1 = (e * w) % N\n u2 = (r * w) % N\n q = _point_add(_scalar_mult(u1, G), _scalar_mult(u2, point))\n if q is None:\n return False\n x, y = q\n return r == x % N\n\ndef _ecdsa_recover(msg_hash_hex, signature_hex):\n assert msg_hash_hex.startswith(\'0x\')\n assert signature_hex.startswith(\'0x\')\n r = int(signature_hex[2:66], 16)\n s = int(signature_hex[66:130], 16)\n z = int(msg_hash_hex[2:], 16)\n\n if len(signature_hex[2:]) == 130:\n v = int(signature_hex[130:], 16)\n if v >= 27:\n recovery_id = v - 27\n else:\n recovery_id = v\n recovery_ids = [recovery_id]\n else:\n recovery_ids = [0, 1]\n\n for recovery_id in recovery_ids:\n for j in range(2):\n x = r + j * N\n if x >= P:\n continue\n\n y_squared = (pow(x, 3, P) + A * x + B) % P\n y = pow(y_squared, (P + 1) // 4, P)\n\n if y % 2 != recovery_id:\n y = P - y\n\n point = (x, y)\n if not _is_on_curve(point):\n continue\n\n r_inv = _inverse_mod(r, N)\n u1 = (-z * r_inv) % N\n u2 = (s * r_inv) % N\n\n q = _point_add(_scalar_mult(u1, G), _scalar_mult(u2, point))\n\n if q is None:\n continue\n\n public_key_hex = f"0x{q[0]:064x}{q[1]:064x}"\n if _ecdsa_verify(msg_hash_hex, signature_hex, public_key_hex):\n return public_key_hex\n\n return None\n\ndef _pubkey_to_address(public_key_hex):\n public_key_bytes = bytes.fromhex(public_key_hex[2:])\n address_bytes = keccak(public_key_bytes)[-20:]\n return \'0x\' + address_bytes.hex()\n\ndef _message_hash(payload):\n payload_hash = keccak(text=payload)\n prefix = b"\\x19Ethereum Signed Message:\\n32"\n return keccak(prefix + payload_hash)\n\ndef _addr_recover(msg, signature_hex):\n if not signature_hex.startswith(\'0x\'):\n signature_hex = \'0x\' + signature_hex\n msg_hash = _message_hash(msg)\n msg_hash_hex = \'0x\' + msg_hash.hex()\n public_key_hex = _ecdsa_recover(msg_hash_hex, signature_hex)\n if not public_key_hex:\n return False\n recovered = _pubkey_to_address(public_key_hex)\n return recovered.lower()\n\ndef _resolve_account(addr):\n addr = addr.lower()\n assert len(addr) <= 42\n if len(addr) == 42:\n assert addr.startswith(\'0x\')\n assert set(addr[2:]) <= set(string.digits + \'abcdef\')\n else:\n assert len(addr) > 4\n\n if len(addr) == 42:\n return handle_lookup(addr)\n return addr\n\ndef _check_tick(tick):\n assert type(tick) is str\n assert len(tick) > 0 and len(tick) < 42\n assert tick[0] in string.ascii_uppercase\n assert set(tick) <= set(string.ascii_uppercase + string.digits + \'_\')\n\n\ndef _get_pubkey(privacy_tick):\n pub, _ = get(privacy_tick, \'privacy_pub\', None)\n if pub is None:\n return None\n return int(pub)\n\n\ndef privacy_init(info, args):\n assert args[\'f\'] == \'privacy_init\'\n\n tick = args[\'a\'][0]\n _check_tick(tick)\n privacy_tick = args[\'a\'][1]\n _check_tick(privacy_tick)\n provider_addr = args[\'a\'][2]\n paillier_pub = int(args[\'a\'][3])\n\n sender = info[\'sender\']\n\n existing_provider, _ = get(privacy_tick, \'privacy_provider\', None)\n if existing_provider is not None:\n return\n\n put(provider_addr, privacy_tick, \'tick\', tick)\n put(provider_addr, privacy_tick, \'transaction_count\', 0)\n put(provider_addr, privacy_tick, \'privacy_provider\', provider_addr)\n put(provider_addr, privacy_tick, \'privacy_pub\', int(paillier_pub))\n\n\ndef privacy_update(info, args):\n assert args[\'f\'] == \'privacy_update\'\n\n # TODO\n\n\ndef privacy_deposit(info, args):\n assert args[\'f\'] == \'privacy_deposit\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n tick, _ = get(privacy_tick, \'tick\', None)\n _check_tick(tick)\n\n functions, _ = get(\'asset\', \'functions\', [], tick)\n assert args[\'f\'] in functions\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n sender = info[\'sender\']\n addr = handle_lookup(sender)\n\n existing_deposit, _ = get(privacy_tick, \'privacy_deposit\', None, addr)\n if existing_deposit:\n return\n\n amount = int(args[\'a\'][1])\n assert amount >= 0\n\n amount_cipher = int(args[\'a\'][2])\n assert amount_cipher >= 0\n\n balance, _ = get(tick, \'balance\', 0, f\'{sender}\')\n assert balance >= amount\n balance_updated = balance - amount\n put(sender, tick, \'balance\', balance_updated, f\'{sender}\')\n\n transaction_id, privacy_tick_owner = get(privacy_tick, \'transaction_count\', 0)\n transaction_id += 1\n put(privacy_tick_owner, privacy_tick, \'transaction_count\', transaction_id)\n\n put(addr, privacy_tick, \'privacy_deposit\', f\'{str(amount)},{str(amount_cipher)},{str(transaction_id)}\', f\'{addr}\')\n event(\'PrivacyDeposit\', [privacy_tick, addr, amount, amount_cipher, transaction_id])\n\n\ndef privacy_deposit_cancel(info, args):\n assert args[\'f\'] == \'privacy_deposit_cancel\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n tick, _ = get(privacy_tick, \'tick\', None)\n _check_tick(tick)\n\n functions, _ = get(\'asset\', \'functions\', [], tick)\n assert args[\'f\'] in functions\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n sender = info[\'sender\']\n addr = handle_lookup(sender)\n\n deposit_info, _ = get(privacy_tick, \'privacy_deposit\', None, addr)\n if not deposit_info:\n return\n\n parts = deposit_info.split(\',\')\n assert len(parts) == 3\n amount = int(parts[0])\n amount_cipher = int(parts[1])\n transaction_id = int(parts[2])\n\n balance, _ = get(tick, \'balance\', 0, sender)\n balance_updated = balance + amount\n put(sender, tick, \'balance\', balance_updated, sender)\n\n put(addr, privacy_tick, \'privacy_deposit\', None, addr)\n\n event(\'PrivacyDepositCancel\', [privacy_tick, addr, amount, amount_cipher, transaction_id])\n\n\ndef privacy_enter(info, args):\n assert args[\'f\'] == \'privacy_enter\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n tick, _ = get(privacy_tick, \'tick\', None)\n _check_tick(tick)\n\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n functions, _ = get(\'asset\', \'functions\', [], tick)\n assert args[\'f\'] in functions\n\n sender = info[\'sender\']\n transaction_id = int(args[\'a\'][1])\n signature_hex = args[\'a\'][2]\n\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n deposit_info, owner = get(privacy_tick, \'privacy_deposit\', 0, f\'{sender}\')\n assert deposit_info is not None\n parts = deposit_info.split(\',\')\n assert len(parts) == 3\n amount = int(parts[0])\n amount_cipher = int(parts[1])\n tx_id = int(parts[2])\n assert tx_id == transaction_id\n put(owner, privacy_tick, \'privacy_deposit\', None, f\'{sender}\')\n\n provider_addr, _ = get(privacy_tick, \'privacy_provider\', None)\n msg_to_sign = f\'{privacy_tick},privacy_deposit,{str(amount)},{str(amount_cipher)},{str(transaction_id)}\'\n\n if provider_addr.lower() != _addr_recover(msg_to_sign, signature_hex):\n return\n\n balance, _ = get(tick, \'balance\', 0, f\'{privacy_tick}\')\n assert balance >= 0\n balance_updated = balance + amount\n put(sender, tick, \'balance\', balance_updated, f\'{privacy_tick}\')\n\n balance_cipher, _ = get(privacy_tick, \'privacy_balance\', 1, f\'{sender},1\')\n balance_cipher_updated = _homomorphic_add(pub, int(balance_cipher), amount_cipher)\n put(sender, privacy_tick, \'privacy_balance\', balance_cipher_updated, f\'{sender},1\')\n\n event(\'PrivacyEnter\', [tick, sender, balance_cipher_updated])\n\n\ndef privacy_withdraw(info, args):\n assert args[\'f\'] == \'privacy_withdraw\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n sender = info[\'sender\']\n from_addr = handle_lookup(sender)\n\n existing_withdraw, _ = get(privacy_tick, \'privacy_withdraw\', None, from_addr)\n if existing_withdraw:\n return\n\n # to_addr = _resolve_account(args[\'a\'][1])\n amount = int(args[\'a\'][1])\n amount_cipher = int(args[\'a\'][2])\n\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n balance_key = f\'{from_addr},1\'\n balance_cipher, _ = get(privacy_tick, \'privacy_balance\', 1, balance_key)\n \n balance_cipher_updated = _homomorphic_sub(pub, int(balance_cipher), amount_cipher)\n put(sender, privacy_tick, \'privacy_balance\', balance_cipher_updated, balance_key)\n\n transaction_id, privacy_tick_owner = get(privacy_tick, \'transaction_count\', 0)\n transaction_id += 1\n put(privacy_tick_owner, privacy_tick, \'transaction_count\', transaction_id)\n\n put(sender, privacy_tick, \'privacy_withdraw\', f\'{str(balance_cipher)},{str(amount)},{str(amount_cipher)},{str(transaction_id)}\', from_addr)\n\n event(\'PrivacyWithdraw\', [privacy_tick, balance_cipher, amount, amount_cipher, transaction_id])\n\n\ndef privacy_withdraw_cancel(info, args):\n assert args[\'f\'] == \'privacy_withdraw_cancel\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n sender = info[\'sender\']\n from_addr = handle_lookup(sender)\n\n withdraw_info, _ = get(privacy_tick, \'privacy_withdraw\', None, from_addr)\n if not withdraw_info:\n return\n\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n parts = withdraw_info.split(\',\')\n assert len(parts) == 4\n addr = parts[0]\n amount = int(parts[1])\n amount_cipher = int(parts[2])\n transaction_id = int(parts[3])\n\n balance_key = f\'{from_addr},1\'\n balance_cipher, _ = get(privacy_tick, \'privacy_balance\', 1, balance_key)\n balance_cipher_updated = _homomorphic_add(pub, int(balance_cipher), amount_cipher)\n put(sender, privacy_tick, \'privacy_balance\', balance_cipher_updated, balance_key)\n\n put(sender, privacy_tick, \'privacy_withdraw\', None, from_addr)\n\n event(\'PrivacyWithdrawCancel\', [privacy_tick, from_addr, amount, amount_cipher, transaction_id])\n\n\ndef privacy_exit(info, args):\n assert args[\'f\'] == \'privacy_exit\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n tick, _ = get(privacy_tick, \'tick\', None)\n _check_tick(tick)\n\n functions, _ = get(\'asset\', \'functions\', [], tick)\n assert args[\'f\'] in functions\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n sender = info[\'sender\']\n transaction_id = int(args[\'a\'][1])\n signature_hex = args[\'a\'][2]\n\n withdraw_info, _ = get(privacy_tick, \'privacy_withdraw\', None, sender)\n if not withdraw_info:\n return\n\n parts = withdraw_info.split(\',\')\n assert len(parts) == 4\n balance_cipher = parts[0]\n amount = int(parts[1])\n amount_cipher = int(parts[2])\n tx_id = int(parts[3])\n assert tx_id == transaction_id\n\n provider_addr, _ = get(privacy_tick, \'privacy_provider\', None)\n msg_to_sign = f\'{privacy_tick},privacy_withdraw,{str(amount)},{str(transaction_id)}\'\n\n if provider_addr.lower() != _addr_recover(msg_to_sign, signature_hex):\n return\n\n pool_balance, _ = get(tick, \'balance\', 0, privacy_tick)\n assert pool_balance >= amount\n put(sender, tick, \'balance\', pool_balance - amount, privacy_tick)\n\n balance, _ = get(tick, \'balance\', 0, sender)\n put(sender, tick, \'balance\', balance + amount, sender)\n\n put(sender, privacy_tick, \'privacy_withdraw\', None, sender)\n\n event(\'PrivacyExit\', [privacy_tick, sender, amount_cipher])\n\n\ndef privacy_send(info, args):\n assert args[\'f\'] == \'privacy_send\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n sender = info[\'sender\']\n from_addr = handle_lookup(sender)\n from_subaccount = int(args[\'a\'][1])\n assert from_subaccount > 0\n to_addr = _resolve_account(args[\'a\'][2])\n to_subaccount = int(args[\'a\'][3])\n assert to_subaccount > 0\n amount_cipher = int(args[\'a\'][4])\n\n send_info, _ = get(privacy_tick, \'privacy_send\', None, f\'{from_addr},{str(from_subaccount)}\')\n if send_info:\n return\n\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n balance_cipher, _ = get(privacy_tick, \'privacy_balance\', from_subaccount, f\'{from_addr},{str(from_subaccount)}\')\n balance_cipher_updated = _homomorphic_sub(pub, int(balance_cipher), amount_cipher)\n put(sender, privacy_tick, \'privacy_balance\', balance_cipher_updated, f\'{from_addr},{str(from_subaccount)}\')\n\n transaction_id, privacy_tick_owner = get(privacy_tick, \'transaction_count\', 0)\n transaction_id += 1\n put(privacy_tick_owner, privacy_tick, \'transaction_count\', transaction_id)\n put(sender, privacy_tick, \'privacy_send\', f\'{str(balance_cipher)},{str(amount_cipher)},{to_addr},{str(to_subaccount)},{str(transaction_id)}\', f\'{sender},{str(from_subaccount)}\')\n\n event(\'PrivacySend\', [privacy_tick, from_addr, from_subaccount, to_addr, to_subaccount, balance_cipher, amount_cipher, transaction_id])\n\n\ndef privacy_send_cancel(info, args):\n assert args[\'f\'] == \'privacy_send_cancel\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n sender = info[\'sender\']\n from_addr = handle_lookup(sender)\n from_subaccount = int(args[\'a\'][1])\n assert from_subaccount > 0\n\n send_info_key = f\'{from_addr},{str(from_subaccount)}\'\n send_info, _ = get(privacy_tick, \'privacy_send\', None, send_info_key)\n if not send_info:\n return\n\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n parts = send_info.split(\',\')\n assert len(parts) == 5\n amount_cipher = int(parts[1])\n transaction_id = int(parts[4])\n\n balance_key = f\'{from_addr},{str(from_subaccount)}\'\n balance_cipher, _ = get(privacy_tick, \'privacy_balance\', 1, balance_key)\n balance_cipher_updated = _homomorphic_add(pub, int(balance_cipher), amount_cipher)\n put(sender, privacy_tick, \'privacy_balance\', balance_cipher_updated, balance_key)\n put(sender, privacy_tick, \'privacy_send\', None, send_info_key)\n\n event(\'PrivacySendCancel\', [privacy_tick, from_addr, from_subaccount, balance_cipher_updated, amount_cipher, transaction_id])\n\n\ndef privacy_accept(info, args):\n assert args[\'f\'] == \'privacy_accept\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n functions, _ = get(\'asset\', \'functions\', [], privacy_tick)\n assert args[\'f\'] in functions\n\n from_addr = _resolve_account(args[\'a\'][1])\n from_subaccount = int(args[\'a\'][2])\n assert from_subaccount > 0\n signature_hex = args[\'a\'][3]\n to_subaccount = int(args[\'a\'][4])\n sender = info[\'sender\']\n\n send_info, _ = get(privacy_tick, \'privacy_send\', None, f\'{from_addr},{str(from_subaccount)}\')\n if not send_info:\n return\n parts = send_info.split(\',\')\n assert len(parts) == 5\n # senderbalance_cipher = int(parts[0])\n amount_cipher = int(parts[1])\n to_addr = parts[2]\n to_subaccount = int(parts[3])\n transaction_id = int(parts[4])\n assert to_addr == sender\n\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n provider_addr, _ = get(privacy_tick, \'privacy_provider\', None)\n msg_to_sign = f\'{privacy_tick},privacy_send,{from_addr},{str(from_subaccount)},{str(transaction_id)}\'\n if provider_addr.lower() != _addr_recover(msg_to_sign, signature_hex):\n return\n\n balance_cipher, _ = get(privacy_tick, \'privacy_balance\', 1, f\'{to_addr},{str(to_subaccount)}\')\n balance_cipher_updated = _homomorphic_add(pub, int(balance_cipher), amount_cipher)\n put(to_addr, privacy_tick, \'privacy_balance\', balance_cipher_updated, f\'{to_addr},{str(to_subaccount)}\')\n put(from_addr, privacy_tick, \'privacy_send\', None, f\'{from_addr},{str(from_subaccount)}\')\n\n event(\'PrivacyAccept\', [privacy_tick, to_subaccount, balance_cipher_updated, amount_cipher, transaction_id])\n\n\ndef privacy_decline(info, args):\n assert args[\'f\'] == \'privacy_decline\'\n\n privacy_tick = args[\'a\'][0]\n _check_tick(privacy_tick)\n from_addr = _resolve_account(args[\'a\'][1])\n from_subaccount = int(args[\'a\'][2])\n assert from_subaccount > 0\n sender = info[\'sender\']\n\n send_info, _ = get(privacy_tick, \'privacy_send\', None, f\'{from_addr},{str(from_subaccount)}\')\n if not send_info:\n return\n parts = send_info.split(\',\')\n assert len(parts) == 5\n amount_cipher = int(parts[1])\n to_addr = parts[2]\n transaction_id = int(parts[4])\n assert to_addr == sender\n\n pub = _get_pubkey(privacy_tick)\n assert pub is not None\n\n balance_cipher, _ = get(privacy_tick, \'privacy_balance\', 1, f\'{from_addr},{str(from_subaccount)}\')\n balance_cipher_updated = _homomorphic_add(pub, int(balance_cipher), amount_cipher)\n put(from_addr, privacy_tick, \'privacy_balance\', balance_cipher_updated, f\'{from_addr},{str(from_subaccount)}\')\n put(from_addr, privacy_tick, \'privacy_send\', None, f\'{from_addr},{str(from_subaccount)}\')\n\n event(\'PrivacyDecline\', [privacy_tick, from_addr, from_subaccount, balance_cipher_updated, amount_cipher, transaction_id])\n\n']}
Events
[['function_snippet', 'NewFunctionSnippet', '3b531f43aeb51b13e57b9b7943c0abe2ac7f4ad66cbfe578668d5ba2210223b8']]