SettleMint
Developer guidesRunbooks

Configure equity collateral

Configure collateral backing requirements for equity tokens via the Collateral Compliance Module API, enforcing minimum reserve ratios before minting shares. The module validates that the token's identity holds sufficient collateral claims before allowing new tokens to be minted.

The Collateral Compliance Module enforces collateral requirements for equity tokens by validating on-chain collateral claims before allowing mints. This ensures that equity shares are backed by verifiable reserves at a configurable ratio, providing transparency and trust for investors.

Overview

The CollateralComplianceModule checks that the token contract's OnchainID identity holds a valid collateral claim before permitting minting operations. The claim must contain a collateral amount that meets or exceeds the required ratio relative to the post-mint total supply.

Key features:

  • Configurable proof topic – Specify which ERC-735 claim topic represents collateral proofs
  • Adjustable collateral ratio – Set ratios from 0% (disabled) to 200% (over-collateralized) in basis points
  • Additional trusted issuers – Extend the global trusted issuer registry with token-specific issuers
  • Mint-only enforcement – Only validates minting operations; regular transfers are unrestricted

Use cases:

  • Private equity funds requiring 100% asset backing
  • Over-collateralized structures (150-200%) for investor protection
  • Regulated securities requiring verified reserve attestations
  • Tokenized real estate with collateral claims representing property valuations

Collateral configuration workflow

This diagram shows the complete API workflow for configuring collateral requirements on an equity token:

Rendering diagram...

API calls in this workflow:

  • GET /system/default – Retrieve the system configuration including the Collateral Compliance Module address from the compliance module registry
  • GET /system/claim-topics – Retrieve the registered collateral claim topic ID from the system
  • POST /token/:address/add-compliance-module – Register Collateral Compliance Module using the retrieved address, topic ID, initial ratio, and trusted issuers
  • PUT /token/:address/compliance-module-params – Adjust collateral ratio or trusted issuers after deployment (optional)
  • POST /token/:address/claim/issue – Add collateral claim to the token's identity with amount and expiry
  • GET /token/:address – Verify module configuration and claim validity before minting

Prerequisites

Before configuring collateral requirements, ensure you have:

  1. Deployed equity token – Created via tokenCreate with type: "equity"
  2. Governance role – Required to add and configure compliance modules
  3. API key – See Getting started
  4. Collateral claim infrastructure – The token's OnchainID identity must receive collateral claims from a trusted issuer (covered in Step 4)

Note: The Collateral Compliance Module address is retrieved dynamically from the system via systemRead (Step 1 of the workflow).


Step 1: Get Collateral Compliance Module address

Before adding the Collateral Compliance Module to your token, retrieve its deployed address from the system's compliance module registry.

