Wallet-based authentication service for managing manufacturer, supplier, and warehouse registrations. The backend persists the full request payload, sends canonical JSON to an on-chain registry, and exposes role-restricted moderation endpoints.
- Node.js 20+
- PostgreSQL 14+
- Access to an Ethereum JSON-RPC endpoint with the deployed
RegistrationRegistrycontract
- Copy
.env.exampleto.envand fill in the real values (private keys must remain single-line with\nescapes). - Install dependencies:
npm install
- Apply the migration:
psql "$DATABASE_URL" -f migrations/001_init.sql - Start the server:
npm run dev
GET /auth/nonce?address=0xYourWallet→ receive nonce + message.- Sign the message off-chain with
personal_sign. POST /auth/loginwith{ address, signature }→ receive JWT (RS256) withroleclaim.- Use
Authorization: Bearer <token>for protected endpoints.
Request a nonce:
curl "http://localhost:8080/auth/nonce?address=0xabc123..."Submit a MANUFACTURER registration (replace <token> and payload fields as needed):
curl -X POST "http://localhost:8080/api/registrations" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"type": "MANUFACTURER",
"identification": {
"uuid": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"legalName": "Acme Manufacturing",
"businessRegNo": "REG-12345",
"countryOfIncorporation": "US"
},
"contact": {
"personName": "Jane Doe",
"designation": "Director",
"email": "jane@acme.example",
"phone": "+1-555-123-0000",
"address": "123 Industry Way, Springfield"
},
"metadata": {
"publicKey": "0x04deadbeef",
"smartContractRole": "MANUFACTURER",
"dateOfRegistration": "2024-01-01"
},
"details": {
"productCategoriesManufactured": ["Widgets", "Gadgets"],
"certifications": ["ISO9001"]
}
}'Update an existing registration (UUID must match the existing record and it will revert to PENDING status):
curl -X PUT "http://localhost:8080/api/registrations/<id>" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"type": "SUPPLIER",
"identification": {
"uuid": "4c5b8f62-7db9-4c42-b995-9c6f1b5f2acd",
"legalName": "Global Supplies Ltd.",
"businessRegNo": "SUP-445599",
"countryOfIncorporation": "SG"
},
"contact": {
"personName": "Michael Lee",
"designation": "Supply Director",
"email": "michael.lee@globalsupplies.example",
"phone": "+65-5550-1234",
"address": "88 Harbour Drive, Singapore"
},
"metadata": {
"publicKey": "0x0456789abcdeffedcba9876543210fedcba9876543210fedcba9876543210fedcb",
"smartContractRole": "SUPPLIER",
"dateOfRegistration": "2024-03-15"
},
"details": {
"productCategoriesSupplied": ["Steel", "Aluminum"],
"sourceRegions": ["CN", "MY"]
}
}'List pending registrations:
curl "http://localhost:8080/api/registrations/pending"Approve a registration (admin token required):
curl -X PATCH "http://localhost:8080/api/registrations/<id>/approve" \
-H "Authorization: Bearer <admin-token>"The reference Solidity contract lives in blockchain/contracts/RegistrationRegistry.sol and mirrors the on-chain interface used by the backend. It now supports updates (when the backend calls with isUpdate=true).
- Install the Hardhat workspace dependencies:
cd blockchain npm install - Compile the contract:
npm run compile
- Run tests (add your own under
blockchain/test):npm test - Deploy to the configured network (defaults to
.envvalues):The script logs the deployed address; copy it into the backendnpm run deploy
.envasREGISTRY_ADDRESSand update the ABI file if the contract changes.
- Addresses are lowercased for storage and comparison.
- Nonces expire after 10 minutes and are single-use.
- Replace
abi/RegistrationRegistry.jsonwith the contract ABI used on-chain if it differs from the placeholder. - Updating a registration triggers a new on-chain transaction and the record re-enters the
PENDINGstate until re-approved.