tutus-chain/docs/ADR-008-UI-Implementation-G...

225 lines
7.7 KiB
Markdown

# ADR-008 UI Implementation Guide
This document provides guidance for front-end developers implementing UI for the ADR-008 security features.
## 1. Commit-Reveal Investment System
### Overview
Investments now use a two-phase commit-reveal pattern to prevent front-running attacks. Users must first commit a hash of their investment, wait for a delay period, then reveal the actual amount.
### Flow
```
1. User decides to invest amount X in opportunity Y
2. Frontend generates random nonce (32 bytes)
3. Frontend computes commitment = SHA256(amount || nonce || investorAddress)
4. User calls commitInvestment(opportunityID, commitment, vitaID)
5. Wait 10+ blocks (configurable: CommitRevealDelay)
6. User calls revealInvestment(commitmentID, amount, nonce)
7. If valid, investment is executed
```
### Contract Methods
#### `commitInvestment(opportunityID: uint64, commitment: bytes32, vitaID: uint64) -> uint64`
- Returns: commitmentID
- Event: `CommitmentCreated(commitmentID, opportunityID, vitaID, revealDeadline)`
#### `revealInvestment(commitmentID: uint64, amount: uint64, nonce: bytes) -> bool`
- Must be called after CommitRevealDelay blocks (default: 10)
- Must be called before CommitRevealWindow expires (default: 1000 blocks)
- Event: `CommitmentRevealed(commitmentID, amount, investmentID)`
#### `cancelCommitment(commitmentID: uint64) -> bool`
- Can cancel pending commitments
- Event: `CommitmentCanceled(commitmentID)`
#### `getCommitment(commitmentID: uint64) -> CommitmentInfo | null`
- Returns commitment details including status
### Frontend Implementation Notes
```typescript
// Generate commitment
function createCommitment(amount: bigint, investorAddress: string): { commitment: string, nonce: string } {
const nonce = crypto.randomBytes(32);
const preimage = Buffer.concat([
Buffer.alloc(8), // amount as uint64 big-endian
nonce,
Buffer.from(investorAddress, 'hex')
]);
// Write amount as big-endian uint64
preimage.writeBigUInt64BE(amount, 0);
const commitment = sha256(preimage);
return {
commitment: commitment.toString('hex'),
nonce: nonce.toString('hex')
};
}
// IMPORTANT: Store nonce securely until reveal!
// If user loses nonce, they cannot reveal and funds are locked until expiry
```
### UI Considerations
- **Nonce Storage**: Store nonce in localStorage/sessionStorage with commitmentID as key
- **Progress Indicator**: Show blocks remaining until reveal is allowed
- **Deadline Warning**: Alert user if reveal deadline is approaching
- **Retry Logic**: If reveal fails, nonce is still valid for retry
---
## 2. Whale Concentration Limits
### Overview
No single investor can hold more than 5% (configurable) of any investment opportunity's total pool.
### How It Works
- When `invest()` is called, the contract checks:
```
(existingInvestment + newAmount) / (totalPool + newAmount) <= WealthConcentration
```
- Default limit: 500 basis points (5%)
- Enforced at investment time, not at commitment time
### UI Considerations
- **Pre-check**: Before committing, query user's existing investment in opportunity
- **Warning**: Show warning if user is approaching concentration limit
- **Error Handling**: Handle "investment would exceed whale concentration limit" error gracefully
### Querying Current Investment
```typescript
// Get all investments by an investor
const investments = await contract.getInvestmentsByInvestor(vitaID);
const investmentInOpp = investments.find(inv => inv.opportunityID === targetOppID);
const currentAmount = investmentInOpp?.amount || 0n;
// Get opportunity details
const opp = await contract.getOpportunity(oppID);
const totalPool = opp.totalPool;
// Calculate max additional investment
const maxConcentration = config.wealthConcentration; // e.g., 500 = 5%
const maxAllowed = (totalPool * BigInt(maxConcentration)) / 10000n;
const maxAdditional = maxAllowed - currentAmount;
```
---
## 3. Sybil Resistance Vesting
### Overview
New Vita tokens have a 30-day vesting period before gaining full rights. This prevents mass creation of fake identities for manipulation.
### Default Vesting Period
- 2,592,000 blocks (~30 days at 1 second per block)
- Committee can adjust vesting for individual tokens
### Contract Methods
#### `isFullyVested(tokenID: uint64) -> bool`
- Returns true if current block >= vestedUntil
#### `getVestingInfo(tokenID: uint64) -> [vestedUntil, isFullyVested, remainingBlocks] | null`
- `vestedUntil`: Block height when vesting completes
- `isFullyVested`: Current vesting status
- `remainingBlocks`: Blocks until fully vested (0 if already vested)
#### `setVesting(tokenID: uint64, vestedUntil: uint32) -> bool` (Committee only)
- Can accelerate vesting for verified identities
- Can extend vesting for suspicious accounts
### UI Considerations
#### Registration Flow
```typescript
// After Vita registration, show vesting status
const vestingInfo = await vita.getVestingInfo(tokenID);
if (!vestingInfo[1]) { // not fully vested
const remainingBlocks = vestingInfo[2];
const estimatedTime = remainingBlocks * 1; // 1 second per block
showVestingBanner(`Your identity will be fully verified in ~${formatDuration(estimatedTime)}`);
}
```
#### Feature Gating
Some features may require fully vested Vita:
- **Voting**: May require full vesting to prevent vote manipulation
- **Large Investments**: Higher limits may require vesting
- **Attestation**: May need vesting to attest others
```typescript
// Check before allowing sensitive actions
async function canPerformAction(vitaID: uint64, action: string): Promise<boolean> {
const isVested = await vita.isFullyVested(vitaID);
switch(action) {
case 'vote':
case 'large_investment':
case 'attest_others':
return isVested;
default:
return true; // Basic actions allowed during vesting
}
}
```
#### Vesting Progress Display
```typescript
// Calculate and display vesting progress
const vestingInfo = await vita.getVestingInfo(tokenID);
const vestedUntil = vestingInfo[0];
const token = await vita.getTokenByID(tokenID);
const createdAt = token.createdAt;
const totalVestingBlocks = vestedUntil - createdAt;
const elapsedBlocks = currentBlock - createdAt;
const progressPercent = Math.min(100, (elapsedBlocks / totalVestingBlocks) * 100);
```
---
## Configuration Values
These can be queried from the contracts:
### Collocatio Config
```typescript
const config = await collocatio.getConfig();
// config.commitRevealDelay = 10 (blocks)
// config.commitRevealWindow = 1000 (blocks)
// config.wealthConcentration = 500 (basis points = 5%)
```
### Vita Vesting
```typescript
// Default vesting period: 2,592,000 blocks (~30 days)
// Query individual token vesting via getVestingInfo()
```
---
## Events to Subscribe
### Collocatio Events
- `CommitmentCreated(commitmentID, opportunityID, vitaID, revealDeadline)`
- `CommitmentRevealed(commitmentID, amount, investmentID)`
- `CommitmentCanceled(commitmentID)`
### Vita Events
- `VestingUpdated(tokenID, vestedUntil, updatedBy)`
---
## Error Messages
| Error | Meaning | UI Action |
|-------|---------|-----------|
| `commitment already exists` | Duplicate commitment | Show existing commitment |
| `commitment not found` | Invalid commitmentID | Check ID is correct |
| `reveal too early` | Before delay period | Show countdown |
| `reveal window expired` | Past deadline | Commitment forfeited |
| `commitment verification failed` | Wrong amount/nonce | Check stored values |
| `investment would exceed whale concentration limit` | Too much in one opp | Show max allowed |
| `vita is not fully vested` | Vesting incomplete | Show remaining time |