Cycle

The Scriptorium

Smart Assembly code templates and tools for on-chain development in Eve Frontier.

Tribe-Gated Storage
IntermediateChapter 5 of 515 min read

Deployment and Testing

This chapter walks through building, deploying, and configuring the tribe storage extension on the EVE Frontier Stillness testnet.

Prerequisites

Before deploying, make sure you have:

  • The SUI CLI installed (cargo install --locked --git https://github.com/MystenLabs/sui.git sui)
  • A SUI wallet with testnet SUI for gas (use sui client faucet on testnet)
  • The EVE Frontier world contracts cloned locally (referenced as a dependency in Move.toml)

Project Structure

``

contracts/tribe-storage-access/

├── Move.toml

├── Published.toml # Created after deployment

└── sources/

├── config.move

└── tribe_storage.move

`

Move.toml

toml
[package]
name = "tribe_storage_access"
edition = "2024.beta"

[dependencies]
world = { local = "../../.world-contracts/contracts/world" }

[environments]
testnet_internal = "4c78adac"
testnet_utopia = "4c78adac"
testnet_stillness = "4c78adac"

The [environments] section maps EVE Frontier environment names to chain identifiers. The world dependency points to the locally cloned game contracts, which provide StorageUnit, Character, OwnerCap, and other types.

Building

Compile the package to check for errors:

bash
cd contracts/tribe-storage-access
sui move build

A successful build produces no errors and creates a build/ directory with the compiled bytecode. Common build errors include:

  • Missing dependencies -- ensure the world path is correct
  • Ability mismatches -- check that your structs have the required abilities
  • Visibility errors -- public(package) functions cannot be called from outside the package

Deploying

Publish the package to the Stillness testnet:

bash
sui client publish --gas-budget 100000000

On success, the output includes:

  • Package ID -- the on-chain address of your published code
  • Created objects -- the AdminCap and ExtensionConfig object IDs

Example output (abbreviated):

`

----- Transaction Effects ----

Created Objects:

- ID: 0xabc123... , Owner: Account Address (0xYOUR_ADDR) ← AdminCap

- ID: 0xdef456... , Owner: Shared ← ExtensionConfig

Published Package: 0x789...

`

Record these three values. You will need them for configuration and dApp setup.

Published.toml

After deploying, create a Published.toml file to record the deployment for future reference and for any tooling that needs it:

toml
[stillness]
package_id = "0x789..."        # Package ID from publish output
config_id = "0xdef456..."      # ExtensionConfig object ID (Shared)
admin_cap_id = "0xabc123..."   # AdminCap object ID (Owned)
published_at = "2025-01-15"

This file is not consumed by the Move compiler but is useful for scripts and documentation.

Post-Deployment Configuration

After publishing, you need to:

  • Set the tribe configuration
  • Have the SSU owner authorize the extension
  • Step 1: Set Tribe Config

    Call set_tribe_config to specify which tribe can use the shared storage:

    bash
    sui client call \
      --package 0x789... \
      --module tribe_storage \
      --function set_tribe_config \
      --args 0xdef456... 0xabc123... 5 \
      --gas-budget 10000000

    Arguments in order:

  • 0xdef456... -- ExtensionConfig object ID (shared)
  • 0xabc123... -- AdminCap object ID (owned by you)
  • 5 -- Tribe ID (u32)
  • Or from TypeScript:

    typescript
    import { Transaction } from '@mysten/sui/transactions';
    import { SuiGrpcClient } from '@mysten/sui/grpc';
    
    const client = new SuiGrpcClient({ network: 'testnet' });
    const tx = new Transaction();
    
    tx.moveCall({
      target: ${PACKAGE_ID}::tribe_storage::set_tribe_config,
      arguments: [
        tx.object(CONFIG_ID),      // ExtensionConfig
        tx.object(ADMIN_CAP_ID),   // AdminCap
        tx.pure.u32(5),            // tribe ID
      ],
    });
    
    // Sign and execute with your wallet

    Step 2: Authorize on SSU

    The SSU owner must authorize the extension. This is done via a PTB that borrows the SSU's OwnerCap:

    typescript
    const tx = new Transaction();
    const xAuthType = ${PACKAGE_ID}::config::XAuth;
    const ssuType = ${EVE_FRONTIER_PKG}::storage_unit::StorageUnit;
    
    // Borrow OwnerCap<StorageUnit> from the character
    const [cap, receipt] = tx.moveCall({
      target: ${EVE_FRONTIER_PKG}::character::borrow_owner_cap,
      typeArguments: [ssuType],
      arguments: [
        tx.object(characterObjectId),
        tx.object(Inputs.ReceivingRef({
          objectId: ownerCapId,
          version: capVersion,
          digest: capDigest,
        })),
      ],
    });
    
    // Authorize the extension
    tx.moveCall({
      target: ${EVE_FRONTIER_PKG}::storage_unit::authorize_extension,
      typeArguments: [xAuthType],
      arguments: [tx.object(ssuId), cap],
    });
    
    // Return the cap
    tx.moveCall({
      target: ${EVE_FRONTIER_PKG}::character::return_owner_cap,
      typeArguments: [ssuType],
      arguments: [tx.object(characterObjectId), cap, receipt],
    });

    Verifying the Deployment

    Check the Package

    bash
    sui client object 0x789...

    This shows the published package metadata.

    Check the Config Object

    bash
    sui client object 0xdef456...

    After set_tribe_config, you should see a dynamic field attached to the object.

    Test a Share Operation

    Have a tribe member dock at the SSU in the game client, drag items from ship to SSU, then call share() from the dApp. If everything is configured correctly:

    • The transaction succeeds
    • Items appear in the open inventory
    • Other tribe members can see and withdraw them

    Common Deployment Issues

    "Package not found" or dependency errors

    Ensure the world dependency path in Move.toml points to the correct local clone of the EVE Frontier contracts. The clone must include the correct version for the target environment.

    "Object equivocation" after failed transactions

    If a transaction fails but the wallet still references stale object versions, you may see equivocation errors. Call reportTransactionEffects on the SUI client to update the wallet's object cache, or wait a few seconds and retry.

    "Dry run failed, could not determine gas budget"

    Some wallet integrations fail on dry-run due to complex PTBs. Set an explicit gas budget:

    typescript
    tx.setGasBudget(50_000_000n);

    AdminCap lost or transferred

    If the AdminCap is sent to the wrong address, you lose admin control forever. There is no recovery mechanism -- you would need to publish a new package.

    Key Takeaways

    • Build with sui move build, deploy with sui client publish --gas-budget .
    • Record the Package ID, ExtensionConfig ID, and AdminCap ID from the publish output.
    • Post-deployment requires two steps: set_tribe_config (admin sets tribe) and authorize_extension (SSU owner grants access).
    • Use Published.toml` to track deployment details for your team.
    • Test by having a tribe member dock at the SSU and performing a share operation through the dApp.

    Sign in to track your progress.