SettleMint
Developer guidesRunbooks

Configure equity collateral

Configure collateral backing requirements for equity tokens with the Collateral Compliance Module. Install the module, issue a token-identity collateral claim, verify collateral stats, and mint only when backing is sufficient.

The Collateral Compliance Module enforces reserve requirements for equity tokens. Before each mint, the module checks the token identity for a valid collateral claim. The mint fails when the claim does not cover the post-mint supply at the configured ratio.

Use this how-to when you already have an equity token and need mint-time reserve controls. You will install the module and issue the claim. Then check the stats endpoint and mint only after the backing is visible.

Rendering diagram...

What the module enforces

The CollateralComplianceModule checks the token contract's OnchainID identity before minting. The identity must hold a valid collateral claim. The claim amount must meet or exceed the required ratio against the post-mint total supply. Regular transfers skip this check.

Enforcement behavior:

  • 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 and subject-specific trusted issuer registry with token-specific issuers
  • Mint-only enforcement – Only validates minting operations; regular transfers are unrestricted

Production requirement: the claim is not the reserve itself. Keep the off-chain reserve evidence, valuation method, attestor approval, and renewal process outside DALP, then publish only the signed collateral amount and expiry that the token identity needs for mint checks.


Collateral configuration workflow

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

Rendering diagram...

SDK calls in this workflow:

  • system.read – Retrieve the system configuration, including the Collateral Compliance Module address from the compliance module registry
  • system.claimTopics.list – Retrieve the registered collateral claim topic ID from the system
  • token.installComplianceModule – Install the Collateral Compliance Module using the retrieved address, topic ID, initial ratio, and trusted issuers
  • token.configureComplianceModule – Adjust collateral ratio or trusted issuers after installation (optional)
  • token.claimIssue – Add the collateral claim to the token identity with an amount and expiry
  • token.statsCollateralRatio – Verify total collateral, required collateral, mintable supply, utilization, and parity confidence before or after minting

Prerequisites

Before configuring collateral requirements, ensure you have:

  1. Deployed equity token – Created with token.create and type: "equity"
  2. Governance role – Required to issue the collateral claim to the token identity
  3. Compliance-module permissions – Required to install and configure the module
  4. Supply-management role – Required for the mint that the module checks
  5. API key – See Getting started
  6. Collateral claim infrastructure – The token identity must receive collateral claims from an authorized issuer or governance operator

Note: Retrieve the Collateral Compliance Module address dynamically from the system with system.read in Step 1.


Step 1: Get the collateral 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

  // 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);

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

  // 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);

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 the collateral module

Install the Collateral Compliance Module on your equity token with token.installComplianceModule. Pass the collateral topic ID, initial ratio, and trusted issuers in the module values.

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

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

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 token.configureComplianceModule.

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

  // Step 8 (Optional): Update collateral parameters to 150%
  await dalp.token.configureComplianceModule({
    params: { tokenAddress: equityAddress },
    body: {
      params: {
        typeId: "collateral",
        module: collateralModuleAddress,
        values: {
          proofTopic: collateralTopic.topicId,
          ratioBps: 15_000,
          trustedIssuers: [],
        },
      },
      walletVerification: {
        secretVerificationCode: pincode,
        verificationType: "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 token.claimIssue to add a collateral claim to the token identity. This requires the governance role on the token.

  // 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",
      },
    },
  });

Key points:

  • Governance-authorized issuance – The governance role authorizes direct claim issuance in this SDK flow
  • Automatic on-chain encoding – The API handles ABI encoding of (uint256 amount, uint256 expiry)
  • Claim ownership – The claim is issued to the token identity and later checked by the collateral module
  • Trusted-issuer validation – Mint-time validation accepts claims from the global registry, subject-specific registry entries, or addresses in trustedIssuers

Step 6: Verify configuration

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

Check collateral stats

Call token.statsCollateralRatio after issuing the claim and before large mints:

const collateralStats = await dalp.token.statsCollateralRatio({
  params: { tokenAddress: equityAddress },
});

console.log("Collateral stats:", collateralStats.data);

token.statsCollateralRatio returns the indexed collateral view for the token. Check totalCollateral, requiredCollateral, mintableSupply, utilizationPercentage, configuredCollateralRatioBps, and parity_confidence. A high parity confidence means the indexed stats match the contract-readable inputs. A degraded value means the response is still usable, but an operator should inspect claim decoding, registry availability, or legacy metadata before relying on the ratio operationally.


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 identity, the module uses the highest collateral amount. Issuers can maintain multiple attestations from different sources without lowering the effective backing amount.


Production checklist

Before using collateral-backed equity minting in production:

  • Keep the source reserve evidence and valuation process current outside the platform.
  • Choose a proof topic that matches the attestation process your auditors and operators recognize.
  • Register or configure only issuers that are allowed to attest reserve amounts for this token.
  • Set ratioBps to the policy threshold. Use 10000 for 100% backing, 15000 for 150%, and 20000 for the maximum 200% ratio.
  • Renew the collateral claim before expiryTimestamp; expired claims fail mint-time validation.
  • Check collateral stats before large mints and investigate parity_confidence: "degraded" before using the result as operating evidence.
  • Separate emergency pause and supply-management procedures from reserve evidence. The module blocks under-collateralized mints. It does not manage reserve custody or off-chain valuation.

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.installComplianceModule({
    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.configureComplianceModule({
    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 full script above can be copied and adapted for a collateral-backed equity setup.


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 token.configureComplianceModule.

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