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:
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:
- Deployed equity token – Created via
tokenCreatewithtype: "equity" - Governance role – Required to add and configure compliance modules
- API key – See Getting started
- 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 thesystemAddressto get the system used by the dApp - The
complianceModuleRegistrycontains all registered compliance modules - Filter by
typeId === "collateral"to find the collateral module - The
modulefield 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:
| Parameter | Type | Description | Example |
|---|---|---|---|
proofTopic | BigInt | ERC-735 claim topic ID for collateral proofs (use keccak256("COLLATERAL") or custom topic) | "123456789..." |
ratioBps | number | Collateral ratio in basis points. 0 = disabled, 10000 = 100%, 20000 = 200%. Required collateral = supply × ratio / 10000 | 10000 (100% backing) |
trustedIssuers | address[] | 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
canAddClaimfunction 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.
Validation steps
-
Mint detection – Module checks if
from == address(0)(minting operation). Regular transfers skip validation. -
Ratio check – If
ratioBps == 0, collateral enforcement is disabled and minting proceeds. -
Identity resolution – Module loads the token's OnchainID identity address from the token contract.
-
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
-
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)
-
Collateral calculation – Module calculates required collateral using ceiling division:
uint256 postSupply = currentSupply + mintAmount; uint256 requiredCollateral = (postSupply * ratioBps + 9999) / 10000; -
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:
-
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 -
Issue a new collateral claim with sufficient amount or update existing claim
-
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
isClaimValidfunction
Solution:
- Verify the issuer address is in the trusted issuer registry for the collateral topic
- Check claim expiry timestamp is in the future
- Confirm claim data encoding matches
abi.encode(amount, expiry) - Verify issuer's
isClaimValidreturns true for the claim
Next steps
- Identity and compliance system – Understand claim-based verification and trusted issuer registries
- Compliance module architecture – Learn how compliance modules integrate with token operations
- Create and mint equities – Deploy equity tokens with initial compliance configuration
- API reference – Explore all compliance module endpoints