Retrieve module address from system

    body: {
      params: {
        typeId: "collateral",
        module: collateralModuleAddress,
        values: {
          proofTopic: collateralTopic.topicId,
          ratioBps: 10_000,
          trustedIssuers: [],
        },
      },
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Collateral module added (100% ratio)");

Expected result:

  • Returns the deployed Collateral Compliance Module address from the system
  • This address is required when adding the module to your token in Step 3

Key points:

  • Use "default" as the systemAddress to get the system used by the dApp
  • The complianceModuleRegistry contains all registered compliance modules
  • Filter by typeId === "collateral" to find the collateral module
  • The module field contains the deployed contract address

Step 2: Get collateral topic ID

Retrieve the registered collateral claim topic ID from the system. This ID identifies which ERC-735 claim topic represents collateral proofs.

Retrieve claim topics

  await dalp.token.setComplianceModuleParams({
    params: { tokenAddress: equityAddress },
    body: {
      params: {
        typeId: "collateral",
        module: collateralModuleAddress,
        values: {
          proofTopic: collateralTopic.topicId,
          ratioBps: 15_000,
          trustedIssuers: [],

Expected result:

  • Returns the collateral topic ID registered in the system
  • This ID is required for the next step when configuring the compliance module

Step 3: Add Collateral Compliance Module

Add the Collateral Compliance Module to your equity token using tokenAddComplianceModule. This configures the module with the collateral topic ID, initial collateral ratio, and trusted issuers.

Configuration parameters

The module accepts three parameters via the values object:

ParameterTypeDescriptionExample
proofTopicBigIntERC-735 claim topic ID for collateral proofs (use keccak256("COLLATERAL") or custom topic)"123456789..."
ratioBpsnumberCollateral ratio in basis points. 0 = disabled, 10000 = 100%, 20000 = 200%. Required collateral = supply × ratio / 1000010000 (100% backing)
trustedIssuersaddress[]Optional. Additional trusted issuers for the proof topic. Only required if the claim issuer is not already registered as a global trusted issuer for the collateral topic. These are merged with global and subject-specific issuers.[] (use global) or ["0xABCD..."]

TypeScript example

      },
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Collateral parameters updated (150% ratio)");

  // Step 9: Unpause the equity
  await dalp.token.unpause({
    params: { tokenAddress: equityAddress },
    body: {
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Equity unpaused");

  // Step 10: Issue collateral claim to token identity
  const expiryTimestamp = Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60;

  await dalp.token.claimIssue({

Expected result:

  • The module is registered on the equity token's compliance contract
  • Future mints will validate collateral claims against the configured ratio
  • The token data is returned with updated compliance modules

Step 4: Update collateral parameters (optional)

If you need to adjust the collateral ratio or trusted issuers after initial configuration, use tokenSetComplianceModuleParams.

When to update parameters

  • Increase collateral ratio – Strengthen investor protections during market volatility
  • Decrease collateral ratio – Adjust after successful track record or regulatory changes
  • Add trusted issuers – Include additional attestors if they're not registered as global trusted issuers for the collateral topic
  • Change proof topic – Switch to a different claim topic (requires coordination with claim issuers)

TypeScript example

    body: {
      claim: {
        topic: "collateral",
        data: {
          amount: 1_500_000_000_000_000_000_000n,
          expiryTimestamp: expiryTimestamp.toString(),
        },
      },
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Collateral claim issued");

  // Step 11: Mint shares (validates collateral)
  await dalp.token.mint({
    params: { tokenAddress: equityAddress },
    body: {
      recipients: [myWallet],
      amounts: [100n],
      walletVerification: {
        secretVerificationCode: pincode,

Note: Parameter updates take effect immediately for subsequent minting operations. Existing token holders are not affected.


Step 5: Issue collateral claim to token identity

The Collateral Compliance Module validates claims on the token's OnchainID identity, not individual investor identities. Before minting, you must add a collateral claim to the token identity using the governance role.

Claim structure

Collateral claims contain two fields:

  • amount – Collateral amount as string (e.g., "1000000000000000000000" for 1000 tokens with 18 decimals)
  • expiryTimestamp – Unix timestamp as string when the claim expires (must be > current time)

Issue the claim via API

Use tokenClaimIssue to add a collateral claim to the token's identity. This requires the governance role on the token.

Key points:

  • No trusted issuer required – The governance role authorizes claim issuance directly
  • Automatic on-chain encoding – The API handles ABI encoding of (uint256 amount, uint256 expiry)
  • Claim ownership – The claim is issued to the token's identity, by the caller's identity
  • Validation – The smart contract's canAddClaim function verifies the caller has the governance role

Step 6: Verify configuration

After adding the module and issuing collateral claims, verify the configuration before attempting to mint.

Check token compliance modules

Note: The generated OpenAPI client may not include all type information for compliance modules. Use tokenRead to retrieve the token data and inspect the compliance configuration. The full example script demonstrates the complete verification workflow.


Understanding collateral validation

The Collateral Compliance Module performs validation during minting operations using a multi-step process.

Rendering diagram...

Validation steps

  1. Mint detection – Module checks if from == address(0) (minting operation). Regular transfers skip validation.

  2. Ratio check – If ratioBps == 0, collateral enforcement is disabled and minting proceeds.

  3. Identity resolution – Module loads the token's OnchainID identity address from the token contract.

  4. Issuer aggregation – Module builds a combined list of trusted issuers:

    • Global issuers from the trusted issuer registry for the proof topic
    • Subject-specific issuers authorized for the token identity
    • Additional issuers from the module configuration
  5. Claim search – Module queries all claims on the token's identity matching the proof topic and validates:

    • Claim is issued by a trusted issuer
    • Claim signature is valid (verified with issuer's isClaimValid)
    • Claim data is properly ABI-encoded as (uint256 amount, uint256 expiry)
    • Claim has not expired (expiry > block.timestamp)
  6. Collateral calculation – Module calculates required collateral using ceiling division:

    uint256 postSupply = currentSupply + mintAmount;
    uint256 requiredCollateral = (postSupply * ratioBps + 9999) / 10000;
  7. Comparison – If claimAmount >= requiredCollateral, minting proceeds. Otherwise, the transaction reverts with "ComplianceCheckFailed: Insufficient collateral for mint".

Best claim selection

If multiple valid collateral claims exist on the token's identity, the module uses the highest collateral amount to maximize the chance of passing validation. This allows issuers to maintain multiple attestations from different sources.


Full example script

Complete TypeScript script demonstrating collateral configuration and validation:

import { createDalpClient } from "@settlemint/dalp-sdk";

async function main() {
  // Step 1: Create the SDK client
  const dalp = createDalpClient({
    url: "https://your-platform.example.com",
    apiKey: "YOUR_API_KEY",
  });
  const pincode = "YOUR_PINCODE";

  // Step 2: Get your wallet address
  const me = await dalp.user.me({});
  const myWallet = me.data.wallet;
  if (!myWallet) {
    throw new Error("No wallet found. Create a wallet first via the DALP dashboard.");
  }
  console.log("Wallet:", myWallet);

  // Step 3: Create equity token
  const equity = await dalp.token.create({
    body: {
      type: "equity",
      name: "Collateralized Series A Shares",
      symbol: "CSAS",
      decimals: 0,
      countryCode: "840",
      priceCurrency: "USD",
      basePrice: "10.00",
      class: "COMMON_EQUITY",
      category: "VOTING_COMMON_STOCK",
      initialModulePairs: [],
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });

  if ("transactionId" in equity) {
    console.log("Equity creation queued:", equity.transactionId);
    return;
  }
  const equityAddress = equity.data.id;
  console.log("Equity created:", equityAddress);

  // Step 4: Grant token roles
  await dalp.token.grantRole({
    params: { tokenAddress: equityAddress },
    body: {
      account: myWallet,
      roles: ["supplyManagement", "emergency", "governance"],
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Roles granted");

  // Step 5: Get Collateral Compliance Module address from system
  const system = await dalp.system.read({ params: { systemAddress: "default" } });
  const registry = system.data.complianceModuleRegistry;
  if (!registry) {
    throw new Error("Compliance module registry not found. Ensure the system is fully deployed.");
  }
  const collateralModule = registry.complianceModules.find((m) => m.typeId === "collateral");

  if (!collateralModule) {
    throw new Error(
      "Collateral compliance module not registered in system. Check system admin has deployed the module."
    );
  }

  const collateralModuleAddress = collateralModule.module;
  console.log("Collateral module:", collateralModuleAddress);

  // Step 6: Get topic ID for collateral claims
  const topics = await dalp.system.claimTopics.list({ query: {} });
  const collateralTopic = topics.data.find((t) => t.name === "collateral");

  if (!collateralTopic) {
    throw new Error("Collateral topic not found in registry. Ensure the topic is registered by a claimPolicyManager.");
  }
  console.log("Collateral topic ID:", collateralTopic.topicId);

  // Step 7: Add Collateral Compliance Module
  await dalp.token.addComplianceModule({
    params: { tokenAddress: equityAddress },
    body: {
      params: {
        typeId: "collateral",
        module: collateralModuleAddress,
        values: {
          proofTopic: collateralTopic.topicId,
          ratioBps: 10_000,
          trustedIssuers: [],
        },
      },
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Collateral module added (100% ratio)");

  // Step 8 (Optional): Update collateral parameters to 150%
  await dalp.token.setComplianceModuleParams({
    params: { tokenAddress: equityAddress },
    body: {
      params: {
        typeId: "collateral",
        module: collateralModuleAddress,
        values: {
          proofTopic: collateralTopic.topicId,
          ratioBps: 15_000,
          trustedIssuers: [],
        },
      },
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Collateral parameters updated (150% ratio)");

  // Step 9: Unpause the equity
  await dalp.token.unpause({
    params: { tokenAddress: equityAddress },
    body: {
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Equity unpaused");

  // Step 10: Issue collateral claim to token identity
  const expiryTimestamp = Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60;

  await dalp.token.claimIssue({
    params: { tokenAddress: equityAddress },
    body: {
      claim: {
        topic: "collateral",
        data: {
          amount: 1_500_000_000_000_000_000_000n,
          expiryTimestamp: expiryTimestamp.toString(),
        },
      },
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Collateral claim issued");

  // Step 11: Mint shares (validates collateral)
  await dalp.token.mint({
    params: { tokenAddress: equityAddress },
    body: {
      recipients: [myWallet],
      amounts: [100n],
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "PINCODE",
      },
    },
  });
  console.log("Mint succeeded — collateral validation passed");
}

await main();

The complete source file is available at kit/dapp/src/examples/configure-equity-collateral.ts and is type-checked as part of the project build.


Troubleshooting

"ComplianceCheckFailed: Insufficient collateral for mint"

Cause: The collateral amount in the claim is less than the required amount for the requested mint.

Solution:

  1. Calculate required collateral:

    const currentSupply = 1000; // Current total supply
    const mintAmount = 500; // Requested mint
    const ratioBps = 10000; // 100% ratio
    
    const postSupply = currentSupply + mintAmount; // 1500
    const required = Math.ceil((postSupply * ratioBps) / 10000); // 1500
  2. Issue a new collateral claim with sufficient amount or update existing claim

  3. Retry minting operation

"Proof topic cannot be zero"

Cause: The proofTopic parameter is set to 0 when adding the module.

Solution: Specify a valid ERC-735 claim topic ID (keccak256 hash of topic name or custom numeric ID).

"Ratio cannot exceed 20000 (200%)"

Cause: The ratioBps parameter exceeds the maximum allowed value.

Solution: Set ratioBps to a value between 0 and 20000. For 200% over-collateralization, use 20000.

"Trusted issuer cannot be zero address"

Cause: The trustedIssuers array contains 0x0000000000000000000000000000000000000000.

Solution: Remove zero addresses from the trustedIssuers array or leave it empty to rely only on global trusted issuers.

Mint succeeds but collateral not validated

Cause: The ratioBps is set to 0, which disables collateral enforcement.

Solution: Set ratioBps to a non-zero value (e.g., 10000 for 100% backing) via tokenSetComplianceModuleParams.

Claim exists but validation fails

Cause: The claim may be:

  • Issued by an untrusted issuer (not in global registry or module config)
  • Expired (expiry <= block.timestamp)
  • Improperly encoded (not matching (uint256, uint256) format)
  • Revoked or invalid according to issuer's isClaimValid function

Solution:

  1. Verify the issuer address is in the trusted issuer registry for the collateral topic
  2. Check claim expiry timestamp is in the future
  3. Confirm claim data encoding matches abi.encode(amount, expiry)
  4. Verify issuer's isClaimValid returns true for the claim

Next steps

On this page