Skip to content

Java backend simulating a blockchain-based crypto trading platform with smart contracts, digital signing, and real-time market data. This challenge deepened my understanding of blockchain mechanics, RSA encryption, and rule-based transaction validation.

Notifications You must be signed in to change notification settings

jraporta/The-Game-is-Hackathon-Blockchain

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 

Repository files navigation

Finished in the 4th place, great learning experience!

final_score

🏦 CaixaBank Java Backend Challenge ☕️

Category: Software
Subcategory: Java Backend
Difficulty: Medium


🌐 Background

In this challenge you will build a Java backend application that simulates a simplified blockchain and cryptocurrency trading platform. The app includes user authentication, wallet management, transaction processing, live market data fetching, blockchain simulation (with mining and chain validation), digital key generation, and the implementation of Smart Contracts with digital signing.

Smart Contracts allow you to set rules on trading operations (for example, to prevent excessively large transactions by “anti-whale” mechanisms) by defining conditions (using a dynamic expression language) that must be met before a transaction is accepted. Each smart contract is associated with a liquidity wallet (for base assets like USDT) and is digitally signed using RSA.

For additional information on the proposed functioning of our blockchain, please download the file: Blockchain Guide

API Endpoint: https://faas-lon1-917a94a7.doserverless.co/api/v1/web/fn-3d8ede30-848f-4a7a-acc2-22ba0cd9a382/default/fake-market-prices


📂 Repository Structure

hackathon-caixabank-backend-java-blockchain
├── blockchain
│   ├── cookies.txt
│   ├── docker-compose.yml
│   ├── Dockerfile
│   ├── keys
│   ├── mvnw
│   ├── mvnw.cmd
│   ├── pom.xml
│   └── src
│       ├── main
│       │   ├── java
│       │   │   └── com
│       │   │       └── hackathon
│       │   │           └── blockchain
│       │   │               ├── BlockchainApplication.java
│       │   │               ├── config
│       │   │               │   └── CorsConfig.java
│       │   │               ├── controller
│       │   │               │   ├── DashboardController.java
│       │   │               │   └── HealthCheckController.java
│       │   │               ├── dto
│       │   │               ├── model
│       │   │               ├── repository
│       │   │               ├── service
│       │   │               │   ├── BlockchainService.java
│       │   │               │   ├── MarketDataService.java
│       │   │               │   ├── SmartContractEvaluationService.java
│       │   │               │   ├── UserService.java
│       │   │               │   ├── WalletKeyService.java
│       │   │               │   └── WalletService.java
│       │   │               └── utils
│       │   └── resources
│       │       └── application.properties
│       └── test
│           └── java
│               └── com
│                   └── hackathon
│                       └── blockchain
│                           └── BlockchainApplicationTests.java
└── README.md

🎯 Tasks

  1. Task 1: Dockerfile & Health Check
  2. Task 2: User Login, Register and Session Management
  3. Task 3: Wallet & Live Data Fetching
  4. Task 4: Transactions
  5. Task 5: Blockchain Simulation
  6. Task 6: Digital Signing
  7. Task 7: Smart Contracts

Please read the entire README and code carefully, as well as the detailed guides below, to fully understand the requirements of the challenge.


📑 Detailed Information About Tasks

Task 1: Dockerfile & Health Check

The first thing to do is to configure the Dockerfile to be able to test the application in containers.

A health check endpoint is provided to which a first request will be sent to check that the container is working properly.

Before doing the first push, you should make sure that this file works correctly, as all other tasks will be tested by attacking the endpoint generated by this container on port 3000.

The contents of the /target folder must not be used for this task.


Task 2: User Login, Register and Session Management

  • Objective:
    Create a full authentication circuit including registration, login (with session creation) and logout.
  • Endpoints:
    • POST /auth/register:
      Request:
      {
        "email": "user@example.com",
        "username": "user123",
        "password": "securePassword"
      }
      Response (HTTP 200):
      {"message": "User registered and logged in successfully"}
    • POST /auth/login:
      Request:
      {
        "username": "user@example.com",
        "password": "securePassword"
      }
      Response (HTTP 200):
      {"message": "Login successful"}
      Errors:
      • 401:
        {"message": "❌ Invalid credentials"}
    • GET /auth/check-session:
      Response (HTTP 200):
      {"user": {"username": "user123"}}
      Or 401 if no active session.
    • POST /auth/logout:
      Response (HTTP 200):
      {"message": "Logged out successfully"}

