# Quickstart

Get up and running with RealSafe in minutes. This guide covers basic setup, deployment, and usage for both V2 and V3 lockers.

## Prerequisites

### Required Tools

```bash
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup

# Verify installation
forge --version
cast --version
```

### Environment Setup

Create a `.env` file in the `contracts/` directory:

```bash
# Private key (without 0x prefix)
PRIVATE_KEY=your_private_key_here

# RPC URLs
MONAD_TESTNET_RPC=https://testnet-rpc.monad.xyz

# Block explorers (optional)
MONAD_EXPLORER_API_KEY=your_api_key
```

## Installation

```bash
# Clone the repository
git clone https://github.com/realsafe/locker.git
cd locker/contracts

# Install dependencies
forge install

# Build contracts
forge build
```

## Deployment

### Deploy on Monad Testnet

```bash
# Deploy contracts
forge script script/DeployMonad.s.sol \
  --rpc-url monad_testnet \
  --broadcast

# Output will show deployment details
```

## Usage Examples

### Example 1: Lock a V3 Position

#### Step 1: Create a Pool and Position

```bash
# Deploy test tokens
forge script script/DeployTwoTokens.s.sol \
  --rpc-url monad_testnet \
  --broadcast

# Create pool and mint position
forge script script/CreatePool.s.sol \
  --rpc-url monad_testnet \
  --broadcast
```

#### Step 2: Lock the Position

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "forge-std/Script.sol";
import {V3Locker} from "../src/V3Locker.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

contract LockMyPosition is Script {
    address constant V3_LOCKER = 0x0b4619Ed28429a392C79aed87E6572F34ab6199e;
    address constant POSITION_MANAGER = 0x46A15B0b27311cedF172AB29E4f4766fbE7F4364;
    
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        
        // Your NFT token ID
        uint256 myTokenId = 83;
        
        // Lock for 30 days
        uint256 unlockTime = block.timestamp + 30 days;
        
        vm.startBroadcast(deployerPrivateKey);
        
        // Approve NFT
        IERC721(POSITION_MANAGER).approve(V3_LOCKER, myTokenId);
        
        // Lock position
        uint256 creationFee = V3Locker(V3_LOCKER).creationFee();
        V3Locker(V3_LOCKER).lockPosition{value: creationFee}(
            myTokenId,
            unlockTime,
            msg.sender,  // collect address
            address(0)   // no condition
        );
        
        vm.stopBroadcast();
        
        console.log("Position locked successfully!");
    }
}
```

Run the script:

```bash
forge script script/LockMyPosition.s.sol \
  --rpc-url monad_testnet \
  --broadcast
```

### Example 2: Lock V2 LP Tokens

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "forge-std/Script.sol";
import {V2Locker} from "../src/V2Locker.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract LockLPTokens is Script {
    address constant V2_LOCKER = 0x527713F26D0769E5EaE5A77b530511025fB4FDe7;
    
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        
        // Your LP token details
        address lpToken = 0x324cc0b7E34882A41aFdf1a623529E6ce6BA9623;
        uint256 amount = 1000 * 1e18; // 1000 LP tokens
        
        // Lock for 90 days
        uint256 unlockTime = block.timestamp + 90 days;
        
        vm.startBroadcast(deployerPrivateKey);
        
        // Approve LP tokens
        IERC20(lpToken).approve(V2_LOCKER, amount);
        
        // Lock tokens
        uint256 creationFee = V2Locker(V2_LOCKER).creationFee();
        V2Locker(V2_LOCKER).lockLP{value: creationFee}(
            lpToken,
            amount,
            unlockTime,
            false,       // not permanent
            address(0)   // no condition
        );
        
        vm.stopBroadcast();
        
        console.log("LP tokens locked successfully!");
    }
}
```

### Example 3: Claim Fees from Locked V3 Position

> **Note**: This only applies to V3 positions. V2 LP tokens don't have a separate fee claiming function because trading fees automatically accrue to the LP token's value. You receive all accrued fees when you unlock your V2 LP tokens.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "forge-std/Script.sol";
import {V3Locker} from "../src/V3Locker.sol";

