Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

Setting Up Automated Compliance Checks in Payment Streams

A technical tutorial for integrating automated compliance modules—KYC verification, sanctions screening, and transaction limits—into payment stream smart contracts.
Chainscore © 2026
introduction
TUTORIAL

Setting Up Automated Compliance Checks in Payment Streams

A guide to implementing real-time, on-chain compliance logic for automated payment streams using smart contracts.

Programmable compliance moves regulatory and policy rules from manual processes into automated code executed on-chain. For payment streams—continuous fund transfers like salaries or subscriptions—this means embedding checks directly into the Stream contract logic. Instead of a central authority reviewing transactions, the contract itself validates each payment against predefined rules, such as sanction list verification, transaction volume limits, or geographic restrictions. This creates a trust-minimized and transparent system where compliance is enforced by the protocol, not by a potentially fallible intermediary.

The core architecture involves a modular design separating the streaming logic from the compliance engine. A base contract, like a modified version of Sablier or Superfluid, handles the payment scheduling. A separate ComplianceModule contract, which can be upgraded or swapped, contains the rule set. Before releasing funds in each stream tick, the main contract calls a function like checkCompliance(address sender, address receiver, uint256 amount) on the module. This function returns a boolean; if false, the payment is halted. This separation allows developers to update compliance rules without disrupting live payment streams.

A practical implementation starts with a basic sanction list check. Deploy a SanctionsComplianceModule that references an on-chain or oracle-fed list of prohibited addresses. The checkCompliance function would query this list for both payer and payee. Here's a simplified example:

solidity
function checkCompliance(address _from, address _to, uint256) public view returns (bool) {
    return !sanctionsList.isSanctioned(_from) && !sanctionsList.isSanctioned(_to);
}

More complex logic can be added, such as integrating with Chainalysis or TRM Labs oracles for real-time risk scores, or setting cumulative volume caps per address over a rolling period.

For production systems, consider gas efficiency and upgrade paths. Performing complex checks on-chain for every stream payment can be expensive. A common pattern is to use an off-chain attestation system. A compliance service signs a verifiable credential stating that a transaction complies with rules; the on-chain contract then simply verifies the signature's validity. Standards like EIP-712 facilitate this. Furthermore, employing a proxy pattern for the ComplianceModule allows the rule logic to be upgraded seamlessly, ensuring the system can adapt to new regulations without requiring users to migrate to a new streaming contract.

Ultimately, programmable compliance transforms payment streams from simple transfer mechanisms into policy-aware financial primitives. By automating checks, projects can reduce operational overhead, mitigate regulatory risk, and build more robust DeFi and payroll applications. The key is to start with clear, auditable rule sets and architect for flexibility, ensuring the system remains compliant as laws and business needs evolve.

prerequisites
PREREQUISITES AND SETUP

Setting Up Automated Compliance Checks in Payment Streams

This guide details the technical prerequisites and initial configuration required to implement automated compliance monitoring for on-chain payment streams using tools like Chainscore.

Automated compliance for payment streams requires a foundational setup of developer tools and a clear understanding of the data sources. You will need a Node.js environment (v18 or later) and a package manager like npm or yarn. The core of the system interacts with blockchain data, so you must have access to an RPC provider for the networks you intend to monitor, such as Alchemy, Infura, or a public node. Additionally, you will need to install the necessary SDKs; for example, npm install @chainscore/sdk ethers provides the client library and a standard interface for Ethereum interactions.

The next step involves configuring your compliance parameters and initializing the Chainscore client. You must obtain an API key from the Chainscore dashboard, which authenticates your requests. Initialize the client in your project with your key and desired network. A critical setup task is defining the ComplianceRule objects that encode your logic. For a payment stream, common rules include checking sender/recipient addresses against sanction lists, monitoring transaction volume thresholds, and verifying that funds originate from approved sources. These rules are expressed as code and passed to the monitoring service.

To put the stream under observation, you need its on-chain identifier. For a Sablier-style linear vesting contract, this is the streamId. For a Superfluid constant flow agreement, you need the flowId. Your application must be able to fetch these IDs, often by listening to contract creation events or querying a subgraph. Once you have the ID, you can register the stream with the compliance service using a method like client.monitorStream(streamId, rules). This establishes a webhook or polling connection that will trigger alerts based on your defined rules.

Finally, you must set up an alerting endpoint to receive and act on compliance violations. The Chainscore service will send HTTP POST requests to a webhook URL you specify, containing a payload with violation details like ruleId, streamId, and the offending transaction hash. Your server should validate these webhook signatures (to prevent spoofing) and execute mitigation logic. This could involve pausing the stream via the protocol's smart contract, notifying administrators, or logging the event to a database for audit trails. Testing this pipeline end-to-end with testnet streams is essential before mainnet deployment.

