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 a Compliance-First Private Sale Infrastructure

A technical guide for developers to build a fundraising platform that integrates zero-knowledge KYC/AML verification, secure investor portals, and immutable audit trails for regulatory compliance.
Chainscore © 2026
introduction
TECHNICAL GUIDE

Setting Up a Compliance-First Private Sale Infrastructure

A practical guide to implementing the technical infrastructure for a private token sale that enforces regulatory compliance by design, using smart contracts and off-chain verification.

A compliance-first private sale infrastructure programmatically enforces investor eligibility rules at the smart contract level. This moves beyond manual KYC/AML checks to create a system where only verified wallets can participate. The core components are: an allowlist manager smart contract that stores verified addresses, a sale contract that checks this list before accepting funds, and an off-chain verification portal where investors submit documentation. This architecture ensures that non-compliant transactions are impossible, not just discouraged, providing a clear audit trail for regulators.

The first step is deploying the allowlist manager, often implemented as a simple mapping or a Merkle tree for gas efficiency. For a basic mapping, your smart contract would include a function like addToAllowlist(address investor) callable only by the admin. A more scalable approach uses a Merkle proof system, where you generate a Merkle root from the list of approved addresses and store only that root on-chain. Investors then submit a cryptographic proof with their transaction, which the sale contract verifies. This method, used by protocols like Uniswap for airdrops, saves significant gas when managing thousands of participants.

Integrate this verification into your sale contract's purchase function. The critical check occurs in the buyTokens function, which should revert if the sender is not verified. For a Merkle-based system, the function signature would be buyTokens(uint256 amount, bytes32[] calldata merkleProof). Inside, it calls a verifier like MerkleProof.verify(merkleProof, merkleRoot, keccak256(abi.encodePacked(msg.sender))). If this returns false, the transaction fails. This on-chain gate is your primary compliance enforcement mechanism.

The off-chain component handles identity verification and proof generation. You need a secure portal (e.g., built with Privy, Web3Auth, or a custom backend) where users connect their wallet, submit KYC details, and provide proof of accreditation if required. Once verified, your backend either calls the addToAllowlist function for them or, for a Merkle system, generates their unique proof and provides it via the UI. It's crucial to hash and securely store the submitted documents off-chain, linking them to the wallet address for future audits.

Finally, consider advanced features for real-world compliance. Implement transfer restrictions on the token itself post-sale, using OpenZeppelin's ERC20Restrictable or similar, to prevent tokens from being sent to non-verified addresses. Set up vesting schedules (e.g., using Sablier or OpenZeppelin's VestingWallet) to release tokens over time, which is a common requirement for regulatory safe harbors. Log all verification events and contract interactions to an immutable service like The Graph or a dedicated compliance dashboard. This end-to-end system turns regulatory requirements into immutable code, reducing operational risk and building investor trust.

prerequisites
FOUNDATION

Prerequisites and System Requirements

A secure, compliant private sale requires a robust technical and legal foundation before any code is written. This guide outlines the essential components you must have in place.

The first prerequisite is establishing a clear legal wrapper for your token sale. This typically involves creating a dedicated legal entity, such as a Delaware C-Corp or a foundation in a crypto-friendly jurisdiction like Switzerland or Singapore. You must draft and finalize legal documents including a Private Placement Memorandum (PPM), Subscription Agreement, and Token Purchase Agreement. These documents define investor rights, lock-up periods, and regulatory compliance frameworks, such as exemptions under Regulation D (for the US) or equivalent rules in other regions. Engaging a law firm with specific Web3 expertise is non-negotiable.

Next, you need to define and implement your Know Your Customer (KYC) and Anti-Money Laundering (AML) verification pipeline. This is a core technical requirement for compliance. You will integrate with a specialized provider like Chainalysis, Sumsub, or Veriff via their API. Your infrastructure must be able to collect, verify, and securely store investor identification documents, screen against sanction lists, and perform risk assessments. The system should tag each verified wallet address with a compliance status (e.g., "approved", "pending", "rejected"), which will be checked on-chain before allowing a contribution.

