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.
How providers work
Section titled “How providers work”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.
Provider workflow
Section titled “Provider workflow”- The provider deploys a main smart contract and shares its address with clients.
- A client creates a bag and sends a storage request to the provider contract.
- The provider contract deploys a per-bag storage contract and notifies the client.
- The provider downloads the bag and activates the per-bag contract.
- The client transfers payment. The provider submits periodic Merkle proofs to prove data possession.
- When the client balance reaches zero or either party closes the contract, remaining funds return to the client and the contract self-destructs.
Prerequisites
Section titled “Prerequisites”storage-daemonandstorage-daemon-clifrom the TON releases page (v2024.01 or newer), running with the-Pflag 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
Import the wallet key
Section titled “Import the wallet key”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:
import-pk <PRIVATE_KEY_FILE>Deploy the provider contract
Section titled “Deploy the provider contract”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:
deploy-providerThe 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,000nanoTON per MB per day (1 MB = 10⁶ bytes, source:storage-daemon-cli.cpphelp textnanoTON per MB*day)max_span:86,400seconds (1 day between proof submissions)min_file_size:1,048,576bytes (2²⁰, one binary megabyte)max_file_size:1,073,741,824bytes (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:
init-provider <CONTRACT_ADDRESS>Configure pricing
Section titled “Configure pricing”Set the pricing and acceptance parameters on the deployed contract:
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:
set-provider-params --accept 1 --rate 10000000 --max-span 86400All 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.
Configure daemon limits
Section titled “Configure daemon limits”Control how many contracts the daemon manages locally (these limits do not affect the on-chain contract):
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).
Verify
Section titled “Verify”Check that the contract is deployed and accepting:
get-provider-paramsCheck active contracts and balances:
get-provider-info --balances --contractsAn output showing accept_new_contracts: true and the configured rate confirms the provider is ready.
Share address with clients
Section titled “Share address with clients”Give clients the contract address returned by deploy-provider. Clients use it to construct a new storage contract message via:
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.
Withdraw earnings
Section titled “Withdraw earnings”Collect earnings from individual storage contracts to the main contract:
withdraw <STORAGE_CONTRACT_ADDRESS>Collect from all contracts that hold at least 1 TON:
withdraw-allSend TON from the main contract to an external address:
send-coins <ADDRESS> <AMOUNT_NANOTON>Troubleshoot
Section titled “Troubleshoot”deploy-providerfails: check that the daemon started with-Pand that the wallet key was imported withimport-pkbefore 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_contractsis set to1viaget-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.