---
# System prepended metadata

title: "VIBECODING A LINERA CONTRACT \U0001F680"

---

# VIBECODING A LINERA CONTRACT 🚀

A complete guide to building, deploying, and interacting with a simple message storage application on Linera.

## Table of Contents

-   [What We Built](#what-we-built)
-   [Project Structure](#project-structure)
-   [Step 1: Understanding the Linera Application Architecture](#step-1-understanding-the-linera-application-architecture)
-   [Step 2: Defining the State](#step-2-defining-the-state)
-   [Step 3: Creating Operations](#step-3-creating-operations)
-   [Step 4: Implementing the Contract Logic](#step-4-implementing-the-contract-logic)
-   [Step 5: Building the GraphQL Service](#step-5-building-the-graphql-service)
-   [Step 6: Writing Tests](#step-6-writing-tests)
-   [Step 7: Building for WebAssembly](#step-7-building-for-webassembly)
-   [Step 8: Deploying to Testnet](#step-8-deploying-to-testnet)
-   [Step 9: Interacting with Your Application](#step-9-interacting-with-your-application)
-   [Key Takeaways](#key-takeaways)

---

## What We Built

A simple message storage contract that allows users to:

-   ✅ Store a message on-chain during deployment
-   ✅ Update the message using GraphQL mutations
-   ✅ Retrieve the current message using GraphQL queries
-   ✅ Persist message state across sessions

**Deployed Application:**

-   Chain ID: `d79aa094242881a3727d36ac12d026caf886438041784b70448fe13adeb3afd4`
-   Application ID: `eab9b22ac9c1e177ffa821937bb6cfdcdd7107860ca40bd9476e461d5804177e`

---

## Project Structure

```
backend/
├── Cargo.toml              # Dependencies and build configuration
├── src/
│   ├── lib.rs              # ABI definition and operations
│   ├── state.rs            # Application state
│   ├── contract.rs         # Contract logic (business layer)
│   └── service.rs          # GraphQL service (query layer)
└── tests/
    └── single_chain.rs     # Integration tests
```

---

## Step 1: Understanding the Linera Application Architecture

Linera applications consist of two main components:

### Contract (contract.rs)

-   Executes operations and modifies state
-   Runs in a secure, sandboxed environment
-   Creates blocks on the blockchain

### Service (service.rs)

-   Provides read-only access to state
-   Exposes GraphQL API for queries
-   Runs on the node service

Both are compiled to WebAssembly and deployed together.

---

## Step 2: Defining the State

**File:** `src/state.rs`

We defined a simple state that stores a message using `RegisterView<String>`:

```rust
use linera_sdk::views::{linera_views, RegisterView, RootView, ViewStorageContext};

#[derive(RootView, async_graphql::SimpleObject)]
#[view(context = ViewStorageContext)]
pub struct BackendState {
    pub message: RegisterView<String>,
}
```

### Key Points:

-   `RootView` - Marks this as the root of the application's state
-   `RegisterView<String>` - Provides persistent storage for a single String value
-   `async_graphql::SimpleObject` - Makes the state queryable via GraphQL

---

## Step 3: Creating Operations

**File:** `src/lib.rs`

We defined two operations users can perform:

```rust
use async_graphql::{Request, Response};
use linera_sdk::{
    graphql::GraphQLMutationRoot,
    linera_base_types::{ContractAbi, ServiceAbi},
};
use serde::{Deserialize, Serialize};

pub struct BackendAbi;

impl ContractAbi for BackendAbi {
    type Operation = Operation;
    type Response = ();
}

impl ServiceAbi for BackendAbi {
    type Query = Request;
    type QueryResponse = Response;
}

#[derive(Debug, Deserialize, Serialize, GraphQLMutationRoot)]
pub enum Operation {
    SetMessage { message: String },
    UpdateMessage { message: String },
}
```

### Key Points:

-   `Operation` enum defines all possible mutations
-   `GraphQLMutationRoot` automatically generates GraphQL mutations
-   Both operations do the same thing - we included both for demonstration

---

## Step 4: Implementing the Contract Logic

**File:** `src/contract.rs`

The contract handles operation execution and state management:

```rust
#![cfg_attr(target_arch = "wasm32", no_main)]

mod state;

use linera_sdk::{
    linera_base_types::WithContractAbi,
    views::{RootView, View},
    Contract, ContractRuntime,
};

use backend::Operation;
use self::state::BackendState;

pub struct BackendContract {
    state: BackendState,
    runtime: ContractRuntime<Self>,
}

linera_sdk::contract!(BackendContract);

impl WithContractAbi for BackendContract {
    type Abi = backend::BackendAbi;
}

impl Contract for BackendContract {
    type Message = ();
    type Parameters = ();
    type InstantiationArgument = String;
    type EventValue = ();

    async fn load(runtime: ContractRuntime<Self>) -> Self {
        let state = BackendState::load(runtime.root_view_storage_context())
            .await
            .expect("Failed to load state");
        BackendContract { state, runtime }
    }

    async fn instantiate(&mut self, argument: Self::InstantiationArgument) {
        self.runtime.application_parameters();
        self.state.message.set(argument);
    }

    async fn execute_operation(&mut self, operation: Self::Operation) -> Self::Response {
        match operation {
            Operation::SetMessage { message } => {
                self.state.message.set(message);
            }
            Operation::UpdateMessage { message } => {
                self.state.message.set(message);
            }
        }
    }

    async fn execute_message(&mut self, _message: Self::Message) {}

    async fn store(mut self) {
        self.state.save().await.expect("Failed to save state");
    }
}
```

### Key Points:

-   `InstantiationArgument = String` - Requires an initial message when deploying
-   `execute_operation` - Handles both SetMessage and UpdateMessage
-   `store` - Persists state changes to storage

---

## Step 5: Building the GraphQL Service

**File:** `src/service.rs`

The service exposes queries and mutations via GraphQL:

```rust
#![cfg_attr(target_arch = "wasm32", no_main)]

mod state;

use std::sync::Arc;

use async_graphql::{EmptySubscription, Object, Schema};
use linera_sdk::{
    graphql::GraphQLMutationRoot, linera_base_types::WithServiceAbi, views::View, Service,
    ServiceRuntime,
};

use backend::Operation;
use self::state::BackendState;

pub struct BackendService {
    state: BackendState,
    runtime: Arc<ServiceRuntime<Self>>,
}

linera_sdk::service!(BackendService);

impl WithServiceAbi for BackendService {
    type Abi = backend::BackendAbi;
}

impl Service for BackendService {
    type Parameters = ();

    async fn new(runtime: ServiceRuntime<Self>) -> Self {
        let state = BackendState::load(runtime.root_view_storage_context())
            .await
            .expect("Failed to load state");
        BackendService {
            state,
            runtime: Arc::new(runtime),
        }
    }

    async fn handle_query(&self, query: Self::Query) -> Self::QueryResponse {
        Schema::build(
            QueryRoot {
                message: self.state.message.get().clone(),
            },
            Operation::mutation_root(self.runtime.clone()),
            EmptySubscription,
        )
        .finish()
        .execute(query)
        .await
    }
}

struct QueryRoot {
    message: String,
}

#[Object]
impl QueryRoot {
    async fn message(&self) -> &String {
        &self.message
    }
}
```

### Key Points:

-   `QueryRoot` - Defines what queries are available
-   `handle_query` - Builds the GraphQL schema dynamically
-   `Operation::mutation_root()` - Automatically generates mutations from operations

---

## Step 6: Writing Tests

**File:** `src/contract.rs` (test module)

We wrote comprehensive tests for our contract:

```rust
#[cfg(test)]
mod tests {
    use futures::FutureExt as _;
    use linera_sdk::{util::BlockingWait, views::View, Contract, ContractRuntime};

    use backend::Operation;
    use super::{BackendContract, BackendState};

    #[test]
    fn set_message_operation() {
        let initial_message = "Hello, Linera!".to_string();
        let mut app = create_and_instantiate_app(initial_message.clone());

        let new_message = "Updated message".to_string();

        let _response = app
            .execute_operation(Operation::SetMessage { message: new_message.clone() })
            .now_or_never()
            .expect("Execution of application operation should not await anything");

        assert_eq!(app.state.message.get(), &new_message);
    }

    #[test]
    fn update_message_operation() {
        let initial_message = "Hello, Linera!".to_string();
        let mut app = create_and_instantiate_app(initial_message.clone());

        let updated_message = "Message updated successfully".to_string();

        let _response = app
            .execute_operation(Operation::UpdateMessage { message: updated_message.clone() })
            .now_or_never()
            .expect("Execution of application operation should not await anything");

        assert_eq!(app.state.message.get(), &updated_message);
    }

    fn create_and_instantiate_app(initial_message: String) -> BackendContract {
        let runtime = ContractRuntime::new().with_application_parameters(());
        let mut contract = BackendContract {
            state: BackendState::load(runtime.root_view_storage_context())
                .blocking_wait()
                .expect("Failed to read from mock key value store"),
            runtime,
        };

        contract
            .instantiate(initial_message.clone())
            .now_or_never()
            .expect("Initialization of application state should not await anything");

        assert_eq!(contract.state.message.get(), &initial_message);

        contract
    }
}
```

---

## Step 7: Building for WebAssembly

### Build Command

```bash
cd backend
cargo build --release --target wasm32-unknown-unknown
```

This compiles your Rust code to WebAssembly bytecode that can run on Linera validators.

### Output Files

The build creates two WASM files:

-   `target/wasm32-unknown-unknown/release/backend_contract.wasm` - Contract bytecode
-   `target/wasm32-unknown-unknown/release/backend_service.wasm` - Service bytecode

---

## Step 8: Deploying to Testnet

### Setup Wallet and Chain

```bash
# Initialize wallet
linera wallet init --faucet https://faucet.testnet-conway.linera.net

# Request a new chain with tokens
linera wallet request-chain --faucet https://faucet.testnet-conway.linera.net
```

### Deploy the Application

The critical part is the `--json-argument` flag:

```bash
linera publish-and-create \
  target/wasm32-unknown-unknown/release/backend_{contract,service}.wasm \
  --json-argument '"Hello, Linera!"'
```

### Common Deployment Issues We Solved

#### Issue 1: Missing JSON Argument

❌ **Error:** `Failed to deserialize instantiation argument [110, 117, 108, 108]`

**Solution:** Always provide the `--json-argument` flag with a properly formatted JSON string.

#### Issue 2: Malformed JSON String

❌ **Error:** `EOF while parsing a string at line 1 column 14`

**Cause:**

```bash
--json-argument "\"Hello, Linera"  # Missing closing quotes!
```

✅ **Solution:**

```bash
--json-argument '"Hello, Linera!"'  # Single quotes outside, double inside
```

---

## Step 9: Interacting with Your Application

### Start the Node Service

```bash
linera service --port 8080
```

**Common Issue:** Port already in use

```
Error is Address already in use (os error 48)
```

**Solution:** Use a different port

```bash
linera service --port 8081
```

### Access GraphiQL

Navigate to:

```
http://localhost:8080/chains/<CHAIN_ID>/applications/<APP_ID>
```

For our deployment:

```
http://localhost:8080/chains/d79aa094242881a3727d36ac12d026caf886438041784b70448fe13adeb3afd4/applications/eab9b22ac9c1e177ffa821937bb6cfdcdd7107860ca40bd9476e461d5804177e
```

### Query the Message

```graphql
query {
    message
}
```

**Response:**

```json
{
    "data": {
        "message": "Hello, Linera!"
    }
}
```

### Update the Message

```graphql
mutation {
    setMessage(message: "My updated message!")
}
```

### Verify the Update

```graphql
query {
    message
}
```

**Response:**

```json
{
    "data": {
        "message": "My updated message!"
    }
}
```

---

## Key Takeaways

### ✅ What We Learned

1. **Linera Architecture**

    - Contracts handle state mutations (write operations)
    - Services provide read-only access via GraphQL
    - Both compile to WebAssembly

2. **State Management**

    - Use `RegisterView<T>` for single values
    - State persists across sessions
    - Each mutation creates a new block

3. **GraphQL Integration**

    - Operations automatically become mutations
    - State fields automatically become queries
    - GraphiQL provides interactive exploration

4. **Deployment Process**

    - Build for `wasm32-unknown-unknown` target
    - Initialize wallet and request chain
    - Deploy with `publish-and-create`
    - Provide initialization arguments as JSON

5. **Testing**
    - Write unit tests in contract modules
    - Test operations and state changes
    - Use Linera's testing utilities

### 🎯 Best Practices

1. **Always provide initialization arguments** when deploying (unless Optional)
2. **Use single quotes** for JSON arguments to avoid escaping issues
3. **Test locally** before deploying to testnet
4. **Keep operations simple** - complex logic can be expensive
5. **Use descriptive names** for operations and state fields

### 🚀 Next Steps

-   Add more complex state (multiple fields, collections)
-   Implement cross-chain messaging
-   Add event emission for notifications
-   Build a frontend to interact with the contract
-   Explore advanced features like cross-application calls

---

## Complete File Reference

### Cargo.toml

```toml
[package]
name = "backend"
version = "0.1.0"
edition = "2021"

[dependencies]
async-graphql = { version = "=7.0.17", default-features = false }
linera-sdk = "0.15.3"
futures = { version = "0.3 "}
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }

[dev-dependencies]
linera-sdk = { version = "0.15.3", features = ["test", "wasmer"] }
tokio = { version = "1.40", features = ["rt", "sync"] }

[[bin]]
name = "backend_contract"
path = "src/contract.rs"

[[bin]]
name = "backend_service"
path = "src/service.rs"

[profile.release]
debug = true
lto = true
opt-level = 'z'
strip = 'debuginfo'
```

---

## Useful Commands Reference

```bash
# Build the application
cargo build --release --target wasm32-unknown-unknown

# Run tests
cargo test

# Initialize wallet (first time)
linera wallet init --faucet https://faucet.testnet-conway.linera.net

# Request a chain
linera wallet request-chain --faucet https://faucet.testnet-conway.linera.net

# Deploy application
linera publish-and-create \
  target/wasm32-unknown-unknown/release/backend_{contract,service}.wasm \
  --json-argument '"Your initial message"'

# Start node service
linera service --port 8080

# Check wallet status
linera wallet show

# Sync with network
linera sync

# Query chain balance
linera query-balance
```

---

## Resources

-   [Linera Developer Documentation](https://linera.dev)
-   [Linera SDK Documentation](https://docs.rs/linera-sdk)
-   [GraphQL Documentation](https://graphql.org/learn/)
-   [Linera GitHub Repository](https://github.com/linera-io/linera-protocol)

---

**Built with 💙 by vibecoding on Linera**

_Remember: Every mutation creates a block, every query reads state, and every deployment is permanent. Code with intention!_ 🚀