Task 3: Wallet & Live Data Fetching

  • Objective:
    Implement wallet creation and live market data endpoints.
  • Endpoints:
    • POST /wallet/create:
      • Must be an authenticated request.
      • New wallets start with a fiat balance of 100,000$.
      • Response (HTTP 200):
        {"message": "✅ Wallet successfully created! Address: <wallet_address>"}
    • POST /wallet/generate-keys:
      • Generates an RSA key pair for the wallet (PEM)
      • Stores keys in the database and as files (in a /keys folder inside the container or volume). The name of the files are: wallet_<wallet_id>_private.pem and wallet_<wallet_id>_public.pem
      • Response (HTTP 200):
        {
          "message": "Keys generated/retrieved successfully for wallet id: <id>",
          "publicKey": "-----BEGIN PUBLIC KEY-----\n...-----END PUBLIC KEY-----\n",
          "absolutePath": "/abs/path/to/keys"
        }
    • GET /market/prices:
      Returns live (or simulated) market prices:
      { "BTC": 35000.0, "ETH": 2500.0, "USDT": 1.0, "NCOIN": 10, "CCOIN": 10 }
    • GET /market/price/{symbol}:
      Returns a price for a specific asset:
      • HTTP 200:
        {"message": "Current price of BTC: $35000.0"}
      • HTTP 400 if not found.

Task 4: Transactions

  • Objective:
    Implement buying and selling of assets and maintain transaction history.
  • Endpoints:
    • POST /wallet/buy:
      • Authenticated request.
      • Request (example):
        { "symbol": "BTC", "quantity": 0.5 }
      • Important: Before processing the buy, the endpoint dynamically checks if the asset has a smart contract associated with its liquidity wallet (see Task 7 below). If such a contract exists and the transaction violates the contract condition, the transaction is blocked (and not saved in the DB).
      • Response (HTTP 200):
        {"message": "✅ Asset purchased successfully!"}
      • Error:
        {"message": "❌ Transaction blocked by smart contract conditions for BTC"}
    • POST /wallet/sell:
      • Similar to the buy endpoint, with dynamic validation against a smart contract if one exists.
    • GET /wallet/balance:
      • Returns wallet details:
        {
          "wallet_address": "<wallet_address>",
          "cash_balance": 100000.0,
          "net_worth": 150000.0,
          "assets": { "BTC": 0.5, "ETH": 3.0, ... }
        }
    • GET /wallet/transactions:
      • Returns transaction history, divided into "sent" and "received" lists.
      {
        "sent": [
          {
            "id": 1,
            "assetSymbol": "BTC",
            "amount": 0.5,
            "pricePerUnit": 35000.0,
            "type": "BUY",
            "timestamp": "2025-02-18T12:34:56.789Z",
            "status": "MINED",
            "fee": 0.0,
            "senderWalletId": 2,
            "receiverWalletId": 3
          }
        ],
        "received": [
          {
            "id": 2,
            "assetSymbol": "ETH",
            "amount": 2.0,
            "pricePerUnit": 2500.0,
            "type": "SELL",
            "timestamp": "2025-02-18T13:45:00.123Z",
            "status": "MINED",
            "fee": 0.0,
            "senderWalletId": 3,
            "receiverWalletId": 2
          }
        ]
      }

Task 5: Blockchain Simulation

  • Objective:
    Simulate a blockchain by grouping pending transactions into blocks.
  • Endpoints:
    • POST /blockchain/mine:
      • Mines a new block containing pending transactions.
      • Response (HTTP 200):
        {"message": "Block mined: <block_hash>"}
      • Error (HTTP 400):
        {"message": "❌ No pending transactions to mine."}
    • GET /blockchain:
      • Returns the blockchain as an array of blocks.
      [
        {
          "id": 1,
          "blockIndex": 0,
          "timestamp": 1739921419757,
          "previousHash": "0",
          "nonce": 77403,
          "hash": "000054ba7a15300dcc48ccc86d6402f1086717bb0ff828a050892524fff8412a",
          "genesis": true
        },
        {
          "id": 2,
          "blockIndex": 1,
          "timestamp": 1739926453603,
          "previousHash": "000054ba7a15300dcc48ccc86d6402f1086717bb0ff828a050892524fff8412a",
          "nonce": 62319,
          "hash": "0000f393638957ef5d7d835a9fe2e5654da67b9303abbd02ae8e82dc0762f896",
          "genesis": false
        },
        {
          "id": 3,
          "blockIndex": 2,
          "timestamp": 1739926650238,
          "previousHash": "0000f393638957ef5d7d835a9fe2e5654da67b9303abbd02ae8e82dc0762f896",
          "nonce": 596,
          "hash": "00004bc719f169f3a0364172593e276e13a631f94084bc45ae4d95ecbdb83f57",
          "genesis": false
        }
      ]
    • GET /blockchain/validate:
      • Returns whether the blockchain is valid:
        {"message": "Blockchain valid: true"}
        or if the chain is invalid,
        {"message": "Blockchain valid: false"}

