> ## 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.

# Sui FAQ

> Common issues and solutions for Sui FAQ. Troubleshoot problems and find answers to frequently asked questions. LayerZero enables secure crosschain messaging.

Frequently asked questions about developing LayerZero applications on Sui.

## General Questions

> [accordion] Why does Sui use the Call (Hot Potato) pattern?
>
> Sui Move lacks native dynamic dispatch (unlike EVM's `delegatecall`). The `Call<Param, Result>` pattern provides an alternative by creating structs without `drop` or `store` abilities that must be consumed, using capability-based authorization, and enforcing call sequences through lifecycle states while ensuring atomicity within Programmable Transaction Blocks.
>
> For a detailed explanation of the Call pattern and Sui's architecture, see the [Sui documentation on PTBs](https://docs.sui.io/concepts/transactions/prog-txn-blocks).

> [accordion] How is the receive path different from EVM?
>
> The key difference is that Sui uses `Call` objects and PTBs instead of `delegatecall`. In EVM, the relayer calls `Endpoint.lzReceive()` which delegates to the OApp. In Sui, the Executor calls `Endpoint.lz_receive()` which creates a `Call<LzReceiveParam, Void>` object that the OApp destroys and processes via explicit PTB routing. Both execution models are permissionless.
>
> For architectural details, see [Technical Overview](https://docs.layerzero.network/v2/developers/sui/technical-overview.md) and [Protocol Overview](https://docs.layerzero.network/v2/developers/sui/protocol-overview.md).

## Development Questions

> [accordion] How do I verify my Sui package?
>
> Use [SuiScan](https://suiscan.xyz/mainnet/package-verification):
>
> **Method 1 - Web Interface**:
>
> 1. Navigate to SuiScan verification page
> 2. Enter package address
> 3. Upload source files
> 4. Wait for verification
>
> **Method 2 - API**:
>
> ```bash wrap theme={null}
> curl -X POST https://suiscan.xyz/api/verify \
>   -d '{"packageId": "0x...", "source": "..."}'
> ```
>
> See [Sui Guidance](https://docs.layerzero.network/v2/developers/sui/technical-reference/sui-guidance.md#contract-verification) for details.

> [accordion] Do I need to deploy my own Endpoint?
>
> No. LayerZero deploys and maintains the `EndpointV2` shared object on Sui. You only need to:
>
> 1. Publish your OApp or OFT package
> 2. Register your OApp with the Endpoint (creates a `MessagingChannel`)
> 3. Configure pathways to other chains

> [accordion] How do I handle decimal precision for OFTs?
>
> OFTs use **shared decimals** to handle precision differences:
>
> ```
> Local Decimals:  Token decimals on current chain (e.g., 9)
> Shared Decimals: Crosschain precision (default: 6)
>
> Conversion Rate: 10^(local - shared)
> ```
>
> When sending:
>
> 1. Amount is divided by conversion rate (removes dust)
> 2. Truncated amount is sent crosschain
> 3. Destination multiplies by its conversion rate
>
> See [OFT Overview](https://docs.layerzero.network/v2/developers/sui/oft/overview.md#decimal-precision) for examples.

> [accordion] Can I use existing tokens with LayerZero?
>
> Yes, use an **OFT Adapter** (lock/unlock model):
>
> ```rust wrap theme={null}
> public struct OFTAdapter {
>     escrow: Balance<EXISTING_TOKEN>, // Locked tokens
>     // No treasury_cap needed
> }
> ```
>
> For new tokens, use **mint/burn OFT** for better efficiency.

## Gas and Fees

> [accordion] What are the gas considerations for crosschain messages?
>
> Sui uses a dual gas model:
>
> **Storage Gas**:
>
> * Charged for creating objects
> * Refunded when objects are deleted
> * Can result in negative net gas
>
> **Computation Gas**:
>
> * Charged for execution
> * Not refunded
>
> **For LayerZero**:
>
> * Minimum 1000 base gas units
> * Budget 5-20M for typical operations
> * Source chain pays destination execution

> [accordion] How do I handle negative gas utilization rates?
>
> Negative gas is **normal** when storage is freed:
>
> ```rust wrap theme={null}
> // Freeing storage triggers rebate
> let MyObject { id, data } = obj;
> object::delete(id); // Rebate > gas used
> ```
>
> **Key Points**:
>
> * This is not an error
> * Still need minimum 1000 base budget
> * Net cost can be negative
> * Rebate goes to transaction sender
>
> See [Technical Overview](https://docs.layerzero.network/v2/developers/sui/technical-overview.md#gas-model) for details.

> [accordion] How much should I budget for gas?
>
> Recommended gas budgets:
>
> | Operation | Gas Budget |
> | - | - |
> | Initialize channel | 10,000,000 |
> | Set peer | 10,000,000 |
> | Configure DVNs | 15,000,000 |
> | Send message | 20,000,000 |
> | Receive message | 15,000,000 |
> | Deploy package | 100,000,000+ |
>
> Start higher and reduce based on actual usage.

## Configuration Questions

> [accordion] Do I need to set custom DVNs and Executors?
>
> No, defaults are available:
>
> ```bash wrap theme={null}
> # Minimal configuration (uses defaults)
> initialize_channel(...)  # Required
> set_peer(...)           # Required
> # That's it! Uses default DVNs and Executor
> ```
>
> Custom configuration is optional for:
>
> * Specific security requirements
> * Custom DVN sets
> * Private executors

> [accordion] How do I check my current configuration?
>
> Use the TypeScript SDK:
>
> ```typescript wrap theme={null}
> // Get peer
> const peer = await oapp.getPeer(remoteEid);
>
> // Get DVN config
> const config = await oapp.getSendConfig(remoteEid);
>
> console.log({
>   peer: Buffer.from(peer).toString('hex'),
>   requiredDVNs: config.requiredDVNs,
>   optionalDVNs: config.optionalDVNs,
> });
> ```
>
> The Sui CLI cannot easily parse complex return values.

> [accordion] Can I change configuration after deployment?
>
> Yes, if you retain the `AdminCap`:
>
> ```bash wrap theme={null}
> # Update peer
> sui client call \
>     --function set_peer \
>     --args $OAPP $ADMIN_CAP $NEW_EID $NEW_PEER \
>     ...
>
> # Update DVNs
> sui client call \
>     --function set_send_uln_config \
>     --args $OAPP $ADMIN_CAP $EID ... \
>     ...
> ```
>
> Without AdminCap, configuration is immutable.

## SDKs and Tooling

> [accordion] What SDKs are available for Sui?
>
> LayerZero provides two TypeScript SDKs:
>
> 1. **[@layerzerolabs/lz-sui-sdk-v2](https://www.npmjs.com/package/@layerzerolabs/lz-sui-sdk-v2)**
>
>    * Core Endpoint interactions
>    * OApp functionality
>    * Configuration management
> 2. **[@layerzerolabs/lz-sui-oft-sdk-v2](https://www.npmjs.com/package/@layerzerolabs/lz-sui-oft-sdk-v2)**
>    * OFT-specific operations
>    * Token transfers
>    * Balance queries
>
> See [OFT SDK](https://docs.layerzero.network/v2/developers/sui/oft/sdk.md) for usage examples.

> [accordion] Why can't I use the Sui CLI to query state?
>
> The Sui CLI can read simple fields but has limitations for complex queries:
>
> * Doesn't easily parse return values from view functions
> * Manual decoding needed for bytes arrays and nested structs
> * No built-in formatting for complex types
>
> **Solution**: Use TypeScript SDK for complex state queries:
>
> ```typescript wrap theme={null}
> import {SuiClient} from '@mysten/sui.js/client';
>
> // Query OApp object fields
> const oapp = await client.getObject({
>   id: oappObjectId,
>   options: {showContent: true},
> });
>
> // Or use LayerZero SDK helpers
> import {OApp} from '@layerzerolabs/lz-sui-sdk-v2';
> const peer = await oapp.getPeer(client, remoteEid);
> ```

> [accordion] Is there a deploy/wire tool for Sui?
>
> Not currently. Package publication and configuration require:
>
> 1. **Publish packages**: Using `sui client publish`
> 2. **Call entry functions**: Invoke configuration functions via `sui client call` or SDK
> 3. **Custom scripts**: Write TypeScript scripts for automated workflows
>
> See [Configuration Guide](https://docs.layerzero.network/v2/developers/sui/configuration/dvn-executor-config.md) for manual setup instructions.

## Troubleshooting

> [accordion] Why is my transaction failing with "unused value without drop ability"?
>
> This error means a `Call` object wasn't properly consumed in your PTB:
>
> ```rust wrap theme={null}
> // - Incorrect: Call object not confirmed
> let call = oapp::send(&mut oapp, &oapp_cap, ...);
> // Transaction ends without destroying call → ERROR
>
> // - Correct: Call object confirmed
> let call = oapp::send(&mut oapp, &oapp_cap, ...);
> // PTB routes call through Endpoint/ULN/Workers
> let (_, receipt) = oapp::confirm_lz_send(&oapp, &oapp_cap, call);
> ```
>
> **Solution**: Every `Call` returned must be confirmed/destroyed before the transaction completes.

> [accordion] What does "Channel not initialized" mean?
>
> You're trying to send to a destination chain without a `MessagingChannel`:
>
> ```bash wrap theme={null}
> # Fix: Initialize the channel first
> sui client call \
>     --package <ENDPOINT_PACKAGE> \
>     --module endpoint_v2 \
>     --function init_channel \
>     --args <ENDPOINT_OBJECT> <CALL_CAP> <REMOTE_EID> \
>     --gas-budget 10000000
> ```
>
> The Endpoint creates a dedicated `MessagingChannel` shared object for each OApp.

> [accordion] How do I recover from a stuck message?
>
> Use recovery entry functions on the Endpoint (requires `AdminCap`):
>
> **Skip a message** (increment nonce without execution):
>
> ```bash wrap theme={null}
> sui client call \
>     --package <ENDPOINT_PACKAGE> \
>     --module endpoint_v2 \
>     --function skip \
>     --args <ENDPOINT_OBJECT> <ADMIN_CAP> <OAPP_ADDRESS> <SRC_EID> <SENDER_BYTES32> <NONCE> \
>     --gas-budget 10000000
> ```
>
> **Clear a message** (mark as delivered without execution):
>
> ```bash wrap theme={null}
> sui client call \
>     --function clear \
>     --args <ENDPOINT_OBJECT> <ADMIN_CAP> <OAPP_ADDRESS> <SRC_EID> <SENDER_BYTES32> <NONCE> \
>     --gas-budget 10000000
> ```
>
> See [Common Errors](https://docs.layerzero.network/v2/developers/sui/troubleshooting/common-errors.md) for more recovery options.

## Security Questions

> [accordion] How do I secure my OApp?
>
> Follow these capability-based security practices:
>
> 1. **Validate CallCap in All Functions**:
>
> ```rust wrap theme={null}
> public fun send(
>     self: &OApp,
>     oapp_cap: &CallCap,  // - Require capability
>     ...
> ) {
>     self.assert_oapp_cap(oapp_cap);  // - Validate ownership
>     // ...
> }
>
> fun assert_oapp_cap(self: &OApp, cap: &CallCap) {
>     assert!(self.oapp_cap.id() == cap.id(), EInvalidOAppCap);
> }
> ```
>
> 2. **Validate Call Objects**:
>
> ```rust wrap theme={null}
> public fun lz_receive(self: &mut OApp, call: Call<LzReceiveParam, Void>) {
>     // - Validate Call came from authorized Endpoint
>     let (callee, param, _) = call.destroy(&self.oapp_cap);
>     assert!(callee == endpoint_address(), EOnlyEndpoint);
>
>     // - Validate sender is configured peer
>     let peer = self.peer.get_peer(param.src_eid);
>     assert!(param.sender == peer, EOnlyPeer);
> }
> ```
>
> 3. **Secure Capability Objects**:
>
> * Store `CallCap` in package module storage (not transferred)
>
> * Use multisig or hardware wallet for `AdminCap`
>
> * Never expose capabilities publicly
>
> * Transfer `AdminCap` carefully (use `transfer::public_transfer`)
>
> 4. **Protect UpgradeCap**:
>
> * Keep upgrade authority secure
> * Consider freezing upgrades after deployment (`package::make_immutable`)
> * Use multisig for mainnet upgrade authority

> [accordion] What are common security pitfalls?
>
> * * Missing `CallCap` validation in functions
> * * Not validating `Call` object source (callee address)
> * * Skipping peer validation in `lz_receive`
> * * Losing capability objects (no recovery possible)
> * * Wrong peer addresses configured
> * * Exposing `AdminCap` or `CallCap` publicly
>
> See [OApp Best Practices](https://docs.layerzero.network/v2/developers/sui/oapp/overview.md#best-practices) for details.

## Next Steps

* [Common Errors](https://docs.layerzero.network/v2/developers/sui/troubleshooting/common-errors.md)
* [Technical Overview](https://docs.layerzero.network/v2/developers/sui/technical-overview.md)
* [Configuration Guide](https://docs.layerzero.network/v2/developers/sui/configuration/dvn-executor-config.md)
* [Sui Guidance](https://docs.layerzero.network/v2/developers/sui/technical-reference/sui-guidance.md)