contract ClaimFeesFromLock is Script {
    address constant V3_LOCKER = 0x0b4619Ed28429a392C79aed87E6572F34ab6199e;
    
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        
        // Your lock ID
        uint256 myLockId = 0;
        
        vm.startBroadcast(deployerPrivateKey);
        
        // Claim all available fees (V3 only)
        V3Locker(V3_LOCKER).claimFees(
            myLockId,
            type(uint128).max,  // max token0
            type(uint128).max   // max token1
        );
        
        vm.stopBroadcast();
        
        console.log("Fees claimed successfully!");
    }
}
```

## Using Cast (Command Line)

### Get Your Lock IDs

```bash
# Get all your lock IDs
cast call 0x0b4619Ed28429a392C79aed87E6572F34ab6199e \
  "getOwnerLockIds(address)" \
  YOUR_ADDRESS \
  --rpc-url monad_testnet
```

### Check Lock Details

```bash
# Get specific lock details
cast call 0x0b4619Ed28429a392C79aed87E6572F34ab6199e \
  "getLock(uint256)" \
  0 \
  --rpc-url monad_testnet
```

### Check if You Can Unlock

```bash
# Check unlock status
cast call 0x0b4619Ed28429a392C79aed87E6572F34ab6199e \
  "canUnlock(uint256)" \
  0 \
  --rpc-url monad_testnet
```

### Unlock Your Position

```bash
# Unlock when ready
cast send 0x0b4619Ed28429a392C79aed87E6572F34ab6199e \
  "withdraw(uint256,address)" \
  0 \
  YOUR_ADDRESS \
  --private-key $PRIVATE_KEY \
  --rpc-url monad_testnet
```

## Testing

### Run All Tests

```bash
# Run full test suite
forge test

# Run with gas reporting
forge test --gas-report

# Run specific test
forge test --match-test testLockPosition -vvv
```

### Test V3 Locker

```bash
forge test --match-contract V3LockerTest -vvv
```

### Test V2 Locker

```bash
forge test --match-contract V2LockerTest -vvv
```

## Verification

### Verify on Monad Explorer

```bash
# Verify V3 Locker
forge verify-contract \
  0x0b4619Ed28429a392C79aed87E6572F34ab6199e \
  src/V3Locker.sol:V3Locker \
  --chain-id 84532 \
  --constructor-args $(cast abi-encode "constructor(address,address,address,uint256,uint256,uint256)" \
    0x46A15B0b27311cedF172AB29E4f4766fbE7F4364 \
    0x735c60c7FA167a8F69Ae631CD7d020942d9923B6 \
    0x735c60c7FA167a8F69Ae631CD7d020942d9923B6 \
    100000000000000 \
    100 \
    100)
```

## Common Issues & Solutions

### Issue: "Insufficient Creation Fee"

**Solution**: Check the current creation fee:

```bash
cast call V3_LOCKER_ADDRESS "creationFee()" --rpc-url base_sepolia
```

Send the correct amount with `--value` flag.

### Issue: "NFT Transfer Failed"

**Solution**: Approve the NFT first:

```bash
cast send POSITION_MANAGER \
  "approve(address,uint256)" \
  V3_LOCKER_ADDRESS \
  TOKEN_ID \
  --private-key $PRIVATE_KEY \
  --rpc-url monad_testnet
```

### Issue: "Lock Not Unlocked"

**Solution**: Check the unlock time:

```bash
# Get lock details
cast call V3_LOCKER_ADDRESS "getLock(uint256)" LOCK_ID --rpc-url base_sepolia

# Compare unlockDate with current timestamp
date +%s
```

## Next Steps

* Read the [V3 Interface Documentation](https://docs.realsafe.app/interfaces/v3)
* Read the [V2 Interface Documentation](https://docs.realsafe.app/interfaces/v2)
* Review [Security Best Practices](https://docs.realsafe.app/reference/security)
* Check [Deployment Addresses](https://docs.realsafe.app/reference/deployments)
* Explore [Advanced Features](https://docs.realsafe.app/advanced/conditional-unlocks)

## Support

* **X**: [@RealSafeLP](https://x.com/RealSafeLP)
* **Documentation**: [Read the docs](https://docs.realsafe.io)