At the start of the application, a series of processes detailed below must be executed:

  • Create wallets for the currencies with the following format: ‘LP-COINNAME’. These wallets do not have an initial balance of fiat money, they only have the related assets.
  • As a liquidity pool, they are initially allocated a certain number of assets. BTC: 100000, ETH: 400000, USDT: 1000000, NCOIN: 10000000, CCOIN: 2000000.
  • A genesis block will have to be created as the first block in the chain with no associated transactions.

Task 6: Digital Signing

  • Objective:
    Implement RSA-based digital signing for wallet keys and smart contracts.
  • Implementation:
    • Each wallet generates an RSA key pair (via /wallet/generate-keys).
    • Smart contracts are signed using the issuer wallet’s private key.
    • In the case of the smart contracts that will be created later by default for a coin at the startup of the application, these will be signed by a system key that is generated separately and without using the endpoint.

Task 7: Smart Contracts

  • Objective:
    Implement a Smart Contracts module that allows setting trading rules (e.g., anti-whale measures) using dynamic conditions (via SpEL) and digital signing.

    • Dynamic Validation:
      When a user submits a buy (or sell) transaction, the endpoint dynamically checks if a smart contract exists for the asset’s liquidity pool.
      • It retrieves the liquidity wallet by address ("LP-" + symbol.toUpperCase()).
      • It retrieves the smart contract linked to that wallet (via issuerWalletId).
      • It evaluates the condition using SpEL with variables (e.g., amount and txType).
      • If the condition fails (e.g., for an anti-whale rule, if the purchase amount is too high), the endpoint returns an error (HTTP 400) and the transaction is not persisted.
    • Manual Creation of Smart Contracts:
      Additionally, a dedicated controller allows manually creating smart contracts.
      • Endpoint: POST /contracts/create
      • Request Body (JSON):
        {
          "name": "Contract example",
          "conditionExpression": "#amount > 10",
          "action": "CANCEL_TRANSACTION",
          "actionValue": 0.0,
          "issuerWalletId": 5
        }
      • Behavior:
        The endpoint retrieves the private key of the issuer wallet (via WalletKeyService), signs the contract data, and stores the contract with its digital signature in the database.
      • Response:
        Returns the smart contract object created in JSON, including the digitalSignature field.
    • Validation Endpoint:
      An endpoint to validate a smart contract’s signature:
      • Endpoint: GET /contracts/validate/{id}
      • Behavior:
        Retrieves the smart contract by ID, obtains the public key of the issuer wallet, reconstructs the signed data, and verifies the digital signature.
      • Response:
        {"message": "Smart contract is valid"}
        o
        {"message": "Smart contract is invalid"}
  • Automatic Association:
    At startup (via the StartupRunner), smart contract is automatically created for BTC liquidity pool wallet with predefined conditions (anti-whale: blocking BUY transactions exceeding 10,000 units).


💫 Guides

📋 Endpoints Table

Endpoint Method Auth Possible Status Codes Response Example
GET /health GET No 200, 500 200 OK: "OK"
User Endpoints
/auth/register POST No 200, 400, 500 200 OK: {"message": "User registered and logged in successfully"}
/auth/login POST No 200, 400, 401, 500 200 OK: {"message": "Login successful"}
/auth/check-session GET Yes 200, 401, 500 200 OK: {"user": {"username": "user123"}}
/auth/logout POST Yes 200, 401 200 OK: {"message": "Logged out successfully"}
Wallet & Key Endpoints
/wallet/create POST Yes 200, 401, 500 200 OK: {"message": "✅ Wallet successfully created! Address: <wallet_address>"}
/wallet/generate-keys POST Yes 200, 401, 404, 500 200 OK: { "message": "Keys generated/retrieved successfully for wallet id: <id>", "publicKey": "-----BEGIN PUBLIC KEY-----\n...", "absolutePath": "/abs/path/to/keys" }
/wallet/transactions GET Yes 200, 401, 404, 500 200 OK: { "sent": [ ... ], "received": [ ... ] }
/wallet/balance GET Yes 200, 401, 404 200 OK: JSON con información de la wallet (address, cash_balance, net_worth, assets)
/wallet/buy POST Yes 200, 400, 401, 500 200 OK: {"message": "✅ Asset purchased successfully!"}
400 Bad Request: {"message": "❌ Transaction blocked by smart contract conditions for BTC"}
/wallet/sell POST Yes 200, 400, 401, 500 200 OK: {"message": "✅ Asset sold successfully!"}
400 Bad Request: {"message": "❌ Transaction blocked by smart contract conditions for BTC"}
Blockchain Endpoints
/blockchain/mine POST Optional 200, 400, 500 200 OK: {"message": "Block mined: <block_hash>"}
400: {"message": "❌ No pending transactions to mine."}
/blockchain GET Optional 200, 500 200 OK: JSON array de bloques
/blockchain/validate GET Optional 200, 500 200 OK: {"message": "Blockchain valid: true"}
Market & Dashboard Endpoints
/market/prices GET No 200, 500 200 OK: { "BTC": 35000.0, "ETH": 2500.0, "USDT": 1.0, ... }
/market/price/{symbol} GET No 200, 400, 500 200 OK: {"message": "Current price of BTC: $35000.0"}
400: {"message": "❌ Asset not found or price unavailable: BTC"}
/api/dashboard GET Yes 200, 401 200 OK: "Welcome to your dashboard, user123! Your registered email is: user@example.com"
Smart Contract Endpoints
/contracts/create POST Yes 200, 400, 401, 500 200 OK: JSON del smart contract creado, incluyendo sus campos y la digitalSignature
/contracts/validate/{id} GET Optional 200, 404, 500 200 OK: {"message": "Smart contract is valid"} o {"message": "Smart contract is invalid"}