Your technical stack must include a secure backend service to manage the sale's business logic off-chain. This service, often built with Node.js, Python (FastAPI/Django), or Go, will handle investor whitelist management, track contribution limits, enforce country restrictions, and generate signed messages for on-chain interactions. It must connect to your KYC provider's API and a secure database (e.g., PostgreSQL) to store sensitive investor data. All communications should be encrypted (TLS 1.3), and access should be protected with robust authentication.

For on-chain components, you need a meticulously audited smart contract for the sale. Key functions include accepting contributions (in ETH, USDC, etc.), enforcing contribution caps, and distributing tokens post-vesting. The contract must integrate a mechanism to check an allowlist, often via a signed message from your backend or a merkle proof. You will also need a secure, multi-signature wallet (using Safe{Wallet} or similar) to custody raised funds, with a clearly defined signer policy (e.g., 3-of-5). Never deploy contracts or hold funds with a single private key.

Finally, establish your operational and security protocols. This includes setting up secure communication channels for your team (e.g., Signal, Keybase), using a secret management service (HashiCorp Vault, AWS Secrets Manager), and planning for incident response. You must also prepare the public-facing elements: a clear landing page detailing the sale terms, a secure portal for investors to complete KYC and contribute, and a plan for communicating with participants throughout the process.

architecture-overview
SYSTEM ARCHITECTURE OVERVIEW

Setting Up a Compliance-First Private Sale Infrastructure

A robust technical foundation is critical for conducting secure and legally compliant private token sales. This guide outlines the core architectural components required to manage investor onboarding, fund collection, and token distribution while adhering to regulatory standards.

A compliance-first private sale architecture separates concerns into distinct, secure layers. The core system typically consists of an Investor Management Portal for KYC/AML verification, a Smart Contract Suite for escrow and distribution, and an Administrative Dashboard for oversight. These components interact through secure APIs, ensuring investor data is siloed from on-chain operations. This separation minimizes attack surfaces and simplifies regulatory audits by providing clear data trails for each module.

The investor portal is your primary compliance gateway. It integrates with specialized providers like Sumsub or Jumio to perform identity verification, document collection, and sanctions screening. Upon successful verification, the system should generate a cryptographically signed proof (like a Merkle proof or a signed message) that grants the verified wallet address permission to interact with the sale smart contract. This proof-of-eligibility model keeps sensitive personal data off-chain while enabling permissioned on-chain access.

The smart contract layer handles the financial and distribution logic. Key contracts include a vesting contract with configurable cliffs and schedules, a multi-signature treasury for collected funds (using Safe{Wallet}), and the main sale contract itself. The sale contract must validate the investor's eligibility proof before accepting contributions. It should also implement hard caps, individual contribution limits, and refund mechanisms to enforce sale terms programmatically and transparently.

For the administrative dashboard, consider using a framework like React or Vue.js with a backend such as Node.js or Python (Django). This dashboard connects to a secure database (e.g., PostgreSQL) storing hashed investor data and links to the blockchain via a node provider like Alchemy or Infura. It should display real-time metrics on funds raised, investor status, and vesting schedules, and allow admins to trigger contract functions (e.g., finalizing the sale) through a secure multi-signature process.

Security is paramount. Implement role-based access control (RBAC) for all admin interfaces, use hardware security modules (HSMs) or multi-party computation (MPC) for key management, and conduct thorough audits of all smart contracts by firms like CertiK or OpenZeppelin. Regularly monitor transactions for anomalies and ensure all off-chain data is encrypted at rest and in transit. This defense-in-depth approach protects both investor assets and the project from legal and technical risks.

core-components
PRIVATE SALE INFRASTRUCTURE

Core Technical Components