architecture-overview
SYSTEM ARCHITECTURE

Setting Up Automated Compliance Checks in Payment Streams

Automated compliance is critical for secure, scalable payment streams. This guide explains how to implement real-time checks using smart contracts and off-chain services.

Automated compliance checks are a non-negotiable layer for any production-grade payment streaming system. They act as programmable guardrails, ensuring every transaction adheres to predefined rules before execution. This is typically implemented as a modular component that intercepts payment stream actions—like creating a stream, withdrawing funds, or canceling—and validates them against a set of policies. The core architecture involves a compliance module that can be toggled on or off, allowing developers to balance security with gas efficiency during testing and deployment. Popular frameworks like OpenZeppelin's AccessControl are often used as a foundation for managing which addresses can update these rules.

The most effective approach uses a hybrid on-chain/off-chain model. Core, gas-efficient checks—such as validating the sender's or recipient's address against a blocklist stored in the contract—are performed directly in the smart contract's logic. For more complex checks that require external data, like sanction list verification or transaction pattern analysis, the system can integrate with off-chain oracles or dedicated compliance APIs. A common pattern is to emit an event when a stream action is requested, which an off-chain service listens for, performs the heavy-lifting check, and submits a verified transaction back to the contract to proceed or revert. This keeps gas costs low while enabling sophisticated risk assessment.

Here is a simplified Solidity example of an on-chain blocklist check integrated into a streaming contract's createStream function. This uses a mapping to store non-compliant addresses and a modifier to enforce the check.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract CompliantPaymentStream {
    mapping(address => bool) public isBlocklisted;
    address public complianceAdmin;

    modifier onlyComplianceAdmin() {
        require(msg.sender == complianceAdmin, "Not authorized");
        _;
    }

    modifier notBlocklisted(address _address) {
        require(!isBlocklisted[_address], "Address is blocklisted");
        _;
    }

    function createStream(address recipient, uint256 amountPerSecond) 
        external 
        notBlocklisted(msg.sender) 
        notBlocklisted(recipient) 
    {
        // ... logic to create the payment stream
    }

    function updateBlocklist(address _address, bool _status) 
        external 
        onlyComplianceAdmin 
    {
        isBlocklisted[_address] = _status;
    }
}

For dynamic, real-world compliance, you must integrate external data sources. Services like Chainalysis or TRM Labs provide smart contract-compatible APIs for sanction screening. You can use a decentralized oracle network like Chainlink to fetch this data securely on-chain. The architecture involves a Compliance Client contract that requests data from an oracle. The oracle queries the external API and returns the result in a callback function, which then updates an on-chain registry or directly influences transaction execution. This decouples the fast-moving compliance data from the slower blockchain state updates, ensuring your streams are evaluated against the latest risk intelligence without constant contract upgrades.

Key considerations for your architecture include upgradeability and gas optimization. Since compliance rules evolve, your checking logic should be housed in an upgradeable component, using patterns like the Proxy pattern or Diamond Standard (EIP-2535). Gas costs are paramount; batch processing checks for multiple streams or using signature-based approvals from a trusted off-chain verifier can reduce on-chain overhead. Always implement a pause mechanism and a clear, multi-signature governance process for updating critical blocklists or rule sets to prevent centralized control and single points of failure.

Finally, audit and test your compliance layer rigorously. Use forked mainnet environments with tools like Foundry or Hardhat to simulate real transactions against live blocklists. Implement comprehensive unit and integration tests that cover edge cases, such as addresses being added to a blocklist mid-stream. The goal is to create a system that is both unobtrusive for legitimate users and impenetrable for bad actors, providing continuous, automated enforcement that scales with your payment streaming protocol's adoption.

compliance-modules
IMPLEMENTATION GUIDE

Core Compliance Modules

Essential tools and frameworks for integrating automated compliance checks into on-chain payment streams, from sanctions screening to transaction monitoring.

05

Real-Time Risk Parameter Updates

Build dynamic compliance rules that can be updated without redeploying contracts. Use decentralized oracles (e.g., Chainlink) or governance-controlled parameter stores to manage allow/deny lists, transaction limits, and geographic restrictions.

  • Pattern: Store critical parameters in a separate, updatable contract that your main payment stream references.
  • Example: Lowering the maximum stream amount for a specific jurisdiction in response to new regulations.
  • Key function: require(complianceModule.isAllowed(recipient, amount), "Compliance check failed");
