# Extending Locks

Comprehensive guide to extending lock durations, adding liquidity, and managing long-term locked positions.

## Overview

RealSafe allows lock owners to extend their lock duration anytime, providing flexibility for long-term liquidity commitment strategies. This guide covers all aspects of lock extension and management.

## Table of Contents

1. [Basic Lock Extension](#basic-lock-extension)
2. [Adding to V2 Locks](#adding-to-v2-locks)
3. [Advanced Strategies](#advanced-strategies)
4. [Use Cases](#use-cases)
5. [Best Practices](#best-practices)
6. [Gas Optimization](#gas-optimization)

***

## Basic Lock Extension

### Extending V3 Locks

V3 locks can have their unlock date extended anytime before unlocking.

```solidity
/**
 * @dev Extends a V3 lock duration
 */
function extendLock(
    uint256 lockId,
    uint256 newUnlockDate
) external
```

**Requirements:**

* Must be lock owner
* Lock must be active
* `newUnlockDate` > current unlock date
* `newUnlockDate` <= current time + 10 years

**Example:**

```solidity
// Get current lock details
Lock memory lock = v3Locker.getLock(myLockId);

// Extend by 90 days
uint256 newUnlockDate = lock.unlockDate + 90 days;

// Execute extension
v3Locker.extendLock(myLockId, newUnlockDate);
```

### Extending V2 Locks

V2 locks work the same way as V3 locks for extension.

```solidity
// Get current unlock time
(, , , uint256 currentUnlockTime, , , ) = v2Locker.locks(myLockId);

// Extend by 6 months
uint256 newUnlockDate = currentUnlockTime + 180 days;

// Execute extension
v2Locker.extendLock(myLockId, newUnlockDate);
```

### Events

Both V2 and V3 emit similar events:

```solidity
event LockExtended(
    address indexed owner,
    uint256 indexed lockId,
    uint256 oldUnlockTime,
    uint256 newUnlockTime
);
```

***

## Adding to V2 Locks

V2 Locker allows adding more LP tokens to existing locks without creating a new lock.

### addToLock Function

```solidity
function addToLock(
    uint256 lockId,
    uint256 amount
) external
```

**Requirements:**

* Must be lock owner
* Lock must be active
* Amount must be > 0
* Must have approved additional tokens

**Example:**

```solidity
// Original lock: 1000 LP tokens
// Want to add: 500 more LP tokens

// 1. Approve additional tokens
IERC20(lpToken).approve(v2LockerAddress, 500 * 1e18);

// 2. Add to existing lock
v2Locker.addToLock(myLockId, 500 * 1e18);

// Now total: 1500 LP tokens locked
```

**Why Add Instead of Creating New Lock?**

* **Gas Savings**: Cheaper than creating new lock
* **Simpler Management**: One lock ID instead of multiple
* **Better UX**: Easier to track and unlock
* **Same Unlock Date**: All tokens unlock together

### Events

```solidity
event LockIncreased(
    address indexed owner,
    uint256 indexed lockId,
    uint256 addedAmount,
    uint256 newTotalAmount
);
```

***

## Advanced Strategies

### Strategy 1: Progressive Extension

Gradually extend lock duration over time to maintain commitment.

```solidity
contract ProgressiveExtension {
    V3Locker public v3Locker;
    
    struct ExtensionSchedule {
        uint256 lockId;
        uint256[] extensionDates;
        uint256[] extensionDurations;
        uint256 nextIndex;
    }
    
    mapping(address => ExtensionSchedule) public schedules;
    
    /**
     * @dev Create an extension schedule
     * Example: Extend by 30 days every 3 months
     */
    function createSchedule(
        uint256 lockId,
        uint256[] calldata intervals,
        uint256[] calldata durations
    ) external {
        require(intervals.length == durations.length, "Length mismatch");
        
        schedules[msg.sender] = ExtensionSchedule({
            lockId: lockId,
            extensionDates: intervals,
            extensionDurations: durations,
            nextIndex: 0
        });
    }
    
    /**
     * @dev Execute next scheduled extension
     */
    function executeNextExtension() external {
        ExtensionSchedule storage schedule = schedules[msg.sender];
        require(schedule.nextIndex < schedule.extensionDates.length, "No more extensions");
        
        uint256 extensionDate = schedule.extensionDates[schedule.nextIndex];
        require(block.timestamp >= extensionDate, "Too early");
        
        Lock memory lock = v3Locker.getLock(schedule.lockId);
        uint256 duration = schedule.extensionDurations[schedule.nextIndex];
        uint256 newUnlockDate = lock.unlockDate + duration;
        
        v3Locker.extendLock(schedule.lockId, newUnlockDate);
        
        schedule.nextIndex++;
    }
}
```

**Usage:**

```solidity
// Extend by 30 days every 90 days, 4 times
uint256[] memory intervals = new uint256[](4);
intervals[0] = block.timestamp + 90 days;
intervals[1] = block.timestamp + 180 days;
intervals[2] = block.timestamp + 270 days;
intervals[3] = block.timestamp + 360 days;

uint256[] memory durations = new uint256[](4);
durations[0] = 30 days;
durations[1] = 30 days;
durations[2] = 30 days;
durations[3] = 30 days;

progressiveExtension.createSchedule(myLockId, intervals, durations);
```

***

### Strategy 2: Conditional Extension

Automatically extend based on conditions.

```solidity
contract ConditionalExtension {
    V3Locker public v3Locker;
    
    struct ConditionalRule {
        uint256 lockId;
        address priceOracle;
        int256 priceThreshold;
        uint256 extensionDuration;
    }
    
    mapping(address => ConditionalRule) public rules;
    
    /**
     * @dev Set rule: If ETH > $4000, extend by 90 days
     */
    function setRule(
        uint256 lockId,
        address priceOracle,
        int256 priceThreshold,
        uint256 extensionDuration
    ) external {
        rules[msg.sender] = ConditionalRule({
            lockId: lockId,
            priceOracle: priceOracle,
            priceThreshold: priceThreshold,
            extensionDuration: extensionDuration
        });
    }
    
    /**
     * @dev Check and extend if condition met
     */
    function checkAndExtend() external {
        ConditionalRule memory rule = rules[msg.sender];
        
        (, int256 price, , , ) = AggregatorV3Interface(rule.priceOracle)
            .latestRoundData();
        
        if (price >= rule.priceThreshold) {
            Lock memory lock = v3Locker.getLock(rule.lockId);
            uint256 newUnlockDate = lock.unlockDate + rule.extensionDuration;
            
            v3Locker.extendLock(rule.lockId, newUnlockDate);
        }
    }
}
```

***

### Strategy 3: DAO-Controlled Extension

Let DAO vote on lock extensions.

```solidity
contract DAOExtension {
    V3Locker public v3Locker;
    
    struct ExtensionProposal {
        uint256 lockId;
        uint256 newUnlockDate;
        uint256 votesFor;
        uint256 votesAgainst;
        bool executed;
        mapping(address => bool) hasVoted;
    }
    
    mapping(uint256 => ExtensionProposal) public proposals;
    uint256 public nextProposalId;
    
    uint256 public constant QUORUM = 100;  // 100 votes needed
    
    /**
     * @dev Create extension proposal
     */
    function propose(uint256 lockId, uint256 newUnlockDate) external returns (uint256) {
        uint256 proposalId = nextProposalId++;
        ExtensionProposal storage proposal = proposals[proposalId];
        
        proposal.lockId = lockId;
        proposal.newUnlockDate = newUnlockDate;
        
        return proposalId;
    }
    
    /**
     * @dev Vote on proposal
     */
    function vote(uint256 proposalId, bool support) external {
        ExtensionProposal storage proposal = proposals[proposalId];
        require(!proposal.executed, "Already executed");
        require(!proposal.hasVoted[msg.sender], "Already voted");
        
        if (support) {
            proposal.votesFor++;
        } else {
            proposal.votesAgainst++;
        }
        
        proposal.hasVoted[msg.sender] = true;
    }
    
    /**
     * @dev Execute passed proposal
     */
    function execute(uint256 proposalId) external {
        ExtensionProposal storage proposal = proposals[proposalId];
        require(!proposal.executed, "Already executed");
        
        uint256 totalVotes = proposal.votesFor + proposal.votesAgainst;
        require(totalVotes >= QUORUM, "Quorum not reached");
        require(proposal.votesFor > proposal.votesAgainst, "Proposal defeated");
        
        v3Locker.extendLock(proposal.lockId, proposal.newUnlockDate);
        proposal.executed = true;
    }
}
```

***

### Strategy 4: Staggered Unlocks

Split liquidity into multiple locks with different unlock dates.

```solidity
contract StaggeredLocks {
    V2Locker public v2Locker;
    
    /**
     * @dev Create multiple locks with staggered unlock dates
     */
    function createStaggeredLocks(
        address lpToken,
        uint256 totalAmount,
        uint256 numberOfLocks,
        uint256 intervalDays
    ) external payable {
        uint256 amountPerLock = totalAmount / numberOfLocks;
        uint256 creationFee = v2Locker.creationFee();
        
        require(msg.value >= creationFee * numberOfLocks, "Insufficient fee");
        
        IERC20(lpToken).approve(address(v2Locker), totalAmount);
        
        for (uint i = 0; i < numberOfLocks; i++) {
            uint256 unlockTime = block.timestamp + (intervalDays * (i + 1) * 1 days);
            
            v2Locker.lockLP{value: creationFee}(
                lpToken,
                amountPerLock,
                unlockTime,
                false,
                address(0)
            );
        }
    }
}
```

**Example:**

```solidity
// Lock 10,000 LP tokens
// Split into 4 locks
// Unlock every 90 days

staggeredLocks.createStaggeredLocks{value: 0.0004 ether}(
    lpTokenAddress,
    10000 * 1e18,  // Total amount
    4,             // Number of locks
    90             // Days between unlocks
);

// Results in:
// Lock 1: 2,500 tokens, unlocks in 90 days
// Lock 2: 2,500 tokens, unlocks in 180 days
// Lock 3: 2,500 tokens, unlocks in 270 days
// Lock 4: 2,500 tokens, unlocks in 360 days
```

***

## Use Cases

### 1. Long-Term Project Commitment

**Scenario**: Project wants to show long-term commitment but maintain flexibility.

**Solution**:

```solidity
// Initial lock: 1 year
lockPosition(tokenId, block.timestamp + 365 days, ...);

// After 6 months, extend by another year
extendLock(lockId, block.timestamp + 365 days + 180 days);

// Keep extending to show continued commitment
```

***

### 2. Yield Farming Strategy

**Scenario**: Want to keep farming rewards while maintaining locked liquidity.

**Solution**:

```solidity
// Lock V3 position for 90 days
uint256 lockId = v3Locker.lockPosition{value: fee}(...);

// Collect trading fees monthly while locked
for (uint i = 0; i < 3; i++) {
    // Wait 30 days
    vm.warp(block.timestamp + 30 days);
    
    // Claim fees
    v3Locker.claimFees(lockId, type(uint128).max, type(uint128).max);
}

// Decide to extend based on yields
if (yieldsAreGood) {
    extendLock(lockId, block.timestamp + 90 days);
}
```

***

### 3. Vesting Schedule

**Scenario**: Team wants progressive liquidity unlocking.

**Solution**:

```solidity
// Create 4 locks for team allocation
// 25% unlock every 6 months
uint256 teamAllocation = 1000000 * 1e18;

for (uint i = 0; i < 4; i++) {
    uint256 amount = teamAllocation / 4;
    uint256 unlockTime = block.timestamp + ((i + 1) * 180 days);
    
    v2Locker.lockLP{value: fee}(lpToken, amount, unlockTime, false, address(0));
}
```

***

### 4. Building Trust with Community

**Scenario**: New project wants to build trust by demonstrating long-term liquidity commitment.

**Timeline**:

1. **Launch**: Lock 100% of initial liquidity for 30 days
2. **After 2 weeks**: Extend to 90 days (shows commitment)
3. **After 1 month**: Extend to 6 months (building confidence)
4. **After 3 months**: Extend to 1 year (long-term commitment proven)

```solidity
// Launch
uint256 lockId = v3Locker.lockPosition{value: fee}(
    tokenId,
    block.timestamp + 30 days,
    treasury,
    address(0)
);

// Week 2: Extend to 90 days
v3Locker.extendLock(lockId, block.timestamp + 90 days);

// Month 1: Extend to 6 months
v3Locker.extendLock(lockId, block.timestamp + 180 days);

// Month 3: Extend to 1 year
v3Locker.extendLock(lockId, block.timestamp + 365 days);
```

***

## Best Practices

### 1. Plan Extensions in Advance

```solidity
// Document your extension strategy
struct ExtensionPlan {
    uint256 lockId;
    uint256[] milestones;    // When to extend
    uint256[] durations;     // How much to extend
    string reasoning;        // Why this schedule
}

// Review quarterly
function reviewExtensionPlan() external onlyOwner {
    // Check market conditions
    // Check project performance
    // Decide on next extension
}
```

***

### 2. Communicate Extensions to Community

```solidity
event LockExtensionPlanned(
    uint256 indexed lockId,
    uint256 currentUnlockTime,
    uint256 newUnlockTime,
    string reason
);

function announceExtension(
    uint256 lockId,
    uint256 newUnlockTime,
    string calldata reason
) external {
    emit LockExtensionPlanned(lockId, lock.unlockDate, newUnlockTime, reason);
    
    // Then execute
    v3Locker.extendLock(lockId, newUnlockTime);
}
```

### 3. Monitor Gas Costs

```solidity
// Batch multiple operations to save gas
function batchExtend(uint256[] calldata lockIds, uint256[] calldata newDates) external {
    require(lockIds.length == newDates.length, "Length mismatch");
    
    for (uint i = 0; i < lockIds.length; i++) {
        v3Locker.extendLock(lockIds[i], newDates[i]);
    }
}
```

***

### 4. Set Maximum Extension Limits

```solidity
// For governance/safety
uint256 public constant MAX_EXTENSION = 365 days;

function safeExtend(uint256 lockId) external {
    Lock memory lock = v3Locker.getLock(lockId);
    uint256 newUnlockDate = lock.unlockDate + MAX_EXTENSION;
    
    require(newUnlockDate <= block.timestamp + 10 years, "Too far");
    
    v3Locker.extendLock(lockId, newUnlockDate);
}
```

***

## Gas Optimization

### Estimated Gas Costs

| Operation      | V2 Locker     | V3 Locker    |
| -------------- | ------------- | ------------ |
| `extendLock()` | \~50,000 gas  | \~50,000 gas |
| `addToLock()`  | \~100,000 gas | N/A          |

### Optimization Tips

1. **Batch Operations**: Extend multiple locks in one transaction
2. **Optimal Timing**: Extend during low gas periods
3. **Combine Operations**: Add to lock + extend together (V2)

```solidity
// Optimized: Add and extend in one transaction
function addAndExtend(
    uint256 lockId,
    uint256 additionalAmount,
    uint256 newUnlockDate
) external {
    // Add tokens
    IERC20(lpToken).approve(address(v2Locker), additionalAmount);
    v2Locker.addToLock(lockId, additionalAmount);
    
    // Extend lock
    v2Locker.extendLock(lockId, newUnlockDate);
}
```

***

## Monitoring Extensions

### Track Extension History

```solidity
contract ExtensionTracker {
    struct ExtensionRecord {
        uint256 timestamp;
        uint256 oldUnlockDate;
        uint256 newUnlockDate;
        address extender;
    }
    
    mapping(uint256 => ExtensionRecord[]) public history;
    
    function recordExtension(
        uint256 lockId,
        uint256 oldDate,
        uint256 newDate
    ) external {
        history[lockId].push(ExtensionRecord({
            timestamp: block.timestamp,
            oldUnlockDate: oldDate,
            newUnlockDate: newDate,
            extender: msg.sender
        }));
    }
    
    function getExtensionHistory(uint256 lockId) 
        external 
        view 
        returns (ExtensionRecord[] memory) 
    {
        return history[lockId];
    }
}
```

***

## Related Documentation

* [V3 Locker Interface](https://docs.realsafe.app/interfaces/v3)
* [V2 Locker Interface](https://docs.realsafe.app/interfaces/v2)
* [Conditional Unlocks](https://docs.realsafe.app/advanced/conditional-unlocks)
* [Security Guide](https://docs.realsafe.app/reference/security)
* [Quick Start Guide](https://docs.realsafe.app/developer-documentation/quickstart)
