Transfer Restrictions
The Security Token implements a sophisticated two-layer transfer restriction system that combines multi-type token support with identity-based compliance rules. This system replaces traditional transfer groups with a more flexible approach based on token types and investor identities.
Architecture Overview
Transfer restrictions are enforced through the integrated TransferRules.sol
contract, which works closely with IdentityRegistry.sol
to provide comprehensive compliance controls:
Two-Layer Rule System
Layer 1: Token Type Assignment Rules
Automatically assigns token types based on investor identity:
// Configure US Accredited investors to receive RegD tokens
transferRules.setTokenTypeRule(
840, // region: United States
2, // accreditation: Accredited
2, // tokenType: RegD
true, // requiresAmlKyc
true // isActive
);
Layer 2: Transfer Restriction Rules
Define holding periods and compliance requirements per token type:
// Configure 6-month holding period for RegD tokens
transferRules.setTransferRule(
2, // tokenType: RegD
840, // recipientRegion: US
0, // recipientAccreditation: Any
TransferRule({
lockDurationSeconds: 180 days,
requiresAmlKyc: true,
isActive: true
})
);
Transfer Validation Process
Here's how transfer restrictions are validated in the current system:
Comprehensive Transfer Rule Configuration
The system supports complex regulatory scenarios through flexible rule configuration:
1. Token Type Assignment Examples
// US Retail Investors → RegCF tokens
transferRules.setTokenTypeRule(840, 1, 3, true, true); // US, Retail, RegCF, AML/KYC required, Active
// US Accredited Investors → RegD tokens
transferRules.setTokenTypeRule(840, 2, 2, true, true); // US, Accredited, RegD, AML/KYC required, Active
// Non-US Qualified Investors → RegS tokens
transferRules.setTokenTypeRule(826, 3, 1, true, true); // UK, Qualified, RegS, AML/KYC required, Active
// Institutional Investors → Custom tokens
transferRules.setTokenTypeRule(0, 4, 4, true, true); // Any region, Institutional, Custom, AML/KYC required, Active
2. Transfer Restriction Examples
// RegS 1-year holding period (offshore to any)
transferRules.setTransferRule(1, 0, 0, TransferRule({
lockDurationSeconds: 365 days,
requiresAmlKyc: true,
isActive: true
}));
// RegD 6-month holding period (US accredited to any)
transferRules.setTransferRule(2, 0, 0, TransferRule({
lockDurationSeconds: 180 days,
requiresAmlKyc: true,
isActive: true
}));
// RegCF restrictions (retail to accredited only)
transferRules.setTransferRule(3, 840, 2, TransferRule({
lockDurationSeconds: 0, // No holding period
requiresAmlKyc: true,
isActive: true
}));
Practical Configuration Process
Step 1: Identity Management
// Register investor identity
uint256[] memory regions = new uint256[](1);
regions[0] = 840; // United States
IdentityInfo memory identity = IdentityInfo({
regions: regions,
accreditationType: 2, // Accredited
lastAmlKycChangeTimestamp: 0, // Use current timestamp
lastAccreditationChangeTimestamp: 0,
amlKycPassed: true
});
identityRegistry.setIdentity(investorAddress, identity);
Step 2: Rule Configuration
// Set token type rules for automatic assignment
transferRules.setTokenTypeRule(840, 2, 2, true, true); // US Accredited → RegD, Active
// Set transfer restrictions for RegD tokens
transferRules.setTransferRule(2, 0, 0, TransferRule({
lockDurationSeconds: 180 days,
requiresAmlKyc: true,
isActive: true
}));
Step 3: Token Operations
// Mint tokens (type automatically determined via rules)
token.mint(investorAddress, 1000 * 10**decimals);
// Or mint specific type
token.mintTokenType(investorAddress, 1000 * 10**decimals, 2); // RegD
Advanced Transfer Scenarios
Multi-Jurisdiction Compliance
// Investor with dual citizenship (US + UK)
uint256[] memory dualRegions = new uint256[](2);
dualRegions[0] = 840; // US
dualRegions[1] = 826; // UK
// Configure rules for both jurisdictions
transferRules.setTokenTypeRule(840, 2, 2, true, true); // US Accredited → RegD, Active
transferRules.setTokenTypeRule(826, 3, 1, true, true); // UK Qualified → RegS, Active
Time-Based Restrictions
// Different holding periods for different recipient types
transferRules.setTransferRule(2, 840, 2, TransferRule({
lockDurationSeconds: 90 days, // 3 months to US accredited
requiresAmlKyc: true,
isActive: true
}));
transferRules.setTransferRule(2, 0, 1, TransferRule({
lockDurationSeconds: 180 days, // 6 months to retail investors
requiresAmlKyc: true,
isActive: true
}));
Error Codes and Restriction Messages
The system provides detailed error codes for different restriction scenarios:
Code | Restriction Type | Description |
---|---|---|
0 | SUCCESS | Transfer allowed |
1 | SENDER_NOT_AMLKYCPASSED | Sender failed AML/KYC verification |
2 | RECIPIENT_NOT_AMLKYCPASSED | Recipient failed AML/KYC verification |
3 | HOLDING_PERIOD_NOT_MET | Token holding period requirement not satisfied |
4 | RECIPIENT_NOT_ELIGIBLE | Recipient not eligible for this token type |
5 | TRANSFER_RULE_NOT_FOUND | No applicable transfer rule configured |
Administrative Functions
Function | Description | Access Control |
---|---|---|
setTokenTypeRule(region, accreditation, tokenType, requiresAmlKyc, isActive) | Configure automatic token type assignment | Transfer Admin |
batchSetTokenTypeRules(regions[], accreditations[], tokenTypes[], requiresAmlKycFlags[], isActiveFlags[]) | Configure multiple token type rules in batch | Transfer Admin |
setDefaultTokenTypeRule(tokenType, requiresAmlKyc, isActive) | Set a global fallback token type when no specific rule matches | Transfer Admin |
resetDefaultTokenTypeRule() | Reset the default rule to inactive GENERIC | Transfer Admin |
defaultTokenTypeRule() | Get the current default rule configuration | Anyone (view) |
setTransferRule(tokenType, recipientRegion, recipientAccreditation, rule) | Set transfer restrictions for token types | Transfer Admin |
updateTransferRule(ruleId, rule) | Update existing transfer rule | Transfer Admin |
deactivateTransferRule(ruleId) | Temporarily disable a transfer rule | Transfer Admin |
checkTransferAllowed(tokenType, mintTimestamp, recipient, identityRegistry) | Query if transfer would be allowed | Anyone (view) |
Batch Configuration
For efficiency when setting up multiple rules, use the batch function:
// Configure multiple token type rules in one transaction
uint256[] memory regions = new uint256[](3);
regions[0] = 840; // US
regions[1] = 826; // UK
regions[2] = 392; // Japan
uint256[] memory accreditations = new uint256[](3);
accreditations[0] = 2; // Accredited
accreditations[1] = 3; // Qualified
accreditations[2] = 3; // Qualified
uint256[] memory tokenTypes = new uint256[](3);
tokenTypes[0] = 2; // RegD
tokenTypes[1] = 1; // RegS
tokenTypes[2] = 1; // RegS
bool[] memory requiresAmlKycFlags = new bool[](3);
requiresAmlKycFlags[0] = true;
requiresAmlKycFlags[1] = true;
requiresAmlKycFlags[2] = true;
bool[] memory isActiveFlags = new bool[](3);
isActiveFlags[0] = true;
isActiveFlags[1] = true;
isActiveFlags[2] = true;
transferRules.batchSetTokenTypeRules(
regions,
accreditations,
tokenTypes,
requiresAmlKycFlags,
isActiveFlags
);
This modern transfer restriction system provides regulatory compliance while maintaining the flexibility needed for complex international securities offerings.