> ## Documentation Index
> Fetch the complete documentation index at: https://docs.layerzero.network/llms.txt
> Use this file to discover all available pages before exploring further.

# IOTA L1 Development Guidance

> Technical reference for IOTA L1 Development Guidance. Complete API documentation with functions, parameters, and usage examples. LayerZero enables secure...

This page provides development guidance for building LayerZero applications on IOTA, covering toolchain setup, operational practices, and technical constraints.

## Toolchain Setup

### IOTA CLI

**Tested Version**: `iota@v1.54.1`

Install the [IOTA CLI](https://docs.iota.org/developer/references/cli):

```bash wrap theme={null}
cargo install --locked --git https://github.com/iotaledger/iota.git --branch mainnet iota
```

Verify installation:

```bash wrap theme={null}
iota --version
# iota 1.54.1-...
```

### Project Structure

Typical IOTA Move project structure:

```
my-oapp/
├── Move.toml              # Package manifest
├── sources/
│   ├── oapp.move         # Main OApp logic
│   ├── config.move       # Configuration
│   └── ...
├── tests/
│   └── oapp_tests.move   # Unit tests
└── scripts/
    └── deploy.sh         # Deployment scripts
```

### Move.toml Configuration

For [package structure](https://docs.iota.org/developer/iota-101/move-overview/package-upgrades/introduction) details:

```toml wrap theme={null}
[package]
name = "my_oapp"
version = "0.0.1"

[dependencies]
IOTA = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "mainnet" }
LayerZeroEndpoint = { git = "https://github.com/LayerZero-Labs/LayerZero-v2.git", subdir = "packages/layerzero-v2/iota/contracts/endpoint-v2", rev = "main" }
LayerZeroOApp = { git = "https://github.com/LayerZero-Labs/LayerZero-v2.git", subdir = "packages/layerzero-v2/iota/contracts/oapps/oapp", rev = "main" }

[addresses]
my_oapp = "0x0"
iota = "0x2"
```

## Development Environment

### Building Contracts

```bash wrap theme={null}
iota move build
```

### Running Tests

```bash wrap theme={null}
iota move test
```

### Local Development

Start a local IOTA network:

```bash wrap theme={null}
iota start
```

## Deployment

### Deploying to Testnet

```bash wrap theme={null}
iota client publish \
    --gas-budget 100000000 \
    --json
```

### Deploying to Mainnet

```bash wrap theme={null}
iota client switch --env mainnet
iota client publish \
    --gas-budget 100000000 \
    --json
```

### Deployment Script Example

```bash wrap theme={null}
#!/bin/bash

# Build
echo "Building..."
iota move build

# Deploy
echo "Deploying..."
RESULT=$(iota client publish \
    --gas-budget 100000000 \
    --json)

# Extract package ID
PACKAGE_ID=$(echo $RESULT | jq -r '.objectChanges[] | select(.type=="published") | .packageId')

echo "Package ID: $PACKAGE_ID"

# Save to file
echo $PACKAGE_ID > deployed_package.txt
```

## Operational Practices

### Package Upgrades

IOTA packages are immutable by default but can be made [upgradeable](https://docs.iota.org/developer/iota-101/move-overview/package-upgrades/upgrade).

**[`UpgradeCap`](https://docs.iota.org/developer/iota-101/move-overview/package-upgrades/upgrade)**: Owned object granting upgrade authority

```rust wrap theme={null}
/// Automatically created when publishing with --with-unpublished-dependencies
public struct UpgradeCap has key, store {
    id: UID,
    package: ID,     // Package being controlled
    version: u64,    // Current version
    policy: u8,      // Upgrade policy (compatible, additive, dep_only)
}
```

**Transfer Upgrade Authority**:

```bash wrap theme={null}
iota client transfer \
    --to <NEW_OWNER_ADDRESS> \
    --object-id <UPGRADE_CAP_OBJECT_ID> \
    --gas-budget 10000000
```

**Upgrade a Package**:

```bash wrap theme={null}
iota client upgrade \
    --upgrade-capability <UPGRADE_CAP_OBJECT_ID> \
    --gas-budget 200000000
```

**Key Point**: Upgraded packages maintain compatibility with objects created by previous versions, provided you follow IOTA's upgrade policies.

### Capability Management

LayerZero uses multiple capability objects:

**For OApp/OFT Packages**:

* `CallCap`: Authorizes creating `Call` objects (usually stored in package module)
* `AdminCap`: Authorizes admin operations (transfer to new admin as needed)
* `MigrationCap`: Authorizes migrating OApp/OFT to new implementations (store securely)
* `TreasuryCap<T>`: Authorizes minting/burning coins (for OFT mint/burn type)
* `UpgradeCap`: Authorizes package upgrades (transfer with caution)

**Transfer Pattern**:

```rust wrap theme={null}
// Transfer owned object to new owner
transfer::public_transfer(admin_cap, new_admin_address);
```

**No Safe Transfer**: IOTA doesn't have EVM's `safeTransfer` callback. Transfers are direct:

```rust wrap theme={null}
transfer::public_transfer(object, recipient);  // Direct, no callback
```

### Multisig Patterns

For multi-party control, use:

1. **IOTA Multisig Addresses**: Native 1-of-n or k-of-n multisig
2. **Shared Control Objects**: Create a shared configuration object requiring multiple approvals
3. **Third-Party Solutions**: IOTA Wallet multisig, protocol-specific multisig

**Example using address derivation**:

```bash wrap theme={null}
# Create multisig address with multiple public keys
iota keygen multi-sig \
    --pks <PUBKEY1> <PUBKEY2> <PUBKEY3> \
    --weights 1 1 1 \
    --threshold 2
```

## Resource & Fee Models

See [IOTA Gas Model](https://docs.iota.org/developer/stardust/units#iota) for complete details.

### Storage Gas

Charged for storing data onchain:

```rust wrap theme={null}
// Creating objects costs storage gas
let obj = MyObject { id: object::new(ctx), data: ... };
transfer::share_object(obj); // Storage charged here
```

### Computation Gas

Charged for execution:

```rust wrap theme={null}
// Complex logic costs computation gas
public fun complex_operation(...) {
    // Each instruction consumes gas
    let result = heavy_computation();
    // ...
}
```

### Rebate Mechanism

When storage is freed, gas is refunded:

```rust wrap theme={null}
// Deleting objects triggers rebate
let MyObject { id, data } = obj;
object::delete(id); // Storage rebate issued
```

**Important**: This can result in **negative gas utilization** for net storage reduction.

### Base Budget

Every transaction requires a minimum of **1000 gas units**, even if net cost is negative due to rebates.

## Technical Constraints

### Package Size Limit

**Maximum size per package**: 250 KiB

If your package exceeds this:

* Split into multiple packages
* Reduce unused code
* Optimize data structures

### Transaction Size Constraints

See [IOTA Transaction Limits](https://docs.iota.org/developer/iota-101/transactions):

* Max objects per transaction: 256
* Max events per transaction: 1024
* Max argument size: 128 KB

### Compute Limits

Gas limits vary by network:

* **Testnet**: Lower limits
* **Mainnet**: Higher limits

For LayerZero operations, budget at least:

* **Simple send**: 5,000,000 gas
* **Complex send**: 20,000,000 gas
* **Receive**: 10,000,000 gas

### Network Resource Limits

Monitor these limits:

* **Object count per address**: Unlimited, but impacts query performance
* **Storage per address**: Unlimited, but costs scale linearly
* **Transaction throughput**: \~5,000 TPS (network-wide)

## Network Considerations

### Finality

IOTA uses a **checkpoint-based finality** system:

* **Soft finality**: Certificate of transaction (milliseconds)
* **Hard finality**: Checkpoint inclusion (\~2-3 seconds)

For LayerZero verification, DVNs wait for checkpoint finality.

### RPC Infrastructure

**Public RPCs**:

* Mainnet: `https://fullnode.mainnet.iota.io:443`
* Testnet: `https://fullnode.testnet.iota.io:443`
* Devnet: `https://fullnode.devnet.iota.io:443`

**Private RPC Providers**:

* Ankr
* QuickNode
* Blast API

For production, use private RPCs for better reliability and rate limits.

## Channel Management

### Recovery Methods

LayerZero provides recovery methods for stuck messages:

```rust wrap theme={null}
// Skip a message
public entry fun skip(
    oapp: &mut OApp,
    admin_cap: &AdminCap,
    src_eid: u32,
    sender: vector<u8>,
    nonce: u64,
)

// Clear a message
public entry fun clear(
    oapp: &mut OApp,
    admin_cap: &AdminCap,
    src_eid: u32,
    sender: vector<u8>,
    nonce: u64,
)

// Nilify a message
public entry fun nilify(
    oapp: &mut OApp,
    admin_cap: &AdminCap,
    src_eid: u32,
    sender: vector<u8>,
    nonce: u64,
)
```

**Authorization**: All recovery methods require the `AdminCap` object.

### Querying State with TypeScript SDKs

The IOTA CLI has limitations for querying state. Use TypeScript SDKs instead:

```typescript wrap theme={null}
import {IOTAClient} from '@iota/iota-sdk/client';
import {OApp} from '@layerzerolabs/lz-iotal1-sdk-v2';

const client = new IOTAClient({url: 'https://fullnode.mainnet.iota.io:443'});

// Query peer configuration
const peer = await oapp.getPeer(client, 30101);

// Query nonce
const nonce = await oapp.getInboundNonce(client, 30101, senderBytes32);

// Query configuration
const config = await oapp.getConfig(client, 30101);
```

### IOTA CLI Limitations

The IOTA CLI cannot easily:

* Parse complex return values from view functions
* Handle nested data structures
* Decode bytes arrays

**Workaround**: Use the TypeScript SDK for all state queries.

## Best Practices

### 1. Test Thoroughly

```bash wrap theme={null}
# Run unit tests
iota move test

# Run integration tests on testnet
iota client call --package $PKG ... --json
```

### 2. Monitor Gas Usage

```bash wrap theme={null}
# Use --gas-budget appropriately
iota client call \
    --gas-budget 20000000 \ # Start higher
    --json
```

### 3. Handle Rebates Correctly

```rust wrap theme={null}
// Don't assume gas cost is always positive
// Rebates can make net cost negative
```

### 4. Version Your Packages

```toml wrap theme={null}
[package]
name = "my_oapp"
version = "1.0.0" # Increment on upgrades
```

### 5. Secure Your Keys

```bash wrap theme={null}
# Use hardware wallets for mainnet
# Keep upgrade capabilities secure
# Use multisig for critical operations
```

## Common Gotchas

### 1. Negative Gas Utilization

When storage is freed, transactions can have negative net gas cost. Budget at least 1000 base units.

### 2. Package Size Exceeded

**Error**: `Package size exceeds maximum`

**Solution**: Split into multiple packages or optimize code.

### 3. Object Ownership Errors

**Error**: `Invalid object ownership`

**Solution**: Verify object is owned by signer or is shared.

### 4. Insufficient Gas

**Error**: `Insufficient gas`

**Solution**: Increase `--gas-budget` parameter.

## Additional Resources

* [IOTA Documentation](https://docs.iota.org/)
* [IOTA Move Documentation](https://docs.iota.org/developer/iota-101/move-overview/move-overview)
* [IOTA GitHub](https://github.com/iotaledger/iota)
* [LayerZero IOTA Contracts](https://github.com/LayerZero-Labs/LayerZero-v2/tree/main/packages/layerzero-v2/iota)

## Next Steps

* [OApp Overview](/v2/developers/iota/oapp/overview)
* [OFT Overview](/v2/developers/iota/oft/overview)
* [Configuration Guide](/v2/developers/iota/configuration/dvn-executor-config)
* [Troubleshooting](/v2/developers/iota/troubleshooting/common-errors)