< 1 sec
Oracle Update Latency
06

Compliance Event Logging & Reporting

Ensure auditability by emitting standardized compliance events from your smart contracts. Log all screening results, rule triggers, and administrative overrides. Structure logs to align with regulatory examination requirements.

  • Solidity Practice: Use explicit event signatures like event SanctionCheck(address indexed target, bool isSanctioned, uint256 timestamp).
  • Off-chain: Index these events into a dashboard or SIEM system for monitoring.
  • Standard: Consider adopting open audit trail standards proposed by bodies like the Blockchain Association.
implement-kyc-verification
COMPLIANCE FOUNDATION

Step 1: Implement KYC Verification Module

Integrating a Know Your Customer (KYC) module is the foundational step for building compliant, automated payment streams. This guide covers the core logic for verifying user identities before they can initiate or receive funds.

A KYC verification module acts as a gatekeeper for your payment stream protocol. Its primary function is to cryptographically verify a user's real-world identity and compliance status before granting access to financial services. This is not just a regulatory checkbox; it's a critical security layer that mitigates risks like money laundering, sanctions evasion, and fraud. In a decentralized context, this module typically interacts with specialized, on-chain or off-chain KYC providers like Chainalysis KYT, Sumsub, or Veriff to attest to a user's verified status.

The core technical implementation involves creating a permissioned access control system. You need to design smart contract functions that check for a valid verification credential before allowing actions like createStream or withdrawFunds. A common pattern is to use a mapping to store verification statuses and a modifier to enforce checks. For example, a basic Solidity structure might look like:

solidity
mapping(address => bool) public isKYCVerified;
modifier onlyVerified() {
    require(isKYCVerified[msg.sender], "KYC verification required");
    _;
}
function createStream(address to, uint256 amount) external onlyVerified {
    // Stream creation logic
}

The verification data itself should be stored off-chain for privacy, with only a proof (like a hashed user ID and issuer signature) recorded on-chain. You can leverage ERC-3668: CCIP Read for gas-efficient off-chain lookups or use ZK-proofs for privacy-preserving verification. The module must also handle state changes: revoking access if a user's KYC status expires or is flagged. This requires setting up secure, permissioned functions (often behind a multisig or DAO vote) to update the isKYCVerified mapping.

When selecting a KYC provider, evaluate their coverage of jurisdictional sanctions lists, data freshness, and integration method (API vs. on-chain attestation). For automated streams, latency is key; the verification check must be near-instantaneous. Consider implementing a caching layer for verified addresses to reduce API calls and gas costs. Always ensure your design complies with data protection regulations like GDPR by minimizing on-chain personal data.

Finally, this module sets the stage for more complex compliance features. Once basic KYC is in place, you can layer on Transaction Monitoring (KYT) to screen individual payments against risk indicators and Automated License Detection to ensure streams only interact with permitted addresses in regulated regions. The goal is to create a seamless, automated flow where compliance is enforced by code, not manual review.

implement-sanctions-screening
AUTOMATED COMPLIANCE

Step 2: Implement Sanctions Screening Module

Integrate real-time sanctions screening into your payment streams to block transactions involving prohibited addresses.

A sanctions screening module is a critical component for any compliant payment system. It acts as a real-time filter, checking the recipient address of every outgoing stream against one or more sanctions lists, such as the OFAC SDN list. The module's primary function is to halt a transaction before funds are transferred if a match is found, preventing regulatory violations and potential asset freezes. This check should be performed at the point of stream creation and can be configured to run periodically on existing streams.

To implement this, you need to connect to a reliable data source for sanctions lists. While you could host and update a list yourself, using a dedicated oracle or API service like Chainalysis, TRM Labs, or Elliptic is more practical for production systems. These services maintain updated lists and provide simple interfaces. Your smart contract will need to call an external function (via an oracle like Chainlink) or your off-chain service will need to query the API and post the result on-chain for the contract to verify.

Here is a simplified conceptual structure for a Solidity function that integrates a check. It assumes an oracle has provided a boolean result for a given address.

solidity
// Pseudo-code structure
function createPaymentStream(address _recipient, uint256 _amountPerSecond) external {
    // 1. Call internal screening function
    require(_isNotSanctioned(_recipient), "Sanctions: Recipient is prohibited");

    // 2. Proceed with stream creation logic if check passes
    // ... [Stream setup logic] ...
}

function _isNotSanctioned(address _addr) internal view returns (bool) {
    // This would read from a state variable updated by an oracle
    return !sanctionsList[_addr];
}

