One command gives you a local Stellar network with the lending contract deployed, initialized and seeded with positions:
npm run devnet| Tool | Version | Why |
|---|---|---|
| Docker | any recent | runs the stellar/quickstart node |
| stellar CLI | ≥ 25.2.0 | soroban-sdk 27 contracts only build with stellar contract build from 25.2+ |
Rust + wasm32v1-none target |
stable | rustup target add wasm32v1-none |
| curl | any | friendbot funding, health checks |
Install the CLI with cargo install --locked stellar-cli, or see the
Stellar docs.
scripts/devnet/bootstrap.sh:
-
Starts a quickstart node with
stellar container start local --limits unlimited(RPC athttp://localhost:8000/rpc). Theunlimitedlimits let the full lending wasm deploy. -
Creates and funds identities
sl-admin,sl-alice,sl-bobandsl-carolthrough friendbot. -
Builds and deploys the lending contract.
-
Resolves the native XLM asset contract and deploys a
USDC:<admin>asset contract. -
Initializes the protocol (1,000,000 USDC debt ceiling, 1 USDC minimum borrow) and seeds:
user positions alice 50,000 XLM vault deposit; 25,000 USDC borrow against 50,000 XLM (200%) bob 40,000 USDC borrow against 60,000 XLM (exactly the 150% minimum) carol 20,000 XLM deposit; 5,000 USDC borrow against 10,000 XLM; 2,000 USDC repaid -
Enables the utilization circuit breaker (trip 90%, reset 80%, 10,000 USDC per borrow while tripped).
-
Prints each position read back from the contract, then writes
.devnet/state.json:
{
"network": { "rpcUrl": "...", "networkPassphrase": "...", "friendbotUrl": "..." },
"contracts": { "lending": "C...", "lendingWasmHash": "...", "xlm": "C...", "usdc": "C..." },
"accounts": { "admin": { "identity": "sl-admin", "address": "G..." }, "...": {} }
}Running it again against a live devnet does nothing except print the summary.
| Command | Effect |
|---|---|
npm run devnet |
Bootstrap, or print the summary if already up |
npm run devnet:reset |
Stop the node, delete .devnet/, bootstrap from an empty ledger |
npm run devnet:rehearse-upgrade |
Rehearse an upgrade and rollback (runbook) |
npm run devnet:faucet -- <name|address>... |
Fund accounts with XLM and devnet USDC (Faucet) |
bash scripts/devnet/bootstrap.sh --dry-run |
Print every command without running anything |
bash scripts/devnet/bootstrap.sh --no-node |
Use an RPC you already run (e.g. docker/devnet compose) |
bash scripts/devnet/bootstrap.sh --skip-build |
Deploy the existing wasm |
npm run test:devnet |
Plan tests for the scripts (no network needed) |
Environment overrides: DEVNET_RPC_URL, DEVNET_FRIENDBOT_URL, DEVNET_PASSPHRASE,
DEVNET_CONTAINER, DEVNET_KEY_PREFIX, DEVNET_STATE_DIR, DEVNET_WASM,
DEVNET_HEALTH_TIMEOUT.
Fund any number of accounts with XLM and devnet USDC in one command, against the
devnet recorded in .devnet/state.json:
npm run devnet:faucet -- sl-dave # create sl-dave if needed, 10,000 USDC
npm run devnet:faucet -- sl-dave sl-erin --usdc 500
npm run devnet:faucet -- GABC... # existing account (must trust USDC)
npm run devnet:faucet -- CABC... --no-xlm # contract: USDC onlyFor each target, scripts/devnet/faucet.sh:
- Generates the identity with
stellar keys generateif the name doesn't exist yet. - Funds accounts (
G...) with XLM through friendbot. Contracts are skipped, and so are accounts friendbot already funded. - Adds a
USDC:<admin>trustline for identities, signed with their own key. - Has
sl-adminmint the USDC through the USDC asset contract.
It prints one <target> <address> line per target on stdout, so scripts can capture
the new addresses.
| Option | Effect |
|---|---|
--usdc <amount> |
Whole USDC per target (default 10,000; 0 skips USDC) |
--no-xlm |
Skip friendbot |
--dry-run |
Print every command without running anything |
The faucet can't add a trustline to a raw G... address because it doesn't hold that
key, so the mint fails with a hint until the account trusts USDC:<admin>. Create the
account as an identity instead (npm run devnet:faucet -- <name>) to have it done for
you. The same DEVNET_* overrides as bootstrap.sh apply.
LENDING=$(grep -oE '"lending": "[^"]+"' .devnet/state.json | cut -d'"' -f4)
USDC=$(grep -oE '"usdc": "[^"]+"' .devnet/state.json | cut -d'"' -f4)
NET=(--rpc-url http://localhost:8000/rpc --network-passphrase "Standalone Network ; February 2017")
# read (simulated, free)
stellar contract invoke --id "$LENDING" --source sl-alice "${NET[@]}" --send=no -- \
get_user_position --user "$(stellar keys address sl-alice)"
# write: bob repays 1 USDC
stellar contract invoke --id "$LENDING" --source sl-bob "${NET[@]}" -- \
repay --user "$(stellar keys address sl-bob)" --asset "$USDC" --amount 10000000From TypeScript, point SorobanRpcAdapter from the
SDK examples at state.json's rpcUrl and
contracts.lending.
| Symptom | Fix |
|---|---|
soroban-sdk requires stellar-cli v25.2.0+ |
Upgrade the CLI. Plain cargo build is refused by the SDK. |
RPC not healthy after 180s |
First boot downloads the image; raise DEVNET_HEALTH_TIMEOUT or check docker logs stellar-local |
| Deploy fails with a size or resource limit | The node was started without --limits unlimited; run npm run devnet:reset |
| Stale contract ids after restarting Docker | Quickstart's local ledger is ephemeral: run npm run devnet:reset |
docker/devnet/ is the full-stack compose environment (API, oracle, Postgres, Redis).
To run the full stack on top of a contract deployment from this script, start the compose
stack and bootstrap against its node:
(cd docker/devnet && docker compose up -d soroban-devnet)
DEVNET_RPC_URL=http://localhost:8000/soroban/rpc bash scripts/devnet/bootstrap.sh --no-node