# Property Onboarding

Complete guide for property owners to tokenize property cash flows and manage yield distribution.

***

## Who Is This For?

* **Property Owners** - Want to raise capital by tokenizing future cash flows
* **Property Managers** - Managing tokenized properties
* **Real Estate Companies** - Looking to create liquid markets for their assets

***

## Complete Onboarding Flow

{% @mermaid/diagram content="graph TB
Start(\[Property Owner])

```
Step1[1. Create YRT Token<br/>YRTFactory.createSeries]
Step2[2. Create DEX Pool<br/>OwnaFactory.createPool]
Step3[3. Add Initial Liquidity<br/>500 YRT + 500 USDC]
Step4[4. Fundraising Period<br/>Users trade on DEX]
Step5[5. Deposit Yield<br/>50k USDC]
Step6[6. Snapshot & Distribution<br/>Chainlink Automation]
Step7{Continue?}
Step8[7. Start New Period]

Start --> Step1
Step1 --> Step2
Step2 --> Step3
Step3 --> Step4
Step4 --> Step5
Step5 --> Step6
Step6 --> Step7
Step7 -->|Yes| Step8
Step8 --> Step4
Step7 -->|No| End([Property Live])" %}
```

***

## ( Required ) Property Information Ready

Before starting, prepare:

* Property name (e.g., "Green Valley Apartment")
* Token name (e.g., "Green Valley YRT")
* Token symbol (e.g., "GV-YRT")
* Initial supply (e.g., 1000 tokens)
* Token price (e.g., 1 USDC per YRT)
* Fundraising duration (e.g., 180 seconds for demo, 7,776,000 for 90 days)

***

## Step 1: Create YRT Token

### Understanding Parameters

```solidity
function createSeries(
    string memory _name,                  // "Green Valley YRT"
    string memory _symbol,                // "GV-YRT"
    string memory _propertyName,          // "Green Valley Apartment"
    uint256 _initialSupply,               // 1000e18 (1000 tokens)
    address _underlyingToken,             // USDC address
    uint256 _tokenPrice,                  // 1e18 (1 USDC = 1 YRT)
    uint256 _fundraisingDuration          // 180 (seconds)
) external returns (uint256 seriesId)
```

**Duration Examples:**

```
Demo/Testing:
- 3 minutes = 180 seconds
- 10 minutes = 600 seconds

Production:
- 30 days = 2,592,000 seconds
- 90 days = 7,776,000 seconds
- 180 days = 15,552,000 seconds
```

### Execute Creation

**Using TypeScript/Frontend:**

```typescript
import { ethers } from "ethers";
import FactoryABI from "@/abis/YRTFactory.json";

const FACTORY_ADDRESS = "0x7698c369Cec5bFD14bFe9184ea19D644540f483b";
const USDC_ADDRESS = "0x70667aea00Fc7f087D6bFFB9De3eD95Af37140a4";

const factory = new ethers.Contract(FACTORY_ADDRESS, FactoryABI, signer);

// Create series
const tx = await factory.createSeries(
    "Green Valley YRT",                       // Token name
    "GV-YRT",                                 // Token symbol
    "Green Valley Apartment",                 // Property name
    ethers.utils.parseUnits("1000", 18),     // 1000 tokens
    USDC_ADDRESS,                             // Underlying token
    ethers.utils.parseUnits("1", 18),        // 1 USDC per token
    180                                       // 3 minutes (demo)
);

const receipt = await tx.wait();

// Get seriesId from event
const event = receipt.events?.find(e => e.event === "SeriesCreated");
const seriesId = event?.args?.seriesId;

console.log(`✅ Series created! ID: ${seriesId}`);

// Get YRT token address
const seriesInfo = await factory.seriesInfo(seriesId);
const yrtAddress = seriesInfo[0];

console.log(`YRT Token: ${yrtAddress}`);
```

**What Happens:**

1. New YRTToken contract deployed
2. 1000 YRT minted to your address
3. Period 1 automatically started
4. Maturity date set (now + 180 seconds)
5. Returns `seriesId` (e.g., 1)

***

## Step 2: Create DEX Pool

### Why Create Pool?

Direct purchase is disabled. Users must buy via DEX for:

* Fair price discovery
* Liquidity incentives
* Secondary market trading

### Execute Pool Creation

```typescript
import DexFactoryABI from "@/abis/OwnaFactory.json";

const DEX_FACTORY = "0xc493CC506aDF88A26cd72F45503D1DE6c3A085EF";

const dexFactory = new ethers.Contract(DEX_FACTORY, DexFactoryABI, signer);

// Create pool
const tx = await dexFactory.createPool(
    yrtAddress,                 // YRT token from Step 1
    USDC_ADDRESS,               // USDC
    "Green Valley Apartment"    // Property name
);

const receipt = await tx.wait();

// Get pool address from event
const event = receipt.events?.find(e => e.event === "PoolCreated");
const poolAddress = event?.args?.pool;

console.log(`✅ Pool created: ${poolAddress}`);
```

**What Happens:**

1. New OwnaPool contract deployed
2. Pair: YRT/USDC
3. Pool is empty (no liquidity yet)
4. Returns `poolAddress`

***

## Step 3: Add Initial Liquidity

### Understanding Initial Liquidity

Initial liquidity sets the **starting price**:

```
Price = Reserve_USDC / Reserve_YRT

Example:
500 YRT + 500 USDC → Price = 1 USDC/YRT
500 YRT + 1000 USDC → Price = 2 USDC/YRT
1000 YRT + 500 USDC → Price = 0.5 USDC/YRT
```

**Recommended:**

* Add 50% of initial supply
* Example: 1000 supply → add 500 YRT
* Match with equal USDC value
* Result: 1:1 starting price

### Execute Liquidity Addition

```typescript
import RouterABI from "@/abis/OwnaRouter.json";

const ROUTER = "0xE5b501b4d2CCD234FcD94906C561B8d5B1e4cEb7";

const router = new ethers.Contract(ROUTER, RouterABI, signer);
const yrt = new ethers.Contract(yrtAddress, ERC20_ABI, signer);
const usdc = new ethers.Contract(USDC_ADDRESS, ERC20_ABI, signer);

// Step 1: Approve tokens
await yrt.approve(ROUTER, ethers.utils.parseUnits("500", 18));
await usdc.approve(ROUTER, ethers.utils.parseUnits("500", 18));

console.log("✅ Tokens approved");

// Step 2: Add liquidity
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes

const tx = await router.addLiquidity(
    yrtAddress,
    USDC_ADDRESS,
    ethers.utils.parseUnits("500", 18),    // 500 YRT
    ethers.utils.parseUnits("500", 18),    // 500 USDC
    ethers.utils.parseUnits("500", 18),    // Min YRT (no slippage for first LP)
    ethers.utils.parseUnits("500", 18),    // Min USDC
    ownerAddress,                           // LP tokens recipient
    deadline,
    "Green Valley Apartment"
);

await tx.wait();

console.log("✅ Liquidity added!");
console.log("Pool state: 500 YRT + 500 USDC");
console.log("Starting price: 1 USDC/YRT");
```

**What Happens:**

1. 500 YRT transferred to pool
2. 500 USDC transferred to pool
3. You receive LP tokens
4. Pool is now active!
5. Users can start trading

***

## Step 4: Fundraising Period

### What Happens During Fundraising

```
Duration: 180 seconds (or configured duration)

Activities:
✅ Users can buy YRT on DEX
✅ Users can sell YRT on DEX
✅ Price changes based on supply/demand
✅ Trading volume accumulates
✅ Holder list changes dynamically

Restrictions:
❌ Cannot mint new tokens
❌ Cannot trigger snapshot yet
❌ Cannot deposit yield yet
```

### Monitor Activity

**Track pool state:**

```typescript
const pool = new ethers.Contract(poolAddress, PoolABI, provider);

// Get reserves
const reserves = await pool.getReserves();
console.log(`Reserve YRT: ${ethers.utils.formatUnits(reserves[0], 18)}`);
console.log(`Reserve USDC: ${ethers.utils.formatUnits(reserves[1], 18)}`);

// Calculate current price
const price = reserves[1] / reserves[0];
console.log(`Current price: ${price.toFixed(4)} USDC/YRT`);
```

**Track token distribution:**

```typescript
const yrt = new ethers.Contract(yrtAddress, TokenABI, provider);

// Get current holders
const holdersCount = await yrt.getHoldersCount();
console.log(`Total holders: ${holdersCount}`);

// Get your balance
const balance = await yrt.balanceOf(ownerAddress);
console.log(`Your balance: ${ethers.utils.formatUnits(balance, 18)} YRT`);
```

### Wait for Maturity

```typescript
// Check maturity date
const maturityDate = await yrt.periodMaturityDate(1);
const now = Math.floor(Date.now() / 1000);
const remaining = maturityDate - now;

console.log(`Time to maturity: ${remaining} seconds`);

if (remaining <= 0) {
    console.log("✅ Period matured! Ready for yield deposit");
}
```

***

## Step 5: Deposit Yield

### When to Deposit

**Timing:**

* After maturity date reached
* Before snapshot trigger
* Recommended: 1-2 days before maturity for safety

**Amount:**

* Based on property cash flow
* Example: 50,000 USDC for quarterly rent collection

### Execute Deposit

```typescript
// Step 1: Approve USDC
const yieldAmount = ethers.utils.parseUnits("50000", 18); // 50k USDC

await usdc.approve(FACTORY_ADDRESS, yieldAmount);
console.log("✅ USDC approved");

// Step 2: Deposit yield
const tx = await factory.depositYield(
    seriesId,      // 1
    1,             // Period 1
    yieldAmount    // 50,000 USDC
);

await tx.wait();
console.log("✅ Yield deposited: 50,000 USDC");
```

**What Happens:**

1. 50,000 USDC transferred from your wallet to factory
2. Yield recorded for Period 1
3. Ready for distribution after snapshot

***

## Step 6: Snapshot & Distribution

### Automatic Snapshot (Chainlink)

**No action required!**

Chainlink Automation will:

1. Monitor maturity date
2. Trigger snapshot automatically when:
   * Maturity date reached ✅
   * Yield deposited ✅
   * Snapshot not taken yet ✅

**Timeline:**

```
Maturity date: Day 90, 00:00:00 UTC
Chainlink check: Every block (~2 seconds)
Snapshot trigger: Within minutes of maturity
```

**Monitor snapshot:**

```typescript
// Check if snapshot taken
const snapshotTaken = await yrt.isSnapshotTakenForPeriod(1);

if (snapshotTaken) {
    console.log("✅ Snapshot taken!");

    // Get snapshot data
    const totalSupply = await yrt.getSnapshotTotalSupplyForPeriod(1);
    const holders = await yrt.getSnapshotHoldersForPeriod(1);

    console.log(`Snapshot total supply: ${ethers.utils.formatUnits(totalSupply, 18)}`);
    console.log(`Snapshot holders: ${holders.length}`);
}
```

### Manual Distribution

After snapshot, you must trigger distribution:

```typescript
import AutoDistributorABI from "@/abis/AutoDistributor.json";

const AUTO_DISTRIBUTOR = "0x8C9edAB077038B4f2e74d79663d79f3fc12Ca945";

const autoDistributor = new ethers.Contract(
    AUTO_DISTRIBUTOR,
    AutoDistributorABI,
    signer
);

// Distribute to all snapshot holders
const tx = await autoDistributor.distributeToAllHolders(
    seriesId,  // 1
    1          // Period 1
);

await tx.wait();

console.log("✅ Yield distributed to all holders!");
```

**What Happens:**

1. Gets snapshot holders list (frozen at maturity)
2. Calculates proportional yield for each holder
3. Transfers USDC to each holder automatically
4. Users receive USDC in wallets (no claim needed)

**Example Distribution:**

```
Total Yield: 50,000 USDC
Total Supply at Snapshot: 1000 YRT

Holders:
- Alice: 250 YRT (25%) → Receives: 12,500 USDC
- Bob: 200 YRT (20%) → Receives: 10,000 USDC
- Charlie: 150 YRT (15%) → Receives: 7,500 USDC
- You (owner): 400 YRT (40%) → Receives: 20,000 USDC
```

***

## Step 7: Start New Period (Optional)

### When to Start New Period

**Typical schedule:**

* Period 1 (Q1): Jan-Mar → Distribute → Start Period 2
* Period 2 (Q2): Apr-Jun → Distribute → Start Period 3
* Period 3 (Q3): Jul-Sep → Distribute → Start Period 4
* Period 4 (Q4): Oct-Dec → Distribute → End or continue

### Execute New Period

```typescript
// Calculate duration (90 days = 7,776,000 seconds)
const durationSeconds = 90 * 24 * 60 * 60; // 7,776,000

// Start Period 2
const tx = await factory.startNewPeriod(
    seriesId,           // 1
    durationSeconds     // 90 days
);

await tx.wait();

console.log("✅ Period 2 started!");
console.log(`Duration: 90 days (${durationSeconds} seconds)`);

// Check new maturity date
const yrt = new ethers.Contract(yrtAddress, TokenABI, provider);
const maturityDate = await yrt.periodMaturityDate(2);

console.log(`Period 2 maturity: ${new Date(maturityDate * 1000)}`);
```

**Cycle repeats:**

1. Fundraising period (90 days)
2. Deposit yield
3. Snapshot (automatic)
4. Distribution
5. Start Period 3...

***

## Supply Expansion

### When to Expand Supply

**Allowed during GAP period:**

* After snapshot taken
* Before next period starts

**Use case:**

* Property generates more cash flow
* Want to raise more capital
* Expand tokenization

### Execute Mint

```typescript
// Check if in GAP period
const period2Started = await yrt.currentPeriod() === 2;
const period1Snapshot = await yrt.isSnapshotTakenForPeriod(1);

if (period1Snapshot && !period2Started) {
    console.log("✅ In GAP period, can mint");

    // Mint 500 more tokens
    const tx = await factory.mintTokens(
        seriesId,                              // 1
        ownerAddress,                          // Recipient
        ethers.utils.parseUnits("500", 18)    // 500 tokens
    );

    await tx.wait();

    console.log("✅ Minted 500 YRT");
    console.log("New total supply: 1500 YRT");
} else {
    console.log("❌ Not in GAP period");
}
```

**Add minted tokens to pool:**

```typescript
// Add new liquidity with minted tokens
await yrt.approve(ROUTER, ethers.utils.parseUnits("500", 18));
await usdc.approve(ROUTER, ethers.utils.parseUnits("500", 18));

await router.addLiquidity(
    yrtAddress,
    USDC_ADDRESS,
    ethers.utils.parseUnits("500", 18),
    ethers.utils.parseUnits("500", 18),
    0,
    0,
    ownerAddress,
    deadline,
    "Green Valley Apartment"
);

console.log("✅ New liquidity added to pool");
```

***

## Best Practices

### Timing

1. **Deposit yield early** (1-2 days before maturity)
   * Ensures Chainlink can trigger snapshot
   * Avoids last-minute issues
2. **Monitor Chainlink Upkeep**
   * Check status: <https://automation.chain.link/base-sepolia>
   * Ensure LINK balance > 5 LINK
3. **Distribute immediately after snapshot**
   * Better UX for users
   * Shows professionalism

### Communication

1. **Announce periods in advance**
   * Share maturity dates
   * Expected yield amounts
   * Distribution timeline
2. **Update users on progress**
   * "Yield deposited ✅"
   * "Snapshot taken ✅"
   * "Distribution complete ✅"
3. **Transparency**
   * Share contract addresses
   * Verify on BaseScan
   * Publish yield calculations

### Risk Management

1. **Start with demo periods** (3-10 minutes)
   * Test full flow
   * Verify automation works
   * Fix issues before production
2. **Use testnet first** (Base Sepolia)
   * No real money at risk
   * Learn the system
   * Train your team
3. **Have yield ready**
   * Don't promise yield you can't deliver
   * Maintain USDC balance
   * Plan for periods in advance

***

## Troubleshooting

### Snapshot Not Triggered

**Check:**

1. Maturity date reached?
2. Yield deposited?
3. Chainlink Upkeep funded?

**Manual trigger (if needed):**

```typescript
await factory.triggerSnapshotForPeriod(seriesId, periodId);
```

### Cannot Mint Tokens

**Error:** "Cannot mint during fundraising period"

**Cause:** Trying to mint during active fundraising

**Solution:** Wait for snapshot, then mint in GAP period

### Distribution Failed

**Check:**

1. Snapshot taken?
2. Sufficient USDC balance in factory?
3. Gas limit (use batchDistribute for many holders)?

***

## Related Documentation

* [Quick Start Guide](https://owna-finance.gitbook.io/owna-finance-docs/how-owna-finance-works/getting-started) - Overview for all users
* [User Trading Guide](https://owna-finance.gitbook.io/owna-finance-docs/user-trading) - Investor perspective
* [Snapshot System](https://owna-finance.gitbook.io/owna-finance-docs/advanced-topics/snapshots) - How snapshots work
* [Chainlink Automation](https://owna-finance.gitbook.io/owna-finance-docs/advanced-topics/chainlink) - Automatic triggers
* [Contract Addresses](https://owna-finance.gitbook.io/owna-finance-docs/deployment/addresses) - Deployed contracts

***

**Congratulations! Your property is now tokenized! 🎉**

**Need Help?**

* Read [FAQ](https://owna-finance.gitbook.io/owna-finance-docs/resources/faq)
* Check [Glossary](https://owna-finance.gitbook.io/owna-finance-docs/resources/glossary)
* Join Discord (link in docs)

***

**Last Updated:** January 2025
