diff --git a/.github/workflows/Docker-Deploy.yml b/.github/workflows/Docker-Deploy.yml index 3c5e1e6..9493dd3 100644 --- a/.github/workflows/Docker-Deploy.yml +++ b/.github/workflows/Docker-Deploy.yml @@ -94,3 +94,99 @@ jobs: docker compose -f docker-compose.prod.yml up -d docker compose -f docker-compose.prod.yml ps + + # ========================================================= + # Update backend .env with deployed contract addresses + # ========================================================= + + ADDRESS_FILE="/opt/NettedX/NettedX-Blockchain/address-data/addresses.json" + ENV_FILE="/opt/NettedX/nettedx-back/.env" + + echo "Reading contract addresses from ${ADDRESS_FILE}" + + test -f "${ADDRESS_FILE}" + + python3 - "${ADDRESS_FILE}" "${ENV_FILE}" <<'PY' + import json + import os + import sys + import tempfile + + address_file = sys.argv[1] + env_file = sys.argv[2] + + with open(address_file, "r") as f: + addresses = json.load(f) + + keys = [ + "NETTEDX_MOCK_USDC_CONTRACT_ADDRESS", + "NETTEDX_MOCK_BOND_CONTRACT_ADDRESS", + "NETTEDX_SETTLEMENT_CONTRACT_ADDRESS", + "NETTEDX_NETTING_CONTRACT_ADDRESS", + "NETTEDX_LIQUIDITY_BUFFER_CONTRACT_ADDRESS", + ] + + # Validate all required addresses exist + for key in keys: + if key not in addresses: + raise RuntimeError( + f"Missing {key} in {address_file}" + ) + + if not addresses[key]: + raise RuntimeError( + f"Empty value for {key}" + ) + + with open(env_file, "r") as f: + lines = f.readlines() + + updated = set() + result = [] + + for line in lines: + stripped = line.lstrip() + + if "=" in line and not stripped.startswith("#"): + key = line.split("=", 1)[0] + + if key in addresses and key in keys: + result.append(f"{key}={addresses[key]}\n") + updated.add(key) + continue + + result.append(line) + + # Add missing keys + for key in keys: + if key not in updated: + result.append(f"{key}={addresses[key]}\n") + + # Atomic replacement of .env + directory = os.path.dirname(os.path.abspath(env_file)) + + fd, temp_file = tempfile.mkstemp( + dir=directory, + prefix=".env.", + text=True, + ) + + try: + with os.fdopen(fd, "w") as f: + f.writelines(result) + + os.replace(temp_file, env_file) + except Exception: + try: + os.unlink(temp_file) + except FileNotFoundError: + pass + raise + + print("Updated contract addresses:") + + for key in keys: + print(f"{key}={addresses[key]}") + PY + + echo "Backend .env updated successfully." \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0295cc0..0e1bbc9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,9 @@ docs/ .env.* !.env.example -# anvil-data -anvil_state.json +# data +anvil-data/ +address-data/ + +# DS_Store files +.DS_Store diff --git a/Dockerfile b/Dockerfile index 4ec9257..e7563fa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,9 @@ COPY --chown=foundry:foundry . . RUN git config --global --add safe.directory /app +# For data directory +RUN mkdir -p /app/address-data + RUN forge build RUN forge test \ No newline at end of file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 10ce582..21d3432 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -33,7 +33,7 @@ services: - "${ANVIL_PORT}:8545" volumes: - - anvil-data:/var/data + - ./anvil-data:/var/data healthcheck: test: @@ -71,5 +71,6 @@ services: - ${RPC_URL} - --broadcast -volumes: - anvil-data: \ No newline at end of file + volumes: + - ./broadcast:/app/broadcast + - ./address-data:/app/address-data \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index e73a2eb..0b4fe8b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,7 +32,7 @@ services: - "${ANVIL_PORT}:${ANVIL_PORT}" volumes: - - anvil-data:/var/data + - ./anvil-data:/var/data healthcheck: test: @@ -72,5 +72,6 @@ services: - ${RPC_URL} - --broadcast -volumes: - anvil-data: \ No newline at end of file + volumes: + - ./broadcast:/app/broadcast + - ./address-data:/app/address-data diff --git a/foundry.toml b/foundry.toml index 25b918f..cad7d8c 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,5 +2,8 @@ src = "src" out = "out" libs = ["lib"] +fs_permissions = [ + { access = "read-write", path = "./address-data" } +] # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index 3983926..710d62e 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -98,5 +98,25 @@ contract Deploy is Script { console2.log("NETTING:", address(netting)); console2.log("LIQUIDITY_BUFFER:", address(liquidityBuffer)); + + // ========================================================= + // Generate contract address file + // ========================================================= + + string memory filePath = "./address-data/addresses.json"; + + string memory json = vm.serializeAddress("addresses", "NETTEDX_MOCK_USDC_CONTRACT_ADDRESS", address(usdc)); + + json = vm.serializeAddress("addresses", "NETTEDX_MOCK_BOND_CONTRACT_ADDRESS", address(bond)); + + json = vm.serializeAddress("addresses", "NETTEDX_SETTLEMENT_CONTRACT_ADDRESS", address(settlement)); + + json = vm.serializeAddress("addresses", "NETTEDX_NETTING_CONTRACT_ADDRESS", address(netting)); + + json = vm.serializeAddress("addresses", "NETTEDX_LIQUIDITY_BUFFER_CONTRACT_ADDRESS", address(liquidityBuffer)); + + vm.writeJson(json, filePath); + + console2.log("Contract addresses written to:", filePath); } }