6. Build a web3 web with windows

6.1 tree folder

fhe-web-python/
├── app.py
├── abi.json
├── requirements.txt
├── .env
├── README.md
└── templates/
    └── index.html

6.2 . Create app.py

from flask import Flask, jsonify, render_template
from web3 import Web3
from dotenv import load_dotenv
import os
import json

load_dotenv()

app = Flask(__name__)

# Kiểm tra file
if not os.path.exists('abi.json'):
    raise FileNotFoundError("Không tìm thấy abi.json!")

# Kết nối
RPC_URL = os.getenv('RPC_URL')
w3 = Web3(Web3.HTTPProvider(RPC_URL))
if not w3.is_connected():
    raise Exception("Không kết nối được Sepolia!")

print(f"Kết nối thành công! Block: {w3.eth.block_number}")

# Contract
CONTRACT_ADDRESS = os.getenv('CONTRACT_ADDRESS')
with open('abi.json', 'r') as f:
    ABI = json.load(f)
contract = w3.eth.contract(address=CONTRACT_ADDRESS, abi=ABI)

# Account
PRIVATE_KEY = os.getenv('PRIVATE_KEY')
account = w3.eth.account.from_key(PRIVATE_KEY)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/get_count')
def get_count():
    try:
        encrypted = contract.functions.getCount().call()
        return jsonify({'count': 'Encrypted'})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/increment', methods=['POST'])
def increment():
    return send_tx('increment')

@app.route('/decrement', methods=['POST'])
def decrement():
    return send_tx('decrement')

def send_tx(func_name):
    try:
        func = getattr(contract.functions, func_name)
        # Tạo input đúng định dạng
        encrypted_input = b'\x00' * 32  # bytes32
        proof = b'\x00' * 64           # proof giả

        tx = func(encrypted_input, proof).build_transaction({
            'from': account.address,
            'gas': 3000000,
            'gasPrice': w3.to_wei('20', 'gwei'),
            'nonce': w3.eth.get_transaction_count(account.address),
        })
        signed_tx = w3.eth.account.sign_transaction(tx, PRIVATE_KEY)
        tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
        return jsonify({'tx_hash': tx_hash.hex()})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True, port=5000)

6.3 . Create abi.json : coppy your abi contract

6.4 . Create requirements.txt

flask==3.0.0
web3==6.15.1
python-dotenv==1.0.0

6.5. Create .env

RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_KEY
PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE
CONTRACT_ADDRESS=0xdcc73F30E59FB1bb4D1292f796b7e574a092ea6f
RELAYER_URL=https://relayer.testnet.zama.cloud

6.6 Create index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>FHE Counter DApp</title>
  <style>
    body { font-family: 'Segoe UI', sans-serif; text-align: center; padding: 50px; background: #f4f6f9; }
    .card { max-width: 500px; margin: 0 auto; background: white; padding: 30px; border-radius: 16px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); }
    h1 { color: #2c3e50; }
    .count { font-size: 3.5em; font-weight: bold; color: #3498db; margin: 20px 0; }
    button { padding: 12px 24px; margin: 8px; font-size: 1.1em; border: none; border-radius: 8px; cursor: pointer; transition: 0.3s; }
    .btn-inc { background: #27ae60; color: white; }
    .btn-dec { background: #e74c3c; color: white; }
    .btn-refresh { background: #3498db; color: white; }
    button:hover { transform: translateY(-2px); }
    #status { margin-top: 15px; font-style: italic; color: #7f8c8d; }
    code { background: #ecf0f1; padding: 2px 6px; border-radius: 4px; font-size: 0.9em; }
  </style>
</head>
<body>
  <div class="card">
    <h1>FHE Counter DApp</h1>
    <p>Contract: <code>0xdcc73F30E59FB1bb4D1292f796b7e574a092ea6f</code></p>
    <div class="count" id="count">Loading...</div>
    <button class="btn-inc" onclick="inc()">+1</button>
    <button class="btn-dec" onclick="dec()">-1</button>
    <br><br>
    <button class="btn-refresh" onclick="fetchCount()">Refresh</button>
    <p id="status"></p>
  </div>

  <script>
    const API = '';
    async function fetchCount() {
      document.getElementById('status').textContent = 'Đang đọc count...';
      try {
        const res = await fetch(API + 'get_count');
        const data = await res.json();
        if (data.error) throw new Error(data.error);
        document.getElementById('count').textContent = data.count;
        document.getElementById('status').textContent = 'Sẵn sàng!';
      } catch (e) {
        document.getElementById('status').textContent = 'Lỗi: ' + e.message;
      }
    }

    async function send(action) {
      document.getElementById('status').textContent = 'Đang gửi giao dịch...';
      try {
        const res = await fetch(API + action, { method: 'POST' });
        const data = await res.json();
        if (data.error) throw new Error(data.error);
        document.getElementById('status').textContent = 'Tx: ' + data.tx_hash.substring(0, 10) + '...';
        setTimeout(fetchCount, 3000);
      } catch (e) {
        document.getElementById('status').textContent = 'Lỗi: ' + e.message;
      }
    }

    function inc() { send('increment'); }
    function dec() { send('decrement'); }

    // Load ban đầu
    fetchCount();
  </script>
</body>
</html>

6.7 :Create virtual environment + settings:

python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt

ok done , now run sever

python app.py

Last updated