A quick, step-by-step verification flow for confirming that a deployed
savings_vault contract responds correctly to every public function. Run
this after deployment to catch configuration or initialization problems
before deeper integration testing.
This guide targets testnet or a local Soroban sandbox. It is not a full walkthrough — see docs/walkthrough.md for a detailed lifecycle example with state explanations.
This contract is for educational and testnet use. See the README's Security Considerations.
Before starting, ensure you have:
- Rust (latest stable), Soroban CLI, and the wasm32-unknown-unknown target installed — see the README's Prerequisites.
- A deployed contract — either via the automated script or manual deploy:
Save the printed contract ID as
./scripts/deploy-testnet.sh deployer
CONTRACT_ID_PLACEHOLDER. - A funded identity — for testnet, fund via
Friendbot; for local sandbox, the
defaultidentity is used automatically. - Network configured — for testnet:
soroban network add \ --global testnet \ --rpc-url https://soroban-testnet.stellar.org:443 \ --network-passphrase "Test SDF Network ; September 2015"
The examples below use the canonical placeholders from docs/placeholders.md. Replace them with your actual values before running.
Run each step in order. Every command should succeed; if any step fails, check the troubleshooting guide before continuing.
soroban contract invoke \
--id CONTRACT_ID_PLACEHOLDER \
--source deployer \
--network testnet \
-- \
initialize \
--admin ADMIN_PUBLIC_KEY \
--token TOKEN_CONTRACT_ADDRESS_PLACEHOLDERA successful call returns no output. A second call to initialize will
panic — this is expected and confirms re-initialization protection works.
soroban contract invoke \
--id CONTRACT_ID_PLACEHOLDER \
--source deployer \
--network testnet \
-- \
deposit \
--user USER_PUBLIC_KEY \
--amount 1000No output on success. This creates an internal accounting entry for the user's balance.
soroban contract invoke \
--id CONTRACT_ID_PLACEHOLDER \
--source deployer \
--network testnet \
-- \
get_balance \
--user USER_PUBLIC_KEYExpected output: 1000
soroban contract invoke \
--id CONTRACT_ID_PLACEHOLDER \
--source deployer \
--network testnet \
-- \
lock_funds \
--user USER_PUBLIC_KEY \
--amount 400 \
--unlock_time UNLOCK_TIMESTAMPUNLOCK_TIMESTAMP must be a Unix timestamp (seconds) in the future. No
output on success. The locked amount is moved from the available balance.
soroban contract invoke \
--id CONTRACT_ID_PLACEHOLDER \
--source deployer \
--network testnet \
-- \
get_locked_balance \
--user USER_PUBLIC_KEYExpected output: 400
soroban contract invoke \
--id CONTRACT_ID_PLACEHOLDER \
--source deployer \
--network testnet \
-- \
can_withdraw \
--user USER_PUBLIC_KEYExpected output: false (the lock has not matured yet)
soroban contract invoke \
--id CONTRACT_ID_PLACEHOLDER \
--source deployer \
--network testnet \
-- \
withdraw \
--user USER_PUBLIC_KEY \
--amount 1000No output on success. Once the lock matures, the full balance (available + matured lock) is withdrawable.
soroban contract invoke \
--id CONTRACT_ID_PLACEHOLDER \
--source deployer \
--network testnet \
-- \
get_balance \
--user USER_PUBLIC_KEYExpected output: 0
| Step | Function | Type | Expected result |
|---|---|---|---|
| 1 | initialize |
state-changing | no output |
| 2 | deposit |
state-changing | no output |
| 3 | get_balance |
read-only | 1000 |
| 4 | lock_funds |
state-changing | no output |
| 5 | get_locked_balance |
read-only | 400 |
| 6 | can_withdraw |
read-only | false |
| 7 | withdraw |
state-changing | no output |
| 8 | get_balance |
read-only | 0 |
All eight steps pass? The contract is deployed and responding correctly.
To run the same smoke test against a local sandbox, replace
--network testnet with --network standalone and use the default
identity for --source and --user. No Friendbot funding is needed.
soroban contract invoke \
--id CONTRACT_ID_PLACEHOLDER \
--source default \
--network standalone \
-- \
get_balance \
--user defaultSee docs/local-development.md for full local sandbox setup and limitations.
- Run the full Rust test suite:
cargo test - Review the invocation examples for all function signatures and arguments
- Check the walkthrough for a detailed lifecycle example with state explanations