More information

The application.properties file contains the configuration necessary for the correct functioning of the application.

The backend tests will simulate the interaction of a user directly with the API running in a container and exposed on port 3000

Final app behaviour

  1. App start:

    • Build the application in a Docker container on port 3000.
    • The /health endpoint confirms that the container is running.
    • In the StartupRunner:
      • Liquidity pools are initialized with predefined assets (BTC, ETH, USDT, etc.).
      • Predefined Smart Contract for BTC is initialized.
      • The blockchain is initialized (including the genesis block).
  2. User Management:

    • Users register (/auth/register), log in (/auth/login), check session (/auth/check-session) and log out (/auth/logout).
  3. Wallet & Key Management:

    • Users create their personal wallets (/wallet/create).
    • RSA key pairs are generated and stored via /wallet/generate-keys.
    • Transaction history and wallet balance can be retrieved.
  4. Trading & Blockchain Operations:

    • Users execute buy (/wallet/buy) and sell (/wallet/sell) orders.
    • Before processing, the system dynamically checks if a smart contract is associated to the liquidity wallet (e.g., "LP-BTC") and evaluates its condition (using SpEL with variables such as amount and txType).
    • If the condition fails (for example, if the transaction exceeds a predefined limit), the operation is blocked and returns an error without saving the transaction.
    • Valid transactions are processed normally.
    • Pending transactions are mined into new blocks via /blockchain/mine and the blockchain can be queried and validated.
  5. Market Data:

    • Live market prices are fetched via /market/prices and /market/price/{symbol}.
  6. Smart Contracts:

    • Manual Creation:
      A dedicated endpoint (POST /contracts/create) allows the manual creation of smart contracts by providing parameters (name, conditionExpression, action, actionValue, issuerWalletId). The contract is digitally signed using the issuer wallet’s private key.
    • Validation:
      An endpoint (GET /contracts/validate/{id}) validates a contract’s digital signature by reconstructing the data and verifying it with the issuer wallet’s public key.

📤 Submission

  1. Solve the proposed tasks.
  2. Continuously push the changes you have made.
  3. Wait for the results.
  4. Click submit challenge when you have reached your maximum score.

📊 Evaluation

The final score will be given according to whether or not the objectives have been met.

In this case, the challenge will be evaluated on 1700 (1300 for backend tasks and 400 for code quality) points which are distributed as follows:

Backend

  • Task 1: 50 points
  • Task 2: 100 points
  • Task 3: 150 points
  • Task 4: 200 points
  • Task 5: 300 points
  • Task 6: 200 points
  • Task 7: 300 points
  • Code quality: 400 points

❓ Additional information

Q1: Can I change anything in the app?

A1: Yes, as it is a hackathon and the application is dockerised, you are free to modify anything within the project, except for the functions that are already predefined to validate the proper functioning of the blockchain and the validation of smart contracts, Dockerfile and docker-compose.

Q2: Can I add resources that are not in pom.xml?

A2: Yes, you can add new resources if necessary, but keep in mind that everything needed to develop it has already been added.

Q3: Is it completely necessary to do the Dockerfile configuration first?

A3: Yes. To ensure the integrity of the correction, a Dockerised environment is the safest way to go.

Q4: Can I participate in both the fullstack and backend challenges at the same time?

A4: No, you cannot participate in both challenges. You must choose only one challenge to compete in.

Q5: What is the latest version of README?

A5: The most recent version will always be the one that appears on the platform. In case there is something to correct in the readme, you can see the updated version on the NUWE website.

About

Java backend simulating a blockchain-based crypto trading platform with smart contracts, digital signing, and real-time market data. This challenge deepened my understanding of blockchain mechanics, RSA encryption, and rule-based transaction validation.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •