Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion BUILDERS_FORGE_RULES_S1.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ To ensure fairness and quality, all participants must follow the guidelines belo

- All tasks in our [Github](https://github.com/cedra-labs/docs/issues) with special `Builders Forge` label
- All code and documentation must be in English
- No copy-paste β€” all work must be original
- No copy-paste - all work must be original
- One GitHub account per participant
- Team submissions allowed, but rewards are per task, not per person
- Submit all work through a GitHub Pull Request (PR)
Expand Down
2 changes: 2 additions & 0 deletions docs/cli/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ cedra move test

This will compile the package (in test mode) and run all tests in your code. Output will show which tests passed or failed, along with any debug prints or assertions from the tests. Use this to verify your module's logic off-chain before deploying.

For comprehensive testing documentation including test annotations, expected failures, and best practices, see [Move Unit Testing](/move/testing).

### πŸš€ Publishing Move Modules to the Blockchain

For packages exceeding 64KB, see [Deploying Large Packages](/large-packages).
Expand Down
124 changes: 124 additions & 0 deletions docs/concepts/accounts/authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Account Authentication

Authentication on Cedra is more flexible than most blockchains. The separation between address and authentication key means you can rotate your keys without changing your account identity - similar to changing a password without creating a new username. Cedra also supports multiple cryptographic schemes and native multisig, all built into the protocol rather than implemented through smart contracts.

:::tip Navigation
**Previous:** [Understanding Accounts](/concepts/accounts/understanding-accounts)
**You are here:** Authentication
**Next:** [Resources](/concepts/accounts/resources)
:::

### Authentication Key vs Address

When you first create an account, your authentication key becomes your address. But here's the key insight: while the address is permanent, the authentication key can change.

The authentication key is what proves you own the account - it's derived from your public key and verified when you sign transactions. If your private key is compromised or you simply want better security, you can rotate to a new authentication key while keeping your existing address, balances, and resources.

```mermaid
graph LR
subgraph "Initial State"
A[Auth Key] -->|equals| B[Address]
end

subgraph "After Rotation"
C[New Auth Key] -->|authenticates| D[Same Address]
end

B --> D
```

The network maintains an on-chain mapping that tracks these rotations, so it knows which authentication key currently controls each address.

## Authentication Schemes

Cedra supports multiple cryptographic schemes for signing transactions. Each scheme uses a different algorithm to derive the authentication key from the public key.

### Ed25519 (Default)

The most common choice, using the Ed25519 elliptic curve. The authentication key is computed as:

```
auth_key = sha3-256(public_key | 0x00)
```

The `0x00` suffix is the scheme identifier that distinguishes Ed25519 from other schemes. Ed25519 offers fast signature verification and is well-suited for most use cases.

### Secp256k1 ECDSA

The same curve used by Bitcoin and Ethereum. If you're migrating from those ecosystems or want compatibility with existing tooling, Secp256k1 is available:

```
auth_key = sha3-256(0x01 | public_key | 0x02)
```

### MultiEd25519 (K-of-N Multisig)

For accounts requiring multiple signatures, Cedra supports K-of-N multisig natively. You specify N public keys and require K of them to sign any transaction:

```
auth_key = sha3-256(pubkey_1 | pubkey_2 | ... | pubkey_n | K | 0x01)
```

For example, a 2-of-3 multisig would have three public keys concatenated, followed by the threshold value 2, then the scheme identifier.

## Native Multisig Support

Unlike Ethereum where multisig requires deploying a smart contract, Cedra's multisig is built into the protocol. This means:

- **Lower gas costs** - No contract deployment or extra execution overhead
- **Simpler setup** - Just combine public keys and set a threshold
- **Mixed key types** - Combine Ed25519, Secp256k1, WebAuthn in one multisig
- **No contract risk** - No smart contract bugs to worry about

A transaction from a multisig account includes multiple signatures. The network verifies that at least K of the N authorized keys have signed before accepting the transaction.

```mermaid
graph TD
subgraph "2-of-3 Multisig"
A[Transaction] --> B{Collect Signatures}
B --> C[Signer 1: Ed25519]
B --> D[Signer 2: Secp256k1]
B --> E[Signer 3: Ed25519]
C --> F{K signatures?}
D --> F
F -->|Yes, 2 of 3| G[Valid Transaction]
end
```


## Key Rotation

Key rotation lets you change the authentication key controlling your account while keeping the same address. This is essential for:

- **Compromised keys** - If you suspect your private key was exposed, rotate immediately
- **Security upgrades** - Move from a single key to multisig, or upgrade to a hardware wallet
- **Organizational changes** - When team members change, rotate the controlling keys

The rotation process uses the `account::rotate_authentication_key` function. You sign the rotation request with your current key to prove ownership, and specify the new authentication key that should take over.

```mermaid
sequenceDiagram
participant Owner
participant Account
participant Network

Owner->>Account: Sign rotation with current key
Owner->>Account: Specify new auth key
Account->>Network: Submit rotation transaction
Network->>Network: Verify current key signature
Network->>Network: Update auth key mapping
Network->>Owner: Confirmation
Note over Owner,Network: Old key no longer works<br/>New key now controls account
```

After rotation, the old key can no longer sign transactions for this account. The address remains unchanged, so all your resources, module references, and history stay intact.

:::info Rotation Tracking
The network maintains an on-chain `OriginatingAddress` table that maps authentication keys to their original addresses. This ensures that even after multiple rotations, the account's identity remains consistent.
:::

## Next Steps

- [Resources](/concepts/accounts/resources) - How Move resources are stored within accounts
- [Understanding Accounts](/concepts/accounts/understanding-accounts) - Account fundamentals
- [Transactions](/concepts/transactions/understanding-transactions) - How authenticated accounts interact with the network
214 changes: 214 additions & 0 deletions docs/concepts/accounts/resources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# Move Resources

On Cedra, all on-chain state is organized into resources and modules stored within accounts. This is fundamentally different from Ethereum's model where each smart contract maintains its own storage. In Cedra, your tokens live in your account, not in a contract's storage - and this per-account model is what enables parallel transaction execution.

:::tip Navigation
**Previous:** [Authentication](/concepts/accounts/authentication)
**You are here:** Resources
**Overview:** [Understanding Accounts](/concepts/accounts/understanding-accounts)
:::

## Resources vs Instances

Move distinguishes between two types of storable data based on their abilities.

A **resource** has the `key` ability, meaning it can be stored directly under an account address. Resources are top-level citizens - you can query them directly by account address and type.

An **instance** has the `store` ability, meaning it can be stored within other resources but not directly under an account. Instances are nested data that lives inside resources.

```move
module 0x1::coin {
/// Resource - stored directly under account (has `key`)
struct CoinStore<phantom CoinType> has key {
coin: Coin<CoinType>,
}

/// Instance - stored within CoinStore (has `store`)
struct Coin<phantom CoinType> has store {
value: u64,
}
}
```

In this example, `CoinStore` is the resource that lives under your account. It contains a `Coin` instance that holds the actual balance. You can't store a `Coin` directly under an account - it must be wrapped in something with the `key` ability.

```mermaid
graph TD
subgraph "Account 0xABC"
A[CoinStore&lt;CED&gt;] -->|contains| B[Coin: 1000]
C[CoinStore&lt;USDC&gt;] -->|contains| D[Coin: 500]
end

style A fill:#e1f5fe
style C fill:#e1f5fe
style B fill:#fff3e0
style D fill:#fff3e0
```

## Defining Resources

When you define a resource, you're specifying its structure, abilities, and the module that governs it.

```move
module 0x1234::token {
struct TokenStore has key {
tokens: vector<Token>,
frozen: bool,
}

struct Token has store, drop {
id: u64,
metadata: vector<u8>,
}
}
```

The fully qualified path to this resource is `0x1234::token::TokenStore`. When you want to access it, you need three pieces of information:

- **Address**: `0x1234` - where the module is deployed
- **Module**: `token` - the module name
- **Resource**: `TokenStore` - the struct name with `key` ability

## Resource Permissions

The module that defines a resource controls all operations on it. This is Move's core security model - only the defining module can:

- Create new instances (`move_to`)
- Destroy instances (`move_from`)
- Borrow references (`borrow_global`, `borrow_global_mut`)

External modules and users can only interact with resources through the public functions that the defining module exposes. The internal state of a resource is completely protected.

```move
module 0x1::coin {
struct Balance has key { value: u64 }

/// Only this module can create balances
public fun initialize(account: &signer) {
move_to(account, Balance { value: 0 });
}

/// Only this module can modify balances
public fun deposit(addr: address, amount: u64) acquires Balance {
let balance = borrow_global_mut<Balance>(addr);
balance.value = balance.value + amount;
}

/// External code can read but not modify
public fun get_balance(addr: address): u64 acquires Balance {
borrow_global<Balance>(addr).value
}
}
```

This means "ownership" in Move is not just about where data is stored - it's about which module has permission to modify it. A token might be stored under your account, but only the token module's code can change its value.

## Storage Location

Resources live within the accounts that own them. When Alice holds CED tokens, the `CoinStore<CED>` resource is stored under Alice's address, not under some global contract address.

To query a resource, you need the owner's address plus the resource type:

```
Account: 0xALICE
Resource: 0x1::coin::CoinStore<0x1::ced::CED>
```

You can view resources through:
- The Cedra Explorer - enter any address to see its resources
- Fullnode REST API - `GET /accounts/{address}/resources`
- SDK calls - `client.getAccountResource(address, resourceType)`

```mermaid
graph LR
subgraph "Query"
A[Account Address] --> B[Resource Type]
B --> C[Resource Data]
end

subgraph "Example"
D["0xALICE"] --> E["0x1::coin::CoinStore"]
E --> F["{ coin: { value: 1000 } }"]
end
```

## Parallel Execution Benefits

This per-account storage model is why Cedra can execute transactions in parallel. When Alice sends tokens to Bob while Carol sends tokens to Dave, these transactions touch completely different storage locations:

- Alice's transaction: reads/writes Alice's `CoinStore`, writes Bob's `CoinStore`
- Carol's transaction: reads/writes Carol's `CoinStore`, writes Dave's `CoinStore`

No overlap means no conflicts, so both transactions can execute simultaneously.

```mermaid
graph TD
subgraph "Parallel Execution"
subgraph "Thread 1"
A1[Alice's CoinStore] --> B1[Bob's CoinStore]
end
subgraph "Thread 2"
A2[Carol's CoinStore] --> B2[Dave's CoinStore]
end
end

style A1 fill:#e8f5e9
style B1 fill:#e8f5e9
style A2 fill:#e3f2fd
style B2 fill:#e3f2fd
```

Compare this to Ethereum, where all ERC-20 transfers go through a single contract's storage. Every transfer must access the same contract state, creating a bottleneck that prevents parallel execution.

:::info Events and Receivers
Events can also be stored in the receiver's account rather than emitted globally. This further reduces contention - Alice receiving tokens triggers an event stored under Alice's account, not in some shared event log.
:::

## Working with Resources

Here's how you interact with resources in Move code:

```move
module 0x1::example {
struct Counter has key {
value: u64,
}

/// Create a new counter under the signer's account
public fun create(account: &signer) {
move_to(account, Counter { value: 0 });
}

/// Check if an account has a counter
public fun exists_at(addr: address): bool {
exists<Counter>(addr)
}

/// Read the counter value
public fun get(addr: address): u64 acquires Counter {
borrow_global<Counter>(addr).value
}

/// Increment the counter (requires signer for access control)
public fun increment(account: &signer) acquires Counter {
let addr = signer::address_of(account);
let counter = borrow_global_mut<Counter>(addr);
counter.value = counter.value + 1;
}

/// Remove and destroy the counter
public fun destroy(account: &signer) acquires Counter {
let addr = signer::address_of(account);
let Counter { value: _ } = move_from<Counter>(addr);
}
}
```

The `acquires` annotation tells the compiler which resources a function accesses. This enables compile-time checking and helps with parallel execution planning.

## Next Steps

- [Understanding Accounts](/concepts/accounts/understanding-accounts) - Account fundamentals and types
- [Authentication](/concepts/accounts/authentication) - How accounts prove ownership
- [Move Resource Types](/move/resource) - Deep dive into resource programming
- [Block-STM](/concepts/block-stm) - How per-account storage enables parallel execution
Loading