Just-In-Time Payment Contract
What it does:
Automatically releases payments to suppliers or partners when predefined conditions, milestones, or delivery confirmations are met, supporting just-in-time supply chains.
Why it matters:
Optimizes cash flow, reduces idle capital, ensures timely supplier payments, and enforces contractual obligations transparently on-chain.
How it works:
-
Buyers or manufacturers deposit funds into the contract
-
Milestones or delivery events are defined in the smart contract (time-based, sensor-based, or off-chain verified)
-
Smart contract automatically releases payments when milestones are achieved
-
Supports partial payments for multi-stage deliveries or production cycles
-
Historical payment events are stored for auditing and reconciliation
-
Integrates with Supply Chain Traceability, Cold Chain Monitoring, and Inventory Management
-
Public dashboards provide visibility into milestone progress, payments, and pending actions
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title JustInTimePayment
* @author Nam
* @notice Automates payments based on delivery or milestone fulfillment in supply chains
*/
contract JustInTimePayment is Ownable {
struct Milestone {
string description;
uint256 amount;
bool completed;
bool paid;
}
struct PaymentContract {
address payable buyer;
address payable supplier;
Milestone[] milestones;
uint256 totalAmount;
}
mapping(uint256 => PaymentContract) public paymentContracts;
uint256 public contractCount;
mapping(address => bool) public authorizedVerifiers;
// -------------------- EVENTS --------------------
event ContractCreated(uint256 indexed contractId, address buyer, address supplier, uint256 totalAmount);
event MilestoneCompleted(uint256 indexed contractId, uint256 milestoneIndex);
event PaymentReleased(uint256 indexed contractId, uint256 milestoneIndex, uint256 amount);
event VerifierApproved(address verifier);
// -------------------- VERIFIER MANAGEMENT --------------------
function approveVerifier(address _verifier) external onlyOwner {
authorizedVerifiers[_verifier] = true;
emit VerifierApproved(_verifier);
}
function revokeVerifier(address _verifier) external onlyOwner {
authorizedVerifiers[_verifier] = false;
}
modifier onlyVerifier() {
require(authorizedVerifiers[msg.sender], "Not an authorized verifier");
_;
}
// -------------------- CONTRACT CREATION --------------------
function createContract(address payable _supplier, string[] calldata _milestoneDescriptions, uint256[] calldata _milestoneAmounts) external payable {
require(_milestoneDescriptions.length == _milestoneAmounts.length, "Mismatched milestones and amounts");
uint256 total = 0;
for (uint256 i = 0; i < _milestoneAmounts.length; i++) {
total += _milestoneAmounts[i];
}
require(msg.value == total, "Incorrect payment amount");
contractCount += 1;
PaymentContract storage c = paymentContracts[contractCount];
c.buyer = payable(msg.sender);
c.supplier = _supplier;
c.totalAmount = total;
for (uint256 i = 0; i < _milestoneDescriptions.length; i++) {
c.milestones.push(Milestone({
description: _milestoneDescriptions[i],
amount: _milestoneAmounts[i],
completed: false,
paid: false
}));
}
emit ContractCreated(contractCount, msg.sender, _supplier, total);
}
// -------------------- MILESTONE MANAGEMENT --------------------
function completeMilestone(uint256 _contractId, uint256 _milestoneIndex) external onlyVerifier {
PaymentContract storage c = paymentContracts[_contractId];
Milestone storage m = c.milestones[_milestoneIndex];
require(!m.completed, "Milestone already completed");
m.completed = true;
emit MilestoneCompleted(_contractId, _milestoneIndex);
// Release payment automatically
c.supplier.transfer(m.amount);
m.paid = true;
emit PaymentReleased(_contractId, _milestoneIndex, m.amount);
}
// -------------------- VIEW FUNCTIONS --------------------
function getMilestones(uint256 _contractId) external view returns (Milestone[] memory) {
return paymentContracts[_contractId].milestones;
}
function getTotalPaid(uint256 _contractId) external view returns (uint256 totalPaid) {
PaymentContract storage c = paymentContracts[_contractId];
for (uint256 i = 0; i < c.milestones.length; i++) {
if (c.milestones[i].paid) {
totalPaid += c.milestones[i].amount;
}
}
}
// -------------------- FUNDING --------------------
receive() external payable {}
}