The key is ensuring the sanctionsList mapping is kept current through a secure, trust-minimized update mechanism controlled by a decentralized oracle or a multisig governance process.

Consider the performance and cost implications. On-chain storage of a full sanctions list is gas-intensive and impractical. Therefore, most designs use an off-chain verification model: an oracle network checks the address against an updated list and submits a proof or boolean result to the chain. For recurring streams, you must decide on a re-screening frequency—daily, weekly, or upon any stream withdrawal attempt—to catch addresses that are newly added to sanctions lists.

Finally, implement clear error handling and logging. When a transaction is blocked, revert with an informative message. Consider emitting an event like SanctionsCheckFailed(address screenedAddress, uint256 blockNumber) for off-chain monitoring and audit trails. This transparency is crucial for demonstrating compliance efforts to regulators and auditors. The module should be upgradeable to adapt to new regulatory requirements or improved data sources without disrupting the core streaming logic.

implement-transaction-limits
AUTOMATED COMPLIANCE

Step 3: Implement Transaction Limits

Configure automated rules to enforce daily, weekly, or per-transaction spending caps within your payment streams.

Transaction limits are a foundational compliance control that prevents misuse and manages financial exposure. By setting hard caps on the amount of value that can be transferred within a specific timeframe, you mitigate risks associated with wallet compromise or unexpected large withdrawals. In programmable payment streams, these limits are enforced on-chain or by your off-chain infrastructure, acting as a circuit breaker. Common limit types include a daily cap (e.g., 1 ETH per day), a per-transaction maximum (e.g., 0.5 ETH), and a rolling period limit (e.g., 5 ETH per week).

Implementation typically involves tracking cumulative spending in a secure data store. For on-chain enforcement with a Solidity stream contract, you would store a mapping of user addresses to their total withdrawn amount per period. Before processing a withdrawal request, the contract's withdraw function checks if the new amount would exceed the defined limit, reverting the transaction if it does. Here's a simplified conceptual check:

solidity
// Pseudo-code for limit check
uint256 public dailyLimit = 1 ether;
mapping(address => mapping(uint256 => uint256)) public dailyWithdrawn;

function withdraw(uint256 amount) external {
    uint256 today = block.timestamp / 1 days;
    uint256 alreadyWithdrawn = dailyWithdrawn[msg.sender][today];
    require(alreadyWithdrawn + amount <= dailyLimit, "Daily limit exceeded");
    // ... proceed with withdrawal logic
}

For more complex or gas-efficient setups, consider using an off-chain relayer or account abstraction (ERC-4337) to validate limits before submitting transactions to the network. Services like Gelato Network or OpenZeppelin Defender can automate these checks and trigger alerts. When defining your limits, base them on the stream's purpose: a payroll stream might have a high weekly limit equal to salary, while a subscription or API credit stream would use small, frequent caps. Always publish the limit rules clearly to users to set correct expectations and ensure transparency in your protocol's operation.

integrate-payment-contract
IMPLEMENTATION

Step 4: Integrate Modules into Payment Contract

This step connects your custom compliance logic to the payment stream contract, enabling automated rule enforcement for every transaction.

With your compliance module deployed, you must now integrate it into your payment stream contract. This is done by modifying the contract's constructor or an initialization function to accept the module's address and store it. The key is to use the IComplianceModule interface you defined earlier, which allows your main contract to call the checkCompliance function without knowing the underlying implementation details. This pattern, known as dependency injection, makes your system modular and upgradeable. For example, you could start with a basic KYC module and later swap it for a more advanced sanctions-screening module without changing your core payment logic.

The integration point is typically within the function that creates or updates a payment stream. Before processing a payment or allowing a stream to be created, your contract should call complianceModule.checkCompliance(payer, payee, amount). This is a critical security check that must be enforced. A common practice is to use Solidity's require statement to revert the transaction if the compliance check fails, ensuring no non-compliant payments can be processed. It's also prudent to emit an event logging the compliance check result for off-chain monitoring and auditing purposes, providing a transparent record of all enforced rules.

Consider a practical implementation in a streaming contract like a modified version of Sablier or Superfluid. Your createStream function would include a compliance gate. The code snippet below illustrates the core integration:

solidity
function createStream(address payee, uint256 amountPerSecond) external payable {
    // 1. Call the external compliance module
    require(
        complianceModule.checkCompliance(msg.sender, payee, msg.value),
        "Compliance check failed"
    );
    
    // 2. Emit an event for transparency
    emit ComplianceChecked(msg.sender, payee, block.timestamp, true);
    
    // 3. Proceed with original stream creation logic
    _createStream(payee, amountPerSecond);
}

