Skip to content

How to run a storage provider

A storage provider is a node that stores bags for a fee, backed by an on-chain smart contract. The TON Storage overview covers the trust model and proof challenges; the TON Storage reference documents every command and flag used below.

The provider system has two components:

  • Smart contract: deployed on the TON Blockchain, stores the Merkle root hash of each bag, issues proof challenges, and manages client payments.
  • storage-daemon: runs on the provider machine, downloads bags, serves data to peers, and submits storage proofs to the contract.
  1. The provider deploys a main smart contract and shares its address with clients.
  2. A client creates a bag and sends a storage request to the provider contract.
  3. The provider contract deploys a per-bag storage contract and notifies the client.
  4. The provider downloads the bag and activates the per-bag contract.
  5. The client transfers payment. The provider submits periodic Merkle proofs to prove data possession.
  6. When the client balance reaches zero or either party closes the contract, remaining funds return to the client and the contract self-destructs.
  • storage-daemon and storage-daemon-cli from the TON releases page (v2024.01 or newer), running with the -P flag per Storage daemon
  • A wallet with sufficient TON to cover the contract deployment fee and initial operating balance
  • The wallet private key available for import into the daemon

The storage provider contract is controlled by a key managed by the daemon. Import the private key of the wallet that will fund contract deployment:

Terminal window
import-pk <PRIVATE_KEY_FILE>

Run deploy-provider in the CLI. The daemon generates a new Ed25519 key pair, constructs the provider contract state init, and sends a deployment message:

Terminal window
deploy-provider

The default initial parameters set in the contract (source: storage/storage-daemon/smc-util.cpp):

  • accept_new_contracts: false (must be enabled explicitly)
  • rate_per_mb_day: 1,000,000 nanoTON per MB per day (1 MB = 10⁶ bytes, source: storage-daemon-cli.cpp help text nanoTON per MB*day)
  • max_span: 86,400 seconds (1 day between proof submissions)
  • min_file_size: 1,048,576 bytes (2²⁰, one binary megabyte)
  • max_file_size: 1,073,741,824 bytes (2³⁰, one binary gigabyte)

After deployment the daemon prints the contract address. Save it; clients need it to send storage requests.

To use an existing deployed contract instead of deploying a new one:

Terminal window
init-provider <CONTRACT_ADDRESS>

Set the pricing and acceptance parameters on the deployed contract:

Terminal window
set-provider-params --accept 1 --rate <NANOTON_PER_MB_DAY> --max-span <SECONDS>

Example, set rate to 10,000,000 nanoTON per MB per day and accept new contracts:

Terminal window
set-provider-params --accept 1 --rate 10000000 --max-span 86400

All set-provider-params flags (source: storage/storage-daemon/storage-daemon-cli.cpp):

  • --accept 0|1 : stop or start accepting new storage contracts.
  • --rate <X>: price in nanoTON per MB per day.
  • --max-span <X> : maximum seconds between required proof submissions.
  • --min-file-size <X> : minimum bag size in bytes (supports size suffixes: k, m, g).
  • --max-file-size <X> : maximum bag size in bytes.

Control how many contracts the daemon manages locally (these limits do not affect the on-chain contract):

Terminal window
set-provider-config --max-contracts 500 --max-total-size 50g
  • --max-contracts : maximum number of active storage contracts (default: 1000).
  • --max-total-size : maximum total stored bytes across all contracts (default: 128g).

Check that the contract is deployed and accepting:

Terminal window
get-provider-params

Check active contracts and balances:

Terminal window
get-provider-info --balances --contracts

An output showing accept_new_contracts: true and the configured rate confirms the provider is ready.

Give clients the contract address returned by deploy-provider. Clients use it to construct a new storage contract message via:

Terminal window
new-contract-message <BAG_ID> <OUTPUT_FILE> --provider <CONTRACT_ADDRESS>

This fetches the current rate and max_span from the contract and writes the message body to <OUTPUT_FILE> for the client to send.

Collect earnings from individual storage contracts to the main contract:

Terminal window
withdraw <STORAGE_CONTRACT_ADDRESS>

Collect from all contracts that hold at least 1 TON:

Terminal window
withdraw-all

Send TON from the main contract to an external address:

Terminal window
send-coins <ADDRESS> <AMOUNT_NANOTON>
  • deploy-provider fails: check that the daemon started with -P and that the wallet key was imported with import-pk before deploying.
  • Storage provider is not enabled: restart the daemon with the --storage-provider (-P) flag.
  • Proof submission errors: verify that the daemon has network connectivity and that the global config points to live liteservers. Check daemon logs at verbosity level 4 or higher.
  • Contract not receiving clients: confirm accept_new_contracts is set to 1 via get-provider-params. Confirm the contract address shared with clients is correct.
  • remove-storage-provider: removes the provider from the daemon without affecting on-chain contracts. Existing bags and contracts continue to exist on-chain but will no longer be managed.