Smart contract + CLI to distribute dfTokens (DeFindex Vault Tokens) to users in a transparent and secure way.
The Distributor enables fund distribution in campaigns or events for DeFindex users: it deposits assets into a vault and distributes the resulting dfTokens to recipients from a CSV that contains asset, vault, user and amount; as if each user had deposited directly. The smart contract ensures that each user receives the corresponding amount of dfTokens verifiably on-chain.
- The script reads a CSV with recipients and amounts per vault
- Groups by vault and splits into batches (to respect Soroban's instruction limit)
- For each batch, calls the
distributecontract which in a single transaction:- Caller sends the total underlying amount to the distributor contract
- Distributor deposits the total amount in the vault and receives minted dfTokens
- Distributes dfTokens pro-rata to each recipient
- Verifies balances before/after and generates incremental CSV + log files with the results
- Node.js v18+
- pnpm package manager
- Stellar CLI (only needed for deploying the smart contract)
Secret keys are stored in the OS keychain (macOS Keychain, Linux Secret Service, Windows Credential Manager) — never in plaintext on disk.
pnpm setup-keys [testnet|mainnet] # store key (prompts for secret key, seed phrase, or generates one)
pnpm setup-keys --show # print stored public key
pnpm setup-keys --delete # remove from keychainFallback: if no keychain entry is found, the scripts fall back to
STELLAR_SECRET_KEY_TESTNET/STELLAR_SECRET_KEY_MAINNETin.env(useful for CI).
pnpm i
pnpm setup-keys mainnetFor CI or environments without a keychain, copy .env.example and set the key there instead:
cp .env.example .envSTELLAR_NETWORK=mainnet
STELLAR_SECRET_KEY_MAINNET=S...
SOROBAN_RPC_MAINNET=https://soroban-rpc.mainnet.stellar.gateway.fm
HORIZON_RPC_MAINNET=https://horizon.stellar.orgThe CSV must have the columns: asset, vault, user, amount (order doesn't matter, parsed by header name).
asset: vault's underlying asset address (token to deposit)vault: DeFindex vault addressuser: recipient addressamount: amount in the asset's minimum unit (stroops, 7 decimals)
asset,vault,user,amount
CCZGLAUBDKJSQK72QOZHVU7CUWKW45OZWYWCLL27AEK74U2OIBK6LXF2,CDHZFQZWSU7GSHUBWFEL2FJ7R2RNVHI3RPY5QMCQ3MGJXOSHSTSW5PE7,GCGI4UWY3JDN2NH4L33Y7GHOGFTV3WTGAPPCQONZJOPOL5BSSCVS6UQI,7952002150
CCZGLAUBDKJSQK72QOZHVU7CUWKW45OZWYWCLL27AEK74U2OIBK6LXF2,CDHZFQZWSU7GSHUBWFEL2FJ7R2RNVHI3RPY5QMCQ3MGJXOSHSTSW5PE7,GCUJW46S35TBIOS2R42LLK4W3O2HRHMQBXGLNSTVTUYCZWN5BML3H7XI,4303465857STELLAR_NETWORK=mainnet pnpm distribute path/to/file.csvAdd --xdr to print the unsigned and signed XDR of each transaction (useful for debugging).
The script will:
- Show the status of each batch and vault
- Compare balances before/after for each user
- Write incremental logs to
output/distributor/distributor_<timestamp>.csvand.log
To test on testnet, run the demo script that creates test vaults and users.
pnpm i
pnpm setup-keys testnetIf you prefer .env, copy the example — it comes configured for testnet by default:
cp .env.example .envpnpm demoThis will:
- Fund the manager account via Friendbot
- Mint Blend USDC tokens via ephemeral accounts
- Fetch blend strategy addresses from the DeFindex repo
- Create 2 vaults (USDC + XLM) with blend strategies via the DeFindex API
- Create a random number of users per vault (between 5 and 20)
- Generate a test CSV at
output/demo/demo_testnet_<timestamp>.csv - Auto-run mint if additional tokens are needed (XLM via Friendbot, Blend tokens via ephemeral accounts)
pnpm distribute output/demo/demo_testnet_<timestamp>.csvAdd --xdr to print the unsigned and signed XDR of each transaction (useful for debugging).
All environment variables are suffixed by network (_TESTNET or _MAINNET). The STELLAR_NETWORK variable determines which suffix is used.
STELLAR_NETWORK=testnet # "testnet" or "mainnet"
# Secret keys are loaded from the OS keychain (pnpm setup-keys).
# These env vars are only needed as a fallback (e.g. CI environments).
STELLAR_SECRET_KEY_TESTNET= # optional fallback
STELLAR_SECRET_KEY_MAINNET= # optional fallback
SOROBAN_RPC_TESTNET=https://soroban-testnet.stellar.org
HORIZON_RPC_TESTNET=https://horizon-testnet.stellar.org
SOROBAN_RPC_MAINNET=
HORIZON_RPC_MAINNET=
DEFINDEX_API_KEY= # Optional: DeFindex API key for demo vault creation
MINT_BLEND_TOKENS_URL= # Optional: Blend faucet URL for demo token mintingDeploys the wasm built by the CI release workflow, so Stellar Expert can verify and link the source code automatically.
Prerequisites: gh CLI authenticated (gh auth login), stellar CLI.
./scripts/deploy.sh <network> <stellar-identity> [release-tag]Examples:
./scripts/deploy.sh testnet user
./scripts/deploy.sh testnet user main_defindex-distributor_pkg0.0.1_cli22.8.1After deploying, update the contract address in src/addresses.ts manually.
make test
make build # build and optimize
stellar keys generate alice --network testnet --fund
stellar contract deploy \
--wasm target/wasm32v1-none/release/defindex_distributor.wasm \
--source-account alice \
--network testnet \
--alias defindex-distributorThe Contract ID will be stored at ~/.config/stellar/contract-ids/defindex-distributor.json
Optional: replace the address in src/addresses.ts
NEW_ADDR=$(cat ~/.config/stellar/contract-ids/defindex-distributor.json | python3 -c "import sys,json; print(json.load(sys.stdin)['ids']['Test SDF Network ; September 2015'])") && \
sed -i "s/export const DISTRIBUTOR_TESTNET = \".*\"/export const DISTRIBUTOR_TESTNET = \"$NEW_ADDR\"/" src/addresses.ts
src/
├── utils.ts # Network config, env helpers, Stellar SDK helpers
├── addresses.ts # Contract addresses and API URLs
├── keychain.ts # OS keychain wrapper (macOS/Linux/Windows)
├── setup-keys.ts # One-time CLI to store keys in the keychain
├── distribute.ts # Main script: deposit + distribute via contract
├── demo.ts # Testnet demo: create vaults via DeFindex API, generate CSV
├── mint.ts # Mint testnet tokens (Blend faucet, Soroswap, Friendbot)
└── logger.ts # Incremental CSV + log file writer
contracts/
└── defindex-distributor/ # Soroban smart contract (Rust)
output/ # Script outputs (gitignored)
├── demo/ # demo_testnet_*.csv
└── distributor/ # distributor_*.csv + distributor_*.log
| Command | Description |
|---|---|
pnpm setup-keys [network] |
Store your Stellar key in the OS keychain (run once) |
pnpm demo |
Create testnet vaults with blend strategies, generate test CSV |
pnpm mint <csv> |
Mint testnet tokens (Soroswap faucet + XLM via Friendbot) |
pnpm distribute <csv> |
Distribute dfTokens to users with incremental logging |
./scripts/deploy.sh <network> <identity> |
Deploy contract from GitHub Release (Stellar Expert verified) |