This structure ensures compliance is non-negotiable and automatically applied.

After integration, you must thoroughly test the interaction. Use a forked mainnet environment in a framework like Foundry or Hardhat to simulate real transactions. Write tests that verify: a compliant transaction succeeds, a non-compliant transaction reverts with the correct error, and the compliance event is emitted correctly. You should also test edge cases, such as what happens if the compliance module address is set to address(0) or if the module itself runs out of gas. This testing phase is essential to ensure the automated enforcement is reliable and secure before deploying to a production network like Ethereum Mainnet or Arbitrum.

Finally, consider the operational aspects. You will need a secure method to update the compliance module address if you need to patch logic or upgrade to a new ruleset. Implementing a governance-controlled or multi-sig protected function like setComplianceModule(address newModule) is standard. This allows for adaptability as regulations change, but it must be carefully permissioned to prevent unauthorized changes that could disable compliance checks. With this integration complete, your payment streams now have a powerful, automated guardrail that can scale to handle millions of transactions while adhering to your defined policy.

SERVICE PROVIDERS

Comparison of On-Chain Compliance Oracles

Key features and specifications for leading on-chain oracle services that provide automated compliance checks for payment streams.

Feature / MetricChainalysis OracleElliptic OracleTRM Labs API

Real-time AML screening

Sanctions list coverage

OFAC, UN, EU, 100+

OFAC, UN, EU, 90+

OFAC, UN, EU, 120+

Smart contract integration

Direct contract calls

API gateway required

Direct contract calls

Latency for address check

< 2 seconds

< 3 seconds

< 1.5 seconds

Cost per 1K checks (mainnet)

$15-25

$20-30

$18-28

Supported chains

Ethereum, Polygon, Arbitrum

Ethereum, BNB Chain

Ethereum, Avalanche, Optimism

Risk scoring model

Proprietary (1-100)

Proprietary (Low/Med/High)

TRM Nexus (0-99)

Custom rule engine

AUTOMATED COMPLIANCE

Frequently Asked Questions

Common questions and solutions for developers implementing automated compliance checks in payment streams using smart contracts.

Automated compliance checks are programmatic rules enforced by smart contracts that validate transactions before execution. In payment streams, these checks can verify sender/recipient identities, transaction amounts, jurisdictional rules, or source-of-funds attestations. Instead of manual review, logic encoded in contracts like ComplianceModule.sol automatically approves, holds, or rejects payments. This is critical for DeFi protocols, payroll services, or subscription models needing regulatory adherence. Common standards include integrating with on-chain registries (e.g., for sanctions) or using zero-knowledge proofs for private verification.

conclusion
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

This guide has outlined the core components for building automated compliance into payment streams. The next steps involve integrating these checks into a production environment and exploring advanced monitoring.

You should now have a functional framework for automating compliance in payment streams. The core components include: a modular rule engine for evaluating transactions against policies, real-time data oracles for fetching sanctions lists and AML data, and a secure execution layer that can pause or redirect non-compliant streams. The example using a Gelato Automation task and the Chainlink Functions oracle demonstrates a practical, serverless implementation that can be adapted to various protocols like Superfluid or Sablier.

For production deployment, several critical steps remain. First, conduct a thorough audit of your smart contracts and off-chain automation scripts. Services like CertiK, OpenZeppelin, or Trail of Bits can identify vulnerabilities in your rule logic and access controls. Second, implement a robust key management strategy for your automation service, using hardware security modules (HSMs) or a managed service like AWS KMS to protect the private keys that trigger compliance actions. Finally, establish a clear incident response plan for handling false positives and managing manual overrides when necessary.

To move beyond basic checks, consider integrating more sophisticated monitoring tools. Platforms like Chainalysis or TRM Labs offer APIs for deeper transaction risk scoring and entity clustering beyond simple list checking. You can also implement time-based rules, such as limiting total volume per address over a rolling 24-hour period, or multi-signature approvals for streams exceeding a certain threshold. Continuously monitor the regulatory landscape for changes to sanctions lists or travel rule requirements (like the EU's Transfer of Funds Regulation [TFR]) and ensure your rule engine can be updated without requiring a full contract migration.

The ultimate goal is to create a defense-in-depth compliance strategy. Automated on-chain checks act as the first, fast layer of defense. They should be complemented by periodic off-chain analysis reports and a clear legal framework for your application's operations. By building compliance into the protocol's architecture from the start, you create a more resilient and trustworthy system for all users, which is essential for mainstream adoption of programmable payment streams.

How to Add Automated Compliance to Payment Streams | ChainScore Guides