SharesTokenizerV7
Overview
Version: 7.0.0 Type: Concrete Upgradeable Contract License: MIT Token Standard: ERC-20 Inherits: ERC20Upgradeable, BaseTokenizerV7, TrustGraphIntegration
SharesTokenizerV7 implements fractional share-based document tokenization using ERC-20 fungible tokens. It enables proportional ownership where multiple parties can hold fungible shares of a document.
Purpose
- Tokenize share-based documents as fungible ERC-20 tokens
- Enable fractional ownership and proportional rights
- Support company equity, partnership interests, and cooperative memberships
- Integrate with DeFi ecosystem via standard ERC-20 interface
- Issue trust credentials when all reserved shares are claimed
Key Features
- ERC-20 fungible token standard
- Per-document share tracking with reservations
- Trust Graph integration for reputation building
- Named reservations only (ERC-20 limitation)
- Standard transferability via ERC-20
- Shareholder tracking for governance
Purpose and Use Cases
Company Shares/Equity
Scenario: Startup issues 1,000,000 shares to founders and investors
// Reserve shares for founders and investors
sharesTokenizer.reserveToken(integraHash, 0, founder1, 400000, processHash); // 40%
sharesTokenizer.reserveToken(integraHash, 0, founder2, 300000, processHash); // 30%
sharesTokenizer.reserveToken(integraHash, 0, investor1, 200000, processHash); // 20%
sharesTokenizer.reserveToken(integraHash, 0, investor2, 100000, processHash); // 10%
// Each party claims their shares
// Result: ERC-20 tokens representing equity ownershipBenefits:
- Proportional voting rights based on token balance
- Easy to track ownership percentages
- Standard ERC-20 transfers for secondary markets
- Compatible with governance systems
Partnership Interests
Scenario: Law firm partnership with profit-sharing
// 3 partners with different ownership levels
sharesTokenizer.reserveToken(integraHash, 0, partner1, 5000, processHash); // 50%
sharesTokenizer.reserveToken(integraHash, 0, partner2, 3000, processHash); // 30%
sharesTokenizer.reserveToken(integraHash, 0, partner3, 2000, processHash); // 20%
// Total: 10,000 shares representing 100% partnershipCooperative Memberships
Scenario: Housing cooperative with member shares
// Each unit gets shares proportional to size/value
sharesTokenizer.reserveToken(integraHash, 0, unit101Owner, 100, processHash);
sharesTokenizer.reserveToken(integraHash, 0, unit102Owner, 150, processHash);
sharesTokenizer.reserveToken(integraHash, 0, unit201Owner, 125, processHash);
// Voting power = share countFractional Real Estate
Scenario: Commercial property split among investors
// $1M property, 100 shares at $10k each
sharesTokenizer.reserveToken(integraHash, 0, investor1, 30, processHash); // 30%
sharesTokenizer.reserveToken(integraHash, 0, investor2, 25, processHash); // 25%
sharesTokenizer.reserveToken(integraHash, 0, investor3, 25, processHash); // 25%
sharesTokenizer.reserveToken(integraHash, 0, investor4, 20, processHash); // 20%
// Rental income distributed proportionallyKey Features
1. Fungible Share Model
Unlike NFTs, all shares are identical and interchangeable:
// All shares have equal value
balanceOf(alice) = 1000 shares
balanceOf(bob) = 500 shares
// Alice has 2x Bob's ownership2. Per-Document Tracking
Each integraHash has its own share pool:
struct ShareData {
bytes32 integraHash;
uint256 totalShares; // Total claimed shares
uint256 reservedShares; // Not yet claimed
mapping(address => uint256) reservations;
mapping(address => bool) claimed;
address[] shareholders;
}3. Trust Graph Integration
Issues reputation credentials when document complete:
// After all shareholders claim their shares
// Trust credential issued to each shareholder
// Builds on-chain reputation for future transactions4. Standard ERC-20 Compatibility
Works with all ERC-20 infrastructure:
// Standard transfers
transfer(recipient, amount);
approve(spender, amount);
transferFrom(sender, recipient, amount);
// DeFi integration
uniswapRouter.swapExactTokensForETH(amount, ...);Architecture
State Variables
struct ShareData {
bytes32 integraHash; // Document identifier
uint256 totalShares; // Total claimed/minted shares
uint256 reservedShares; // Reserved but not claimed
mapping(address => uint256) reservations; // Per-recipient reservations
mapping(address => bool) claimed; // Claim status per recipient
address[] shareholders; // All shareholders
}
mapping(bytes32 => ShareData) private shareData;
IEAS private eas; // Ethereum Attestation Service for Trust GraphToken Identification
- integraHash: Document identifier
- tokenId: Always 0 (ERC-20 doesn’t use token IDs)
- amount: Number of shares reserved/claimed
Inheritance Hierarchy
ERC20Upgradeable (OpenZeppelin)
├─ Standard fungible token implementation
└─ Transfer, approve, allowance functions
BaseTokenizerV7
├─ Access control (owner, executor, governor)
├─ Capability verification
├─ Document registry integration
└─ Process hash validation
TrustGraphIntegration
├─ Trust credential issuance
├─ Document completion detection
└─ EAS integrationFunctions
Initialization
initialize
function initialize(
string memory name_,
string memory symbol_,
address governor,
address _documentRegistry,
address _namespace,
address _providerRegistry,
bytes32 _defaultProviderId,
bytes32 _credentialSchema,
address _trustRegistry,
address _easAddress
) external initializerInitializes the upgradeable contract.
Parameters:
name_: Token name (e.g., “Acme Corp Shares”)symbol_: Token symbol (e.g., “ACME”)governor: Governor address for admin operations_documentRegistry: IntegraDocumentRegistryV7_Immutable address_namespace: CapabilityNamespaceV7_Immutable address_providerRegistry: AttestationProviderRegistryV7_Immutable address_defaultProviderId: Default attestation provider ID_credentialSchema: EAS schema UID for trust credentials_trustRegistry: Trust registry address_easAddress: EAS contract address
Requirements:
- Governor cannot be zero address
- Can only be called once (initializer modifier)
Effects:
- Initializes ERC-20 with name and symbol
- Sets up access control roles
- Integrates with document registry and trust graph
Reserve Functions
reserveToken
function reserveToken(
bytes32 integraHash,
uint256 tokenId,
address recipient,
uint256 amount,
bytes32 processHash
) external override requireOwnerOrExecutor(integraHash) nonReentrant whenNotPausedReserves shares for a specific recipient.
Parameters:
integraHash: Document identifiertokenId: Ignored (always 0 for ERC-20)recipient: Address receiving the sharesamount: Number of shares to reserveprocessHash: Off-chain process correlation ID
Requirements:
- Caller must be document owner or authorized executor
- Recipient cannot be zero address
- Amount must be greater than 0
- Recipient cannot already have a reservation
- Contract must not be paused
Effects:
- Creates reservation for recipient
- Increments
reservedSharescounter - Emits
TokenReservedevent
Events:
emit TokenReserved(integraHash, 0, recipient, amount, processHash, block.timestamp);reserveTokenAnonymous
function reserveTokenAnonymous(
bytes32 integraHash,
uint256 tokenId,
uint256 amount,
bytes calldata encryptedLabel,
bytes32 processHash
) external override requireOwnerOrExecutor(integraHash) nonReentrant whenNotPausedNOT SUPPORTED for ERC-20 shares.
Reverts: “Use reserveToken for ERC-20 shares”
Reason: ERC-20 doesn’t support anonymous reservations well due to lack of distinct token IDs. All shares are fungible, so recipient must be known upfront.
Claim Functions
claimToken
function claimToken(
bytes32 integraHash,
uint256 tokenId,
bytes32 capabilityAttestationUID,
bytes32 processHash
) external override requiresCapabilityWithUID(integraHash, CAPABILITY_CLAIM_TOKEN, capabilityAttestationUID) nonReentrant whenNotPausedClaims reserved shares and mints ERC-20 tokens.
Parameters:
integraHash: Document identifiertokenId: Ignored (always 0 for ERC-20)capabilityAttestationUID: EAS attestation proving claim capabilityprocessHash: Process correlation ID
Requirements:
- Caller must have valid capability attestation
- Caller must have a reservation
- Caller must not have already claimed
- Contract must not be paused
Effects:
- Mints
amountERC-20 tokens to caller - Increments
totalShares - Decrements
reservedShares - Marks caller as claimed
- Adds caller to shareholders array
- Emits
TokenClaimedevent - Triggers trust credential issuance if document complete
Events:
emit TokenClaimed(integraHash, 0, msg.sender, capabilityAttestationUID, processHash, block.timestamp);Trust Graph Integration:
// After claim, if all shares claimed:
_handleTrustCredential(integraHash, msg.sender);
// Issues on-chain trust credential via EASCancellation Functions
cancelReservation
function cancelReservation(
bytes32 integraHash,
uint256 tokenId,
bytes32 processHash
) external override requireOwnerOrExecutor(integraHash) nonReentrant whenNotPausedNOT FULLY IMPLEMENTED - simplified version.
Reverts: “Use specific cancellation function”
Reason: ERC-20 implementation requires recipient address for proper cancellation since reservations are mapped per-recipient.
View Functions
balanceOf
function balanceOf(address account, uint256) public view returns (uint256)Returns ERC-20 balance for account. The tokenId parameter is ignored.
Parameters:
account: Address to querytokenId: Ignored (for interface compatibility)
Returns: Number of shares held by account
getTokenInfo
function getTokenInfo(bytes32 integraHash, uint256)
external view returns (IDocumentTokenizerV7.TokenInfo memory)Returns comprehensive share information.
Parameters:
integraHash: Document identifiertokenId: Ignored
Returns:
struct TokenInfo {
bytes32 integraHash;
uint256 tokenId; // Always 0
uint256 totalSupply; // Total claimed shares
uint256 reserved; // Reserved but unclaimed
address[] holders; // All shareholders
bytes encryptedLabel; // Empty (not used)
address reservedFor; // Zero address (not applicable)
bool claimed; // False (not per-token)
address claimedBy; // Zero address (not applicable)
}getClaimStatus
function getClaimStatus(bytes32 integraHash, uint256)
external view returns (bool, address)Returns whether any shares claimed.
Returns:
bool: True if totalShares > 0address: Zero address (ERC-20 has multiple holders)
tokenType
function tokenType() external pure returns (IDocumentTokenizerV7.TokenType)Returns token standard identifier.
Returns: TokenType.ERC20
Utility Functions
getEncryptedLabel
function getEncryptedLabel(bytes32, uint256) external pure returns (bytes memory)Returns empty bytes (not supported for ERC-20).
getAllEncryptedLabels
function getAllEncryptedLabels(bytes32)
external pure returns (uint256[] memory, bytes[] memory)Returns empty arrays (not supported for ERC-20).
getReservedTokens
function getReservedTokens(bytes32, address) external pure returns (uint256[] memory)Returns empty array (ERC-20 doesn’t have distinct token IDs).
Token Lifecycle
Complete Flow Example
// 1. DEPLOY
SharesTokenizerV7 sharesTokenizer = new SharesTokenizerV7();
sharesTokenizer.initialize(
"Acme Corp",
"ACME",
governor,
documentRegistry,
namespace,
providerRegistry,
defaultProviderId,
credentialSchema,
trustRegistry,
easAddress
);
// 2. RESERVE SHARES
// Founder 1: 40%
sharesTokenizer.reserveToken(
integraHash,
0,
founder1Address,
400000, // 400,000 shares
processHash
);
// Founder 2: 30%
sharesTokenizer.reserveToken(
integraHash,
0,
founder2Address,
300000,
processHash
);
// Investor: 30%
sharesTokenizer.reserveToken(
integraHash,
0,
investorAddress,
300000,
processHash
);
// Total reserved: 1,000,000 shares
// 3. CLAIM SHARES
// Each party claims with their capability attestation
sharesTokenizer.claimToken(
integraHash,
0,
founder1AttestationUID,
processHash
);
// founder1 now has 400,000 ACME tokens
sharesTokenizer.claimToken(
integraHash,
0,
founder2AttestationUID,
processHash
);
// founder2 now has 300,000 ACME tokens
sharesTokenizer.claimToken(
integraHash,
0,
investorAttestationUID,
processHash
);
// investor now has 300,000 ACME tokens
// 4. DOCUMENT COMPLETE
// All reservations claimed → trust credentials issued to all shareholders
// 5. TRANSFER SHARES
// Standard ERC-20 transfers
sharesTokenizer.transfer(buyer, 50000); // Sell 50k shares
sharesTokenizer.approve(dex, 100000); // Approve DEXState Transitions
UNRESERVED → RESERVED → CLAIMED
↓
CANCELLEDUNRESERVED: No reservation exists
- Action:
reserveToken() - Transition to: RESERVED
RESERVED: Shares reserved for recipient
- State:
reservations[recipient] = amount - State:
reservedShares += amount - Action:
claimToken()orcancelReservation() - Transition to: CLAIMED or CANCELLED
CLAIMED: Shares minted as ERC-20 tokens
- State:
totalShares += amount - State:
reservedShares -= amount - State:
claimed[recipient] = true - State: Tokens minted to recipient
- No further transitions (ERC-20 handles ownership)
CANCELLED: Reservation removed (simplified implementation)
Security Considerations
1. Duplicate Reservations
Risk: Same recipient reserved twice
Mitigation:
if (data.reservations[recipient] > 0) {
revert TokenAlreadyReserved(integraHash, tokenId);
}2. Zero Amount
Risk: Reserving zero shares
Mitigation:
if (amount == 0) revert InvalidAmount(amount);3. Claim Without Reservation
Risk: Claiming shares without prior reservation
Mitigation:
uint256 amount = data.reservations[msg.sender];
if (amount == 0) revert TokenNotReserved(integraHash, tokenId);4. Double Claiming
Risk: Same recipient claims multiple times
Mitigation:
if (data.claimed[msg.sender]) {
revert TokenAlreadyClaimed(integraHash, tokenId);
}5. Capability Attestation
Risk: Unauthorized claims
Mitigation:
requiresCapabilityWithUID(integraHash, CAPABILITY_CLAIM_TOKEN, capabilityAttestationUID)
// Verifies EAS attestation via BaseTokenizerV76. Reentrancy
Risk: Reentrancy attacks during claim/transfer
Mitigation:
nonReentrant // OpenZeppelin ReentrancyGuard7. Unlimited Supply
Risk: No cap on total shares
Note: This is by design. SharesTokenizerV7 doesn’t enforce a supply cap. Implement supply caps at the application layer or extend the contract if needed.
8. ERC-20 Standard Risks
Risk: All standard ERC-20 risks apply
- Front-running
- Approval race conditions
- Transfer hooks
Mitigation: Use standard ERC-20 best practices
Usage Examples
Basic Company Shares
// Deploy and initialize
SharesTokenizerV7 shares = new SharesTokenizerV7();
shares.initialize("MyCompany", "MYC", governor, ...);
// Reserve shares
shares.reserveToken(docHash, 0, founder, 500000, procHash);
shares.reserveToken(docHash, 0, investor, 500000, procHash);
// Claim shares
shares.claimToken(docHash, 0, founderAttestation, procHash);
shares.claimToken(docHash, 0, investorAttestation, procHash);
// Check balances
uint256 founderShares = shares.balanceOf(founder, 0); // 500,000
uint256 investorShares = shares.balanceOf(investor, 0); // 500,000
// Transfer shares
shares.transfer(buyer, 100000); // Sell 100k sharesProportional Voting
// Calculate voting power
function getVotingPower(address voter) public view returns (uint256) {
uint256 voterShares = shares.balanceOf(voter, 0);
ShareData storage data = shareData[integraHash];
uint256 totalShares = data.totalShares;
return (voterShares * 10000) / totalShares; // Basis points
}
// Example: voter has 250k of 1M total shares
// Voting power = 2500 basis points = 25%Multi-Document Portfolio
// Company A shares
bytes32 companyAHash = keccak256("Company A");
shares.reserveToken(companyAHash, 0, investor, 1000, procHash);
shares.claimToken(companyAHash, 0, attestation1, procHash);
// Company B shares
bytes32 companyBHash = keccak256("Company B");
shares.reserveToken(companyBHash, 0, investor, 2000, procHash);
shares.claimToken(companyBHash, 0, attestation2, procHash);
// Each document has separate share poolIntegration Guide
Frontend Integration
// Reserve shares for recipient
async function reserveShares(
integraHash: string,
recipient: string,
amount: number,
processHash: string
) {
const tx = await sharesTokenizer.reserveToken(
integraHash,
0, // tokenId always 0
recipient,
amount,
processHash
);
await tx.wait();
return tx.hash;
}
// Claim shares with attestation
async function claimShares(
integraHash: string,
attestationUID: string,
processHash: string
) {
const tx = await sharesTokenizer.claimToken(
integraHash,
0, // tokenId always 0
attestationUID,
processHash
);
await tx.wait();
return tx.hash;
}
// Get share info
async function getShareInfo(integraHash: string) {
const info = await sharesTokenizer.getTokenInfo(integraHash, 0);
return {
totalShares: info.totalSupply.toNumber(),
reservedShares: info.reserved.toNumber(),
shareholders: info.holders
};
}
// Get user balance
async function getUserBalance(userAddress: string) {
const balance = await sharesTokenizer.balanceOf(userAddress, 0);
return balance.toNumber();
}Backend Integration
// Listen for share reservations
sharesTokenizer.on("TokenReserved", (
integraHash,
tokenId,
recipient,
amount,
processHash,
timestamp
) => {
console.log(`Reserved ${amount} shares for ${recipient}`);
// Update database
db.reservations.create({
integraHash,
recipient,
amount,
processHash,
timestamp: new Date(timestamp * 1000)
});
});
// Listen for claims
sharesTokenizer.on("TokenClaimed", (
integraHash,
tokenId,
claimer,
attestationUID,
processHash,
timestamp
) => {
console.log(`${claimer} claimed shares`);
// Mark as claimed in database
db.reservations.update({
integraHash,
recipient: claimer
}, {
claimed: true,
claimedAt: new Date(timestamp * 1000)
});
});GraphQL Integration
type ShareDocument {
integraHash: String!
totalShares: Int!
reservedShares: Int!
shareholders: [String!]!
}
type Query {
shareDocument(integraHash: String!): ShareDocument
userShares(userAddress: String!): Int!
}Best Practices
1. Share Amount Consistency
Use consistent units across all reservations:
// GOOD: All amounts in whole shares
reserveToken(hash, 0, alice, 1000000, procHash);
reserveToken(hash, 0, bob, 500000, procHash);
// AVOID: Inconsistent units
reserveToken(hash, 0, alice, 1000000, procHash); // millions
reserveToken(hash, 0, bob, 50, procHash); // different scale?2. Total Supply Planning
Plan total supply upfront:
// GOOD: Clear total supply plan
uint256 totalSupply = 10000000; // 10M shares
reserveToken(hash, 0, founder1, totalSupply * 40 / 100, procHash); // 40%
reserveToken(hash, 0, founder2, totalSupply * 30 / 100, procHash); // 30%
reserveToken(hash, 0, investor, totalSupply * 30 / 100, procHash); // 30%
// AVOID: Ad-hoc amounts without planning
reserveToken(hash, 0, founder1, 12345, procHash);
reserveToken(hash, 0, founder2, 67890, procHash);3. Shareholder Tracking
Track shareholders for governance:
// Get all shareholders
TokenInfo memory info = sharesTokenizer.getTokenInfo(integraHash, 0);
address[] memory shareholders = info.holders;
// Iterate for voting
for (uint i = 0; i < shareholders.length; i++) {
uint256 votes = sharesTokenizer.balanceOf(shareholders[i], 0);
// Process vote
}4. Process Hash Correlation
Use consistent process hashes:
// GOOD: Use same process hash for related operations
bytes32 procHash = keccak256(abi.encodePacked("cap-raise-2024", block.timestamp));
reserveToken(hash, 0, investor1, 100, procHash);
reserveToken(hash, 0, investor2, 200, procHash);
// AVOID: Random process hashes
reserveToken(hash, 0, investor1, 100, keccak256("random1"));
reserveToken(hash, 0, investor2, 200, keccak256("random2"));5. Capability Attestations
Ensure valid attestations before claiming:
// GOOD: Verify attestation exists and is valid
bytes32 attestationUID = await getValidAttestation(claimer, integraHash);
await sharesTokenizer.claimToken(integraHash, 0, attestationUID, procHash);
// AVOID: Using invalid or expired attestations6. Event Monitoring
Monitor all events for audit trail:
// Monitor reservation and claim events
// Store in database for compliance
// Generate reports for shareholders7. Transfer Restrictions
If needed, implement transfer restrictions:
// Option 1: Extend SharesTokenizerV7
contract RestrictedShares is SharesTokenizerV7 {
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal override
{
require(isAccredited[to], "Recipient not accredited");
super._beforeTokenTransfer(from, to, amount);
}
}
// Option 2: Use SecurityTokenTokenizerV7 instead
// It has built-in compliance featuresGas Optimization
Claim Gas Costs
Typical Claim: ~100,000 gas
Breakdown:
- ERC-20 mint: ~50,000 gas
- Storage updates: ~30,000 gas
- Event emission: ~10,000 gas
- Trust credential: ~10,000 gas
Batch Operations
Pattern: Reserve multiple parties in single transaction
// OFF-CHAIN: Batch multiple reservations
function batchReserve(
bytes32 integraHash,
address[] memory recipients,
uint256[] memory amounts,
bytes32 processHash
) external requireOwnerOrExecutor(integraHash) {
for (uint i = 0; i < recipients.length; i++) {
reserveToken(integraHash, 0, recipients[i], amounts[i], processHash);
}
}Savings: ~21,000 gas per additional recipient (vs separate txs)
View Function Optimization
// Efficient: Single call
TokenInfo memory info = getTokenInfo(integraHash, 0);
// Less efficient: Multiple calls
uint256 total = info.totalSupply;
uint256 reserved = info.reserved;
address[] memory holders = info.holders;Related Contracts
Base Contracts
-
BaseTokenizerV7: Shared tokenizer functionality
- Access control (owner, executor, governor)
- Capability verification
- Process hash validation
- Document registry integration
-
TrustGraphIntegration: Reputation system
- Trust credential issuance
- Document completion detection
- EAS integration
Token Standard
- ERC20Upgradeable: OpenZeppelin implementation
- Standard fungible token
- Transfer, approve, allowance
- Minting capabilities
Interfaces
- IDocumentTokenizerV7: Standard tokenizer interface
reserveToken(),claimToken(),cancelReservation()getTokenInfo(),balanceOf(),tokenType()
Related Tokenizers
- SecurityTokenTokenizerV7: Similar ERC-20 but with compliance features
- RoyaltyTokenizerV7: Use for revenue splits (basis points model)
- MultiPartyTokenizerV7: Use for distinct roles (not fungible shares)
Upgradeability
Pattern: UUPS (Universal Upgradeable Proxy Standard)
Upgrade Process:
// Deploy new implementation
SharesTokenizerV7 newImpl = new SharesTokenizerV7();
// Upgrade via governor
sharesTokenizer.upgradeTo(address(newImpl));Storage Layout:
// State variables
mapping(bytes32 => ShareData) private shareData; // Slot 0
IEAS private eas; // Slot 1
// Storage gap for future upgrades
uint256[49] private __gap; // 50 - 1 = 49 slotsUpgrade Safety:
- Never remove or reorder existing state variables
- Only append new variables
- Maintain storage gap
- Test upgrades on testnet first
Comparison with Similar Tokenizers
SharesTokenizerV7 vs SecurityTokenTokenizerV7
| Feature | SharesTokenizerV7 | SecurityTokenTokenizerV7 |
|---|---|---|
| Token Standard | ERC-20 | ERC-20 |
| Transfer Restrictions | No | Yes (attestation-based) |
| Compliance | Basic | Regulatory |
| Use Case | General shares | Regulated securities |
| Trust Graph | Yes | Yes |
When to use:
- Shares: General partnerships, cooperatives, unrestricted equity
- Security: SEC-regulated securities, accredited investors only
SharesTokenizerV7 vs RoyaltyTokenizerV7
| Feature | SharesTokenizerV7 | RoyaltyTokenizerV7 |
|---|---|---|
| Token Standard | ERC-20 | ERC-1155 |
| Fungibility | Fully fungible | Semi-fungible |
| Use Case | Ownership shares | Revenue splits |
| Allocation | Unlimited | Must total 10,000 |
| Token IDs | No (single pool) | Yes (per stakeholder) |
When to use:
- Shares: Ownership representation, voting rights
- Royalty: Revenue distribution, percentage-based payments
Limitations
1. No Anonymous Reservations
ERC-20 doesn’t support encrypted labels:
// NOT SUPPORTED
reserveTokenAnonymous(integraHash, 0, amount, encryptedLabel, procHash);
// Reverts: "Use reserveToken for ERC-20 shares"Workaround: Use MultiPartyTokenizerV7 if anonymous reservations needed
2. No Supply Cap
No built-in maximum supply:
// Can reserve unlimited shares
reserveToken(hash, 0, alice, 1000000000000, procHash); // No capWorkaround: Implement cap in application layer or extend contract
3. Single Pool Per Document
All shares in one fungible pool:
// Cannot differentiate share classes (common vs preferred)
// Use separate documents or extend contract for share classesWorkaround: Deploy separate tokenizer per share class
4. Cancellation Complexity
Simplified cancellation requires recipient address:
// Not fully implemented
cancelReservation(integraHash, 0, procHash); // RevertsWorkaround: Implement specific cancellation function with recipient parameter
FAQ
Q: Can I use SharesTokenizerV7 for company stock? A: Yes, but ensure compliance with securities regulations. For regulated securities, consider SecurityTokenTokenizerV7.
Q: How do I handle different share classes (common/preferred)? A: Deploy separate SharesTokenizerV7 instances for each share class, or extend the contract.
Q: Can shareholders vote with their tokens? A: Not built-in. Implement governance contract that reads balances.
Q: What happens if someone loses their wallet? A: Shares are tied to the address. Implement recovery mechanisms at application layer.
Q: Can I restrict transfers?
A: Not built-in. Override _beforeTokenTransfer or use SecurityTokenTokenizerV7.
Q: How do I distribute dividends? A: Off-chain or via separate dividend distribution contract that reads balances.
Q: Can I use this with DeFi protocols? A: Yes, it’s standard ERC-20. Works with DEXs, lending protocols, etc.
Q: What’s the difference vs RoyaltyTokenizerV7? A: Shares = ownership tokens, Royalty = revenue split tokens (10,000 total).
Further Reading
- SecurityTokenTokenizerV7 - Compliant alternative
- RoyaltyTokenizerV7 - Revenue splits
- Tokenizer Comparison Guide - Choose the right tokenizer