Building a compliant private sale requires integrating specific, auditable components for KYC, token distribution, and investor management.

04

Investor Portal (SAFE/SAFT Management)

Provide a secure dashboard for investors to view their commitment, signed agreements, and vesting schedule.

  • Documents: Host executed SAFTs (Simple Agreement for Future Tokens) or token purchase agreements, potentially using IPFS for immutable storage.
  • Data: Display the investor's committed amount, vested/unvested token balance, and next unlock date.
  • Integration: This portal should pull data directly from your KYC provider, smart contract vault, and distribution module.
05

Regulatory Jurisdiction Analysis

Determine the legal framework governing your sale based on investor location and token classification. This dictates all other technical choices.

  • Critical Questions: Is the token a security (Howey Test)? Which countries' investors can participate?
  • Impact: This analysis defines your required KYC depth, accreditation checks, disclosure documents, and reporting obligations.
  • Action: Consult legal counsel early. Tools cannot replace legal advice, but they must be configured to enforce the resulting rules.
step-1-zk-circuit
CIRCUIT ARCHITECTURE

Step 1: Designing the ZK KYC Verification Circuit

This step defines the core logic for verifying user credentials without exposing sensitive data. We'll build a circuit using Circom to prove a user meets specific compliance criteria.

A zero-knowledge proof (ZKP) circuit is the computational blueprint for your verification system. It defines the exact conditions a user must satisfy to generate a valid proof, without revealing the underlying data. For a KYC check, this typically involves proving that a user's hashed credentials match an entry on an approved list and that they are not on a sanctions list. The circuit's outputs are the proof and a public signal, which acts as a commitment to the verification result for on-chain validation.

We'll use Circom 2.1.6, a popular domain-specific language for writing ZK circuits. The core component is a template that takes private inputs (the user's data) and public inputs (the Merkle root of the allowlist). The circuit performs cryptographic checks and outputs a binary result. Below is a simplified circuit structure verifying a user is on a Merkle allowlist:

circom
include "circomlib/merkleTree.circom";

template KYCVerifier(levels) {
    signal input leaf; // Private: hashed user credential (poseidon hash)
    signal input pathElements[levels]; // Private: Merkle path elements
    signal input pathIndices[levels]; // Private: Merkle path indices (0/1)
    signal input root; // Public: Published Merkle root of the allowlist

    component mt = MerkleTreeChecker(levels);
    mt.leaf <== leaf;
    for (var i = 0; i < levels; i++) {
        mt.pathElements[i] <== pathElements[i];
        mt.pathIndices[i] <== pathIndices[i];
    }
    mt.root <== root;

    // Public output signal: 1 if verification passes
    signal output verified;
    verified <== 1;
}

The circuit's constraints ensure the user-provided leaf hashes to a value that, when combined with the pathElements according to pathIndices, reconstructs the publicly known root. If the constraints are satisfied, the circuit outputs verified = 1. This proof can be generated locally by the user's wallet. Critical design considerations include selecting a secure hash function (like Poseidon, optimized for ZK), determining the Merkle tree depth based on your allowlist size, and ensuring the circuit does not leak information through side channels.

After writing the circuit, you must compile it into an R1CS (Rank-1 Constraint System) and generate the corresponding proving and verification keys. Use the Circom compiler (circom kyc.circom --r1cs --wasm) for this. The proving key is used to generate proofs, while the verification key is what your smart contract will use to verify them. This separation is fundamental: the verifier only needs the lightweight verification key and the proof, not the large proving key or any private data.

Finally, integrate this circuit with a proving system like Groth16 or PLONK using a snarkjs setup. You will perform a trusted setup ceremony to generate the proving and verification keys, a critical step for security. The resulting verification key, often represented as a Solidity contract, will be deployed on-chain. This completes the off-chain trust layer; the smart contract can now trust proofs generated by this specific circuit without knowing who submitted them.

step-2-smart-contracts
IMPLEMENTATION

Step 2: Deploying the On-Chain Verifier and Sale Contracts

This step covers the deployment of the core smart contracts that enforce compliance rules on-chain and manage the private sale mechanics.

The foundation of a compliance-first private sale is a two-contract architecture: a Verifier and a Sale contract. The Verifier is an immutable, reusable contract that holds the logic for checking investor eligibility against a predefined set of rules (e.g., KYC status, accreditation proofs, jurisdiction allow/deny lists). The Sale contract is the actual token distribution mechanism that holds the tokens for sale and references the Verifier contract's address. Before any purchase function executes, the Sale contract calls the Verifier to confirm the participant's address is approved. This separation of concerns enhances security and auditability.

Deployment is typically a two-step process. First, you deploy the Verifier contract, initializing it with your compliance parameters. For a Solidity-based system using Foundry, the command might look like forge create Verifier --constructor-args <kycRegistryAddress> <accreditedOnlyFlag>. Once deployed, you receive the Verifier's immutable contract address. Next, you deploy the Sale contract, passing the Verifier's address as a constructor argument, along with sale-specific details like the token address, price, and timestamps. This creates a permanent link; the Sale contract will forever query that specific Verifier instance for approvals.

Critical post-deployment actions include verifying the contract source code on block explorers like Etherscan or Basescan. This transparency builds trust with potential investors. You must then transfer the sale token allocation from the project wallet to the Sale contract's address and configure the contract's withdrawal permissions, usually setting a secure multisig or Timelock controller as the beneficiary. Thorough testing on a testnet (e.g., Sepolia, Base Sepolia) with simulated compliant and non-compliant wallets is non-negotiable before mainnet deployment to ensure the rule engine functions as intended.

step-3-backend-service
COMPLIANCE ENGINE

Step 3: Building the Off-Chain Verification Service

Implement a secure, scalable backend service to verify investor credentials and manage allowlists before on-chain minting.

The off-chain verification service acts as the compliance gatekeeper for your private sale. Its primary function is to authenticate potential investors against your predefined criteria—such as KYC status, accreditation proofs, or participation in a previous community round—before granting them permission to mint. This separation of concerns is critical: complex identity checks and regulatory logic are handled off-chain, while the on-chain contract only needs to verify a simple, cryptographically signed permission. This architecture minimizes gas costs, protects sensitive user data from being stored on a public ledger, and allows for flexible, updatable compliance rules without needing to modify the smart contract.

At its core, the service needs to perform three key tasks. First, it must expose a secure API endpoint (e.g., /api/verify) that accepts a user's wallet address and any required documentation. Second, it must execute your business logic to validate the user against your compliance database. Finally, upon successful verification, it must generate a cryptographic signature using a secure, private server key. This signature, which typically includes the user's address and an expiry timestamp, is the proof that will be checked by your MerkleProof or Signature contract. You can build this with common frameworks like Node.js/Express, Python/FastAPI, or Go, ensuring robust error handling and logging for audit trails.

Security for this service is non-negotiable. The signing key must be stored in a hardware security module (HSM), a cloud KMS (like AWS KMS or GCP Cloud KMS), or as an encrypted environment variable—never hardcoded. Implement rate limiting to prevent abuse and use API keys or other authentication to protect the verification endpoint itself. For the database, you can use PostgreSQL or MongoDB to store audit logs of verification attempts (successful and failed), mapping wallet addresses to internal user IDs without storing full KYC documents. This log is essential for regulatory compliance and troubleshooting.

Here is a simplified Node.js example using Ethers.js and Express for the signing endpoint:

javascript
const { ethers } = require('ethers');
const express = require('express');
const app = express();
app.use(express.json());

// Load the private key from a secure environment variable
const SIGNER_PRIVATE_KEY = process.env.SIGNER_PRIVATE_KEY;
const signer = new ethers.Wallet(SIGNER_PRIVATE_KEY);

app.post('/api/verify', async (req, res) => {
  const { userAddress } = req.body;
  // 1. Your custom compliance logic here (check KYC, accreditation, etc.)
  const isVerified = await checkCompliance(userAddress);
  
  if (!isVerified) {
    return res.status(403).json({ error: 'Verification failed' });
  }
  
  // 2. Create a message hash (address + expiry)
  const expiry = Math.floor(Date.now() / 1000) + 3600; // 1 hour expiry
  const messageHash = ethers.solidityPackedKeccak256(
    ['address', 'uint256'],
    [userAddress, expiry]
  );
  
  // 3. Sign the hash
  const signature = await signer.signMessage(ethers.getBytes(messageHash));
  
  // 4. Return the signature and expiry to the client
  res.json({ signature, expiry });
});

The client-side dApp would then pass this signature and expiry to the smart contract's mint function.

To complete the flow, integrate this service with your frontend application. After a user connects their wallet, your dApp should call your verification API. Upon receiving a valid signature, the dApp submits the mint transaction, including the signature as a parameter. The smart contract uses ECDSA.recover or a similar method to validate that the signature was created by your trusted signer address and that it matches the minter's address. This pattern, used by protocols like OpenSea's Seaport for off-chain allowlists, ensures that only authorized, compliant users can interact with the on-chain sale, creating a robust and legally defensible launch infrastructure.

step-4-investor-portal
PRIVATE SALE INFRASTRUCTURE

Step 4: Developing the Secure Investor Portal

This guide details the technical implementation of a compliance-first investor portal for private token sales, focusing on secure access control, KYC/AML integration, and on-chain commitment tracking.

A secure investor portal is the central hub for managing a private sale, acting as the gatekeeper between accredited investors and the token distribution contract. Its core functions are access control, investor verification, and commitment tracking. Unlike public sales, private sales require whitelisting, which involves verifying investor accreditation status (KYC/AML) and assigning a specific allocation cap. The portal must securely store this off-chain data and provide a signed authorization that the on-chain sale contract can verify before accepting funds. A common architecture uses a backend API to manage investor data and a frontend dApp for investors to connect their wallet, submit documents, and commit funds.

The technical stack typically involves a React/Next.js frontend for the user interface, a Node.js/Express backend for business logic and KYC integration, and a PostgreSQL database for storing investor profiles and verification status. Smart contract interaction is handled via libraries like ethers.js or viem. The critical security pattern is the use of cryptographic signatures. The backend, holding the whitelist, signs a message containing the investor's wallet address and their maximum allocation. This signature is passed to the frontend and submitted with the transaction. The sale smart contract uses ecrecover to validate the signature against a known admin signer address, ensuring only approved investors can participate within their limits.

Integrating a KYC/AML provider like Sumsub, Jumio, or Ondato is essential for compliance. The flow is: 1) Investor connects wallet to the portal, 2) Portal checks if the wallet is pre-whitelisted or prompts for KYC, 3) Investor completes the provider's verification flow, 4) The provider's webhook sends verification results to your backend, 5) Backend updates the investor's status to verified and generates their allocation signature. This decouples identity verification from blockchain operations, keeping sensitive personal data off-chain while using the blockchain for immutable, permissioned financial commitments.

The smart contract must be designed to work with this off-chain whitelist. Key functions include commitEth or commitUSDC, which require a signature parameter. The contract verifies that signature is a valid sign from the trusted signer for the msg.sender and that the commitment amount does not exceed the allocated cap embedded in the signed message. It then records the commitment and transfers the funds. Use OpenZeppelin's EIP712 standard for structured data signing to prevent replay attacks and improve user experience by showing clear signing messages in wallets like MetaMask.

Security audits are non-negotiable for both the smart contracts and the web application. Common vulnerabilities include signature replay across different sales, frontend injection attacks that could steal signatures, and insecure direct object references in the backend API that might allow users to view others' data. Implement rate limiting, use nonces in your signed messages, and ensure all sensitive endpoints are protected with authentication. The final portal should provide investors with a clear dashboard showing their verification status, allocation limit, committed amount, and expected token distribution timeline post-sale.

INFRASTRUCTURE

Compliance Feature Comparison: Traditional vs. ZK-Based

A technical comparison of compliance mechanisms for private sale infrastructure, highlighting the trade-offs between established and emerging cryptographic approaches.

Compliance FeatureTraditional KYC/AMLZK-Based VerificationHybrid Model

Identity Verification

Centralized KYC Provider

ZK Proof of Credential

ZK Proof + Selective KYC

On-Chain Privacy

Regulatory Audit Trail

Full Data Access

Selective Disclosure via ZK

ZK Proofs + Encrypted Logs

Gas Cost per Verification

$5-15

$0.50-2.00

$2-8

Settlement Finality Delay

1-3 days

< 1 sec

1-3 days

Cross-Jurisdiction Portability

Resistance to Sybil Attacks

Database Checks

Proof of Uniqueness

Proof of Uniqueness + Database

Developer Integration Complexity

Medium

High

High

PRIVATE SALE INFRASTRUCTURE

Frequently Asked Questions

Common technical questions and troubleshooting for developers building compliant private sale platforms on EVM chains.

A whitelist mechanism is an access control layer that restricts token purchase rights to pre-approved addresses. It's a core component of KYC/AML compliance for private sales. Secure implementation requires on-chain verification of off-chain approvals.

Key Implementation Steps:

  1. Off-Chain Verification: Use a backend service to collect and verify investor identity (KYC) and accreditation status. Store only a commitment (like a hashed signature) on-chain.
  2. On-Chain Validation: Deploy a smart contract with a mapping(address => bool) public whitelist. Expose a permissioned function (e.g., addToWhitelist(bytes32 signature, bytes memory sig)) that uses ecrecover to validate a signed message from your admin key.
  3. Purchase Guard: In your sale contract's buy function, include the check require(whitelist[msg.sender], "Not whitelisted");.

Critical Security Note: Never store raw KYC data on-chain. Use a Merkle tree or signature-based approach to minimize gas costs and preserve privacy. The Chainscore Labs Compliance SDK provides audited modules for this pattern.

conclusion-next-steps
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have now configured the core components of a compliance-first private sale infrastructure. This foundation enables secure, automated, and legally sound token distribution.

Your setup now integrates on-chain verification with off-chain compliance. The key components you have operationalized are: a KYC/AML verification provider (like Chainscore or Synaps), a whitelist manager smart contract, a secure multi-signature wallet (e.g., Safe) for treasury management, and a vesting contract (e.g., using OpenZeppelin's VestingWallet). This architecture ensures that only verified participants can interact with the sale, funds are protected, and token releases are automated and trustless.

For ongoing management, you must monitor the whitelist contract for new verifications and process refunds for any failed contributions. Use a script or a dashboard like the one provided by your KYC platform to sync verified addresses. It is critical to conduct a final security audit of all smart contracts, including the token, sale, and vesting contracts, before the mainnet deployment. Engage a reputable firm like CertiK or OpenZeppelin for this review.

Next, prepare your legal documentation. Ensure your Simple Agreement for Future Tokens (SAFT) or token purchase agreement is finalized and that your KYC process aligns with its stipulations. Communicate clearly with investors about the verification steps, contribution windows, and vesting schedule. Transparency here builds trust and reduces support overhead.

Finally, consider the next phase of your token's lifecycle. Plan the transition from the private sale contract to liquidity provisioning on a DEX. Determine the initial liquidity pool size, select an AMM like Uniswap V3 or Balancer, and prepare a timelock or community-governed proposal for the liquidity deployment. Your compliance-first foundation now positions you to scale into public distribution with significantly reduced regulatory and execution risk.