Cost Model

Pricing of compute leases

[!WARNING] Work in progress The rates and constants on this page are placeholder values for development and testing. Final pricing, rate ratios, and economic parameters are still under design review and will change before production.

Lease pricing is fully deterministic. The cost is computed from the resource dimensions, the duration, and the provider's certificate price multiplier, using integer arithmetic in micro-XUSD (1 XUSD = 1,000,000 µXUSD). The ledger validates that every lease block carries the exact cost produced by this formula -- no negotiation, no rounding errors.

Formula

The rates are already denominated in micro-XUSD per hour, so the unscaled product lands directly in micro-XUSD. The provider's price multiplier is applied last, with a single ceiling divide:

perHourMicro = vCPUs x 20_000 + ceil(memoryMB / 1024) x 10_000 + diskGB x 1_000
hours        = ceil(duration / 3600)
costMicro    = perHourMicro x hours
cost         = ceil(costMicro x multiplierMilli / 1000)     // minimum 1 µXUSD

multiplierMilli is the provider's price multiplier scaled ×1000 (1000 = 1.000×), read from the performance certificate the lease block references. See Performance Evaluation.

In Go:

func LeaseCost(vcpus, memoryMB, diskGB, duration, multiplierMilli uint64) (uint64, error) {
    hours := (duration + 3599) / 3600
    memGB := (memoryMB + 1023) / 1024
    perHourMicro := vcpus*LeaseVCPURate + memGB*LeaseMemGBRate + diskGB*LeaseDiskGBRate
    costMicro, ok := safeMul(perHourMicro, hours)   // overflow-checked
    scaled, ok := safeMul(costMicro, multiplierMilli)
    cost := ceilDiv(scaled, 1000)                   // ceiling divide
    if cost == 0 { cost = 1 }
    return cost, nil
}

Rate table

Resource

Rate

Unit

vCPU

20,000 µXUSD (0.02 XUSD)

per vCPU per hour

Memory

10,000 µXUSD (0.01 XUSD)

per GB per hour (rounded up to nearest GB)

Disk

1,000 µXUSD (0.001 XUSD)

per GB per hour

[!NOTE] Rounding Memory is rounded up to the nearest GB: 1025 MB counts as 2 GB. Duration is rounded up to the nearest hour: 3601 seconds counts as 2 hours. The multiplier scaling is ceiling-divided. All rounding uses integer ceiling division and always rounds up, consistently.

Derived values

Value

Formula

Description

Cost

See above

µXUSD debited from the consumer into escrow

Stake

ceil(cost / 5) (min 1 µXUSD)

µXUSD locked by the provider as collateral

XE emission

ceil(cost x R_capped / 1000) (min 1 µXE)

micro-XE minted to the provider on settlement

The stake uses ceiling division (LeaseStake): a cost of 7 µXUSD yields a stake of 2 µXUSD. The minimum stake is 1 µXUSD regardless of cost. The XE emission is not the same number as the cost — it scales the cost by the emission rate R that was locked onto the lease at acceptance. See Economics.

Constants

const (
    LeaseVCPURate     = 20_000    // micro-XUSD per vCPU per hour
    LeaseMemGBRate    = 10_000    // micro-XUSD per GB memory per hour
    LeaseDiskGBRate   = 1_000     // micro-XUSD per GB disk per hour
    LeaseStakeDivisor = 5         // stake = ceil(cost / 5), min 1
    LeaseMaxDuration  = 31536000  // maximum 365 days
)

// Genesis-pinned; the value below is the production default (#524).
DefaultLeaseMinDuration = 60      // minimum 1 minute

[!IMPORTANT] Minimum duration is a network parameter LeaseMinDuration is pinned by the genesis block, defaulting to the production value of 60 seconds. A network can pin a different value at genesis, so read the live value from GET /node (lease_timing.min_duration_secs) rather than assuming a compiled-in constant. LeaseMaxDuration is a protocol constant and is not genesis-pinned.

Examples

All rows assume a baseline price multiplier of 1000 (1.000×).

vCPUs

Memory

Disk

Duration

Per-hour µXUSD

Hours

Cost (µXUSD)

Cost (XUSD)

Stake (µXUSD)

1

1024 MB

1 GB

60s

20,000+10,000+1,000 = 31,000

1

31,000

0.031

6,200

1

512 MB

5 GB

120s

20,000+10,000+5,000 = 35,000

1

35,000

0.035

7,000

2

2048 MB

20 GB

3600s

40,000+20,000+20,000 = 80,000

1

80,000

0.08

16,000

4

8192 MB

100 GB

3600s

80,000+80,000+100,000 = 260,000

1

260,000

0.26

52,000

2

4096 MB

50 GB

86400s

40,000+40,000+50,000 = 130,000

24

3,120,000

3.12

624,000

8

16384 MB

200 GB

86400s

160,000+160,000+200,000 = 520,000

24

12,480,000

12.48

2,496,000

4

8192 MB

100 GB

2592000s

80,000+80,000+100,000 = 260,000

720

187,200,000

187.2

37,440,000

[!EXAMPLE] Worked example: 1 vCPU, 1 GB RAM, 10 GB disk for 1 day at 1.000×

Per-hour micro = (1 x 20_000) + ceil(1024/1024) x 10_000 + 10 x 1_000
               = 20_000 + 10_000 + 10_000
               = 40_000 µXUSD/hour

Hours          = ceil(86400 / 3600) = 24

Cost micro     = 40_000 x 24 = 960_000

Cost           = ceil(960_000 x 1000 / 1000) = 960_000 µXUSD = 0.96 XUSD
Stake          = ceil(960_000 / 5) = 192_000 µXUSD = 0.192 XUSD

This is the target case documented in the source: 960,000 µXUSD = 24 h × (20,000 + 10,000 + 10×1,000).

Validation

The ledger enforces the following invariants:

Check

Rule

Certificate required

The lease block must carry a certificate_hash for an unexpired certificate belonging to the destination provider

Cost matches formula

lease.Amount == LeaseCost(vcpus, memoryMB, diskGB, duration, cert.PriceMultiplierMilli)

Stake matches formula

lease_accept.Amount == ceil(cost / LeaseStakeDivisor) (min 1 µXUSD)

Rate lock

lease_accept.CertificateHash must equal the certificate hash the consumer referenced on the lease block

XE emission matches formula

lease_settle.Amount == ceil(cost x R_capped / 1000), using the emission parameters locked onto the lease at acceptance

Duration in range

LeaseMinDuration <= duration <= 31,536,000 seconds

Resources non-zero

At least one resource dimension must be > 0

No overflow

Multiplication uses safeMul() with overflow detection via bits.Mul64

Integer arithmetic

All calculations use uint64 -- no floating point

[!WARNING] Overflow protection The cost calculation uses bits.Mul64 to detect overflow. If perHourMicro * hours (or the multiplier scaling) would exceed uint64 max, the lease is rejected. This prevents absurdly large resource requests from wrapping around.