Testnet Deployment
Prerequisites
- Stellar CLI:
cargo install stellar-cli - A funded testnet keypair (see below)
- Rust with the
wasm32-unknown-unknowntarget:rustup target add wasm32-unknown-unknown
Generate and fund a testnet keypair
# Generate a new keypair and store it in the Stellar CLI keystore
stellar keys generate --network testnet deployer
# Print the public key
stellar keys address deployer
# Fund via Friendbot (replace with your public key)
curl "https://friendbot.stellar.org/?addr=$(stellar keys address deployer)"Build the vault contract
cd packages/contracts/vault
stellar contract buildThis produces target/wasm32-unknown-unknown/release/meridian_vault.wasm.
Deploy USDC and mUSDC (testnet only)
On testnet, deploy mock Stellar Asset Contracts (SAC) for USDC and mUSDC. On mainnet, use the real USDC contract address already present in CONTRACT_ADDRESSES.testnet.usdc.
To deploy a SAC you first need a funded keypair to act as the asset issuer, then wrap that classic asset as a Soroban contract:
# Generate an issuer keypair
stellar keys generate --network testnet issuer
curl "https://friendbot.stellar.org/?addr=$(stellar keys address issuer)"
# Deploy a SAC for mock USDC
stellar contract asset deploy \
--asset USDC:$(stellar keys address issuer) \
--network testnet \
--source deployerRecord the returned contract ID as USDC_CONTRACT_ID.
Repeat with a different asset code (e.g. MUSDC) for the share token and record as MUSDC_CONTRACT_ID.
Deploy the vault contract
stellar contract deploy \
--wasm target/wasm32-unknown-unknown/release/meridian_vault.wasm \
--network testnet \
--source deployerRecord the returned contract ID as VAULT_CONTRACT_ID.
Initialize the vault
stellar contract invoke \
--id $VAULT_CONTRACT_ID \
--network testnet \
--source deployer \
-- initialize \
--admin $(stellar keys address deployer) \
--usdc $USDC_CONTRACT_ID \
--musdc $MUSDC_CONTRACT_IDTransfer mUSDC admin to the vault
The vault must be the admin of the mUSDC asset in order to mint and burn share tokens autonomously.
stellar contract invoke \
--id $MUSDC_CONTRACT_ID \
--network testnet \
--source issuer \
-- set_admin \
--new_admin $VAULT_CONTRACT_IDUpdate contract addresses
Add the deployed contract IDs to packages/shared/src/constants.ts:
export const CONTRACT_ADDRESSES = {
testnet: {
blend: {
pool: "C...",
},
defindex: {
factory: "C...",
vault: "",
},
usdc: "C...", // USDC_CONTRACT_ID
eurc: "C...",
musdc: "C...", // MUSDC_CONTRACT_ID
vault: "C...", // VAULT_CONTRACT_ID
},
} as const;The vault contract address is read from constants at build time. There is no runtime environment variable for it.
Verify the deployment
# Check total assets (should be 0 after initialization)
stellar contract invoke \
--id $VAULT_CONTRACT_ID \
--network testnet \
--source deployer \
-- get_total_assetsA return value of 0 confirms the contract is initialized and responding.
Run the signing flow end-to-end
With the contract deployed and constants updated:
- Open the app, connect Freighter (testnet mode).
- Enter a USDC amount and click Deposit.
- Freighter should display the transaction details; verify the contract address matches
VAULT_CONTRACT_ID. - Approve the transaction.
- After ~5 seconds, the position summary should update with your deposited amount.