Enforceable on-chain data licensing for CHF 13,000–100,000+ institutional customers. Escrow payments, milestone delivery, SLA penalties, and API key provisioning — all on-chain.
6
Sector Contracts
USDC
Escrow Currency
EVM
Ethereum / Polygon
CHF 75,000–80,000/year
Deliverables
Payment Schedule
25% upfront · 25% at 90d · 50% annual
SLA Commitment
99.5% uptime · <500ms API latency · Daily signal delivery by 07:00 UTC
Penalty Clauses
5% rebate per missed signal day · 10% for data breach
Legal Framework
Deployment
createLicense() to initiateprovisionAPIKey()// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title SatClimate Carbon Trader Intelligence License
* @notice Data licensing agreement for carbon market signal delivery
* @dev Escrow-based payment with milestone delivery verification
* Handles CHF 75,000–80,000/year subscriptions
*/
contract CarbonTraderIntelligenceLicense is ReentrancyGuard, Ownable {
// ── State ──────────────────────────────────────────────────────────
IERC20 public immutable paymentToken; // USDC (6 decimals)
address public immutable satclimateVault;
enum ContractStatus { Pending, Active, Disputed, Terminated, Completed }
enum SignalType { BULLISH, BEARISH, NEUTRAL }
struct DataLicense {
address client;
uint256 totalValue; // in USDC (6 decimals)
uint256 annualFee; // CHF equivalent in USDC
uint256 startDate;
uint256 endDate; // 12 months from start
uint256 paidAmount;
uint256 signalsDelivered;
uint256 missedSignals;
ContractStatus status;
string apiKeyHash; // keccak256 of provisioned API key
string[] markets; // e.g. ["EU_ETS", "China_ETS", "UK_ETS"]
bool autoRenew;
}
struct Milestone {
uint256 dueDate;
uint256 amount; // USDC amount for this milestone
bool delivered;
bool paid;
string deliveryProof; // IPFS hash of delivery confirmation
}
// licenseId => DataLicense
mapping(bytes32 => DataLicense) public licenses;
// licenseId => milestones
mapping(bytes32 => Milestone[4]) public milestones;
// client => licenseIds
mapping(address => bytes32[]) public clientLicenses;
uint256 public constant PENALTY_RATE = 50; // 5% = 50 basis points per missed day
uint256 public constant BREACH_PENALTY = 1000; // 10% for data breach
uint256 public constant MIN_UPFRONT_PERCENT = 25; // 25% upfront required
uint256 public constant DISPUTE_WINDOW = 7 days;
uint256 public constant SIGNAL_SLA_WINDOW = 1 days;
// ── Events ────────────────────────────────────────────────────────
event LicenseCreated(bytes32 indexed licenseId, address indexed client, uint256 annualFee);
event PaymentReceived(bytes32 indexed licenseId, uint256 amount, uint256 milestone);
event SignalDelivered(bytes32 indexed licenseId, uint256 signalCount, SignalType signalType, string market);
event APIKeyProvisioned(bytes32 indexed licenseId, address indexed client);
event PenaltyApplied(bytes32 indexed licenseId, uint256 penaltyAmount, string reason);
event LicenseRenewed(bytes32 indexed licenseId, uint256 newEndDate);
event DisputeRaised(bytes32 indexed licenseId, address indexed raisedBy, string reason);
event LicenseTerminated(bytes32 indexed licenseId, address indexed terminatedBy);
// ── Constructor ───────────────────────────────────────────────────
constructor(address _paymentToken, address _satclimateVault) Ownable(msg.sender) {
paymentToken = IERC20(_paymentToken);
satclimateVault = _satclimateVault;
}
// ── Core Functions ────────────────────────────────────────────────
/**
* @notice Client initiates a new data license agreement
* @param annualFee Total annual fee in USDC (e.g. 75000 * 1e6 for $75,000)
* @param markets Array of carbon markets to cover (EU_ETS, China_ETS, etc.)
* @param autoRenew Enable automatic annual renewal
*/
function createLicense(
uint256 annualFee,
string[] calldata markets,
bool autoRenew
) external nonReentrant returns (bytes32 licenseId) {
require(annualFee >= 50000 * 1e6, "Minimum license: $50,000/year");
require(markets.length >= 1 && markets.length <= 13, "1-13 markets required");
// Generate unique license ID
licenseId = keccak256(abi.encodePacked(msg.sender, block.timestamp, annualFee));
// Set up 4-milestone payment schedule
// M1: 25% upfront, M2: 25% at 90d, M3: 25% at 180d, M4: 25% at 270d
uint256 quarter = annualFee / 4;
milestones[licenseId][0] = Milestone(block.timestamp + 1 days, quarter, false, false, "");
milestones[licenseId][1] = Milestone(block.timestamp + 90 days, quarter, false, false, "");
milestones[licenseId][2] = Milestone(block.timestamp + 180 days, quarter, false, false, "");
milestones[licenseId][3] = Milestone(block.timestamp + 270 days, quarter, false, false, "");
licenses[licenseId] = DataLicense({
client: msg.sender,
totalValue: annualFee,
annualFee: annualFee,
startDate: block.timestamp,
endDate: block.timestamp + 365 days,
paidAmount: 0,
signalsDelivered: 0,
missedSignals: 0,
status: ContractStatus.Pending,
apiKeyHash: "",
markets: markets,
autoRenew: autoRenew
});
clientLicenses[msg.sender].push(licenseId);
emit LicenseCreated(licenseId, msg.sender, annualFee);
}
/**
* @notice Client pays milestone (25% installments)
* @param licenseId The license to pay for
* @param milestoneIndex Which milestone to pay (0-3)
*/
function payMilestone(bytes32 licenseId, uint256 milestoneIndex) external nonReentrant {
DataLicense storage lic = licenses[licenseId];
require(lic.client == msg.sender, "Not license holder");
require(lic.status == ContractStatus.Pending || lic.status == ContractStatus.Active, "License not payable");
require(milestoneIndex < 4, "Invalid milestone");
Milestone storage ms = milestones[licenseId][milestoneIndex];
require(!ms.paid, "Milestone already paid");
require(block.timestamp >= ms.dueDate - 7 days, "Too early for this milestone");
// Transfer USDC from client to this contract (escrow)
paymentToken.transferFrom(msg.sender, address(this), ms.amount);
ms.paid = true;
lic.paidAmount += ms.amount;
// Activate license on first payment
if (milestoneIndex == 0 && lic.status == ContractStatus.Pending) {
lic.status = ContractStatus.Active;
}
emit PaymentReceived(licenseId, ms.amount, milestoneIndex);
}
/**
* @notice SatClimate records daily signal delivery (called by oracle/backend)
* @param licenseId The license to record delivery for
* @param signalType BULLISH / BEARISH / NEUTRAL
* @param market Which market this signal is for
* @param deliveryTimestamp When the signal was delivered
*/
function recordSignalDelivery(
bytes32 licenseId,
SignalType signalType,
string calldata market,
uint256 deliveryTimestamp
) external onlyOwner {
DataLicense storage lic = licenses[licenseId];
require(lic.status == ContractStatus.Active, "License not active");
lic.signalsDelivered++;
// Check SLA: signal must arrive within SIGNAL_SLA_WINDOW of expected time
bool slaBreached = deliveryTimestamp > block.timestamp + SIGNAL_SLA_WINDOW;
if (slaBreached) {
lic.missedSignals++;
uint256 penalty = (lic.annualFee * PENALTY_RATE) / 10000 / 365;
emit PenaltyApplied(licenseId, penalty, "SLA breach: signal delivered late");
}
emit SignalDelivered(licenseId, lic.signalsDelivered, signalType, market);
}
/**
* @notice SatClimate provisions API key on-chain (hash stored, key sent off-chain securely)
* @param licenseId The active license
* @param apiKeyHash keccak256 hash of the API key
*/
function provisionAPIKey(bytes32 licenseId, string calldata apiKeyHash) external onlyOwner {
DataLicense storage lic = licenses[licenseId];
require(lic.status == ContractStatus.Active, "License not active");
require(lic.paidAmount >= lic.totalValue / 4, "First milestone required");
lic.apiKeyHash = apiKeyHash;
emit APIKeyProvisioned(licenseId, lic.client);
}
/**
* @notice Release escrowed payment to SatClimate vault after milestone delivery
* @param licenseId The license
* @param milestoneIndex Which milestone to release
* @param deliveryProof IPFS hash proving delivery
*/
function releaseMilestonePayment(
bytes32 licenseId,
uint256 milestoneIndex,
string calldata deliveryProof
) external onlyOwner {
Milestone storage ms = milestones[licenseId][milestoneIndex];
require(ms.paid, "Milestone not yet paid by client");
require(!ms.delivered, "Already released");
ms.delivered = true;
ms.deliveryProof = deliveryProof;
// Transfer from escrow to SatClimate vault
paymentToken.transfer(satclimateVault, ms.amount);
}
/**
* @notice Client or SatClimate can raise a dispute within DISPUTE_WINDOW
*/
function raiseDispute(bytes32 licenseId, string calldata reason) external {
DataLicense storage lic = licenses[licenseId];
require(lic.client == msg.sender || owner() == msg.sender, "Unauthorized");
require(lic.status == ContractStatus.Active, "Cannot dispute inactive license");
lic.status = ContractStatus.Disputed;
emit DisputeRaised(licenseId, msg.sender, reason);
}
/**
* @notice Auto-renew license for another year (if autoRenew enabled)
*/
function renewLicense(bytes32 licenseId) external {
DataLicense storage lic = licenses[licenseId];
require(lic.client == msg.sender, "Not license holder");
require(lic.autoRenew, "Auto-renew not enabled");
require(block.timestamp >= lic.endDate - 30 days, "Too early to renew");
lic.startDate = lic.endDate;
lic.endDate = lic.endDate + 365 days;
lic.paidAmount = 0;
lic.status = ContractStatus.Pending;
// Reset milestones for new year
uint256 quarter = lic.annualFee / 4;
milestones[licenseId][0] = Milestone(lic.startDate + 1 days, quarter, false, false, "");
milestones[licenseId][1] = Milestone(lic.startDate + 90 days, quarter, false, false, "");
milestones[licenseId][2] = Milestone(lic.startDate + 180 days, quarter, false, false, "");
milestones[licenseId][3] = Milestone(lic.startDate + 270 days, quarter, false, false, "");
emit LicenseRenewed(licenseId, lic.endDate);
}
// ── Views ─────────────────────────────────────────────────────────
function getLicenseStatus(bytes32 licenseId) external view returns (
ContractStatus status,
uint256 paidAmount,
uint256 signalsDelivered,
uint256 daysRemaining
) {
DataLicense storage lic = licenses[licenseId];
return (
lic.status,
lic.paidAmount,
lic.signalsDelivered,
lic.endDate > block.timestamp ? (lic.endDate - block.timestamp) / 1 days : 0
);
}
function getClientLicenses(address client) external view returns (bytes32[] memory) {
return clientLicenses[client];
}
}Deploy via Remix IDE
Paste this contract into Remix, compile with Solidity ^0.8.20, deploy with USDC + vault address
From CHF 13,000 pilot to CHF 60,000/year — scenario foresight, emissions scanning, carbon project fraud.
Scenario Foresight Engine
CHF 25,000–60,000/year
Deliverables
Payment: 50% upfront · 50% at 6 months
SLA: 99.5% uptime
Penalty: 5% per missed P1–P2 alarm
Emissions Scanning Suite
CHF 13,000–45,000/year
Deliverables
Payment: 100% upfront (pilot) · Quarterly for annual
SLA: 99.9% sensor uptime
Penalty: 10% rebate per missed methane event >10 tonne threshold
Carbon Project Risk & Fraud
CHF 20,000–50,000/year
Deliverables
Payment: 40% upfront · 60% at 6 months
SLA: 99.5% uptime
Penalty: 8% rebate per false fraud flag on legitimate project
Industrial Facility Scanning
CHF 5,000–75,000/month
Deliverables
Payment: Monthly
SLA: 99.9% uptime
Penalty: 5% per missed daily report
Methane Compliance API
CHF 49–399/month
Deliverables
Payment: Monthly
SLA: 99.9% uptime
Penalty: 1% per hour downtime
Solar Energy Attribute Verifier
CHF 299–1,999/month
Deliverables
Payment: Monthly
SLA: 99.5% uptime
Penalty: 3% per late certification
Seagrass Habitat MRV
CHF 199–499/month
Deliverables
Payment: Quarterly
SLA: 99.5% uptime
Penalty: 5% per late MRV report
Environmental Risk Scoring Engine
CHF 2,500–30,000/month
Deliverables
Payment: Monthly
SLA: 99.9% uptime
Penalty: 5% per missed refresh
Deforestation & Land-Use Scanning
CHF 5,000–20,000/month
Deliverables
Payment: Monthly/Annual
SLA: 99.5% uptime
Penalty: 5% per missed detection
| Sector | Annual Fee (CHF) | Payment Schedule | Key SLA | Main Penalty |
|---|---|---|---|---|
| Carbon Trader Intelligence | CHF 75,000–80,000/year | 25% upfront · 25% at 90d · 50% annual | 99.5% uptime | 5% rebate per missed signal day |
| Energy Trader Signals | CHF 50,000–75,000/year | 30% upfront · 35% at 6mo · 35% at 9mo | 99.5% uptime | 5% rebate per missed foresight day |
| Quant Fund Raw Data Bundle | CHF 35,000–60,000/year | 50% upfront · 50% at 6 months | 99.9% data availability | 2% rebate per missed weekly batch |
| ESG Intelligence License | CHF 55,000–75,000/year | 25% upfront · 75% quarterly | 99.5% uptime | 3% rebate per missed weekly report |
| Regulatory Compliance Suite | CHF 40,000–60,000/year | 100% annual payment upfront (government/regulatory pricing) | 99.9% uptime | 10% refund per confirmed missed flaring event |
| Utility Operations Intelligence | CHF 50,000–70,000/year | 33% upfront · 33% at 4mo · 34% at 8mo | 99.5% uptime | 4% rebate per missed daily alarm |