Complete public-interface specification for both Soroban smart contracts.
All functions live in the InvestmentVault or ProjectRegistry crates.
Crate: project_registry
Constructor args: admin: Address, whitelister: Address
| Function | Auth | Args | Returns | Events |
|---|---|---|---|---|
set_whitelist(account, status) |
whitelister | account: Address, status: bool |
() |
WhitelistSet { account, status } |
create_project(creator, uri, maturity_date) |
creator (whitelisted) | creator: Address, uri: String, maturity_date: u64 |
u32 (project_id) |
ProjectCreated { project_id, owner } |
get_project(id) |
none | id: u32 |
ProjectData |
— |
total_projects() |
none | — | u32 |
— |
get_all_projects() |
none | — | Vec<(u32, ProjectData)> |
— |
update_impact_score(project_id, credit_quality, green_impact) |
admin (owner) | project_id: u32, credit_quality: u32, green_impact: u32 |
() |
ProjectUpdated, RateUpdated, ScoreChanged |
update_credit_quality_score(project_id, credit_quality) |
admin (owner) | project_id: u32, credit_quality: u32 (0–100) |
() |
ScoreChanged |
certify_project(caller, project_id, status) |
whitelister or admin | caller: Address, project_id: u32, status: CertificationStatus |
() |
ProjectCertified { project_id, status } |
is_mature(project_id) |
none | project_id: u32 |
bool |
— |
create_proposal(proposer, description, voting_duration_secs) |
proposer | proposer: Address, description: String, voting_duration_secs: u64 (≥ 86400) |
u32 (proposal_id) |
ProposalCreated { proposal_id, proposer, voting_ends_at } |
cast_vote(voter, proposal_id, support, weight) |
voter | voter: Address, proposal_id: u32, support: bool, weight: i128 |
() |
VoteCast { proposal_id, voter, support, weight } |
execute_proposal(proposal_id) |
none | proposal_id: u32 |
bool (passed) |
ProposalExecuted { proposal_id, passed } |
get_proposal(proposal_id) |
none | proposal_id: u32 |
Proposal |
— |
pub struct ProjectData {
pub owner: Address,
pub uri: String,
pub credit_quality: u32, // 0–100, oracle-set
pub green_impact: u32, // 0–100, oracle-set
pub maturity_date: u64, // Unix timestamp; 0 = open-ended
pub certification_status: CertificationStatus,
}
pub enum CertificationStatus { None, Certified, Revoked }
pub struct Proposal {
pub description: String,
pub proposer: Address,
pub voting_ends_at: u64,
pub votes_for: i128,
pub votes_against: i128,
pub executed: bool,
}| Function | Scope | Emitted Events |
|---|---|---|
update_impact_score |
Sets both credit_quality AND green_impact atomically |
ProjectUpdated, RateUpdated, ScoreChanged |
update_credit_quality_score |
Sets only credit_quality, leaves green_impact unchanged |
ScoreChanged |
The ScoreChanged event (#131) includes both old and new score values plus old and new interest rates, enabling off-chain notification services to calculate the exact delta without querying historical state.
Crate: investment_vault
Constructor args: admin: Address, usdc_sac: Address, registry: Address
Token: HBS (Heliobond Shares) — SEP-41 fungible token via FungibleToken trait
| Name | Value | Purpose |
|---|---|---|
MAX_DEPOSIT |
1 billion USDC (7 dp) | Single-deposit ceiling |
INSURANCE_PREMIUM_BPS |
50 | 0.5% of each deposit reserved for insurance fund |
MAX_MANAGEMENT_FEE_BPS |
500 | 5% hard cap on admin-set management fee |
YIELD_SCALE |
1e18 | Precision for yield-per-share accumulator |
| Function | Auth | Args | Returns | Events |
|---|---|---|---|---|
deposit(from, usdc_amount) |
from | from: Address, usdc_amount: i128 (≤ MAX_DEPOSIT) |
i128 (shares minted) |
Deposit { from, usdc_amount, shares_minted } |
withdraw(from, shares_amount) |
from (via burn) |
from: Address, shares_amount: i128 |
i128 (USDC returned) |
Withdraw { from, shares_burned, usdc_returned } |
Deposit fee deduction order:
insurance_premium = usdc_amount × 50 / 10_000management_fee = usdc_amount × fee_bps / 10_000investable = usdc_amount − insurance_premium − management_feeshares = convert_to_shares(investable)
| Function | Auth | Args | Returns | Events |
|---|---|---|---|---|
fund_project(project_id, amount) |
admin | project_id: u32, amount: i128 |
() |
ProjectFunded { project_id, amount, recipient } |
The insurance reserve is subtracted from available USDC before the check, preventing the admin from accidentally funding projects with insurance money.
| Function | Auth | Args | Returns |
|---|---|---|---|
total_assets() |
none | — | i128 (total USDC value) |
convert_to_shares(usdc_amount) |
none | usdc_amount: i128 |
i128 |
convert_to_assets(shares_amount) |
none | shares_amount: i128 |
i128 |
get_expected_returns() |
none | — | i128 |
| Function | Auth | Args | Returns | Events |
|---|---|---|---|---|
receive_yield(from, amount) |
admin | from: Address, amount: i128 |
() |
YieldReceived { from, amount } |
claimable_yield(account) |
none | account: Address |
i128 |
— |
claim_yield(from) |
from | from: Address |
i128 |
YieldClaimed { to, amount } |
get_portfolio(account) |
none | account: Address |
PortfolioInfo |
— |
| Function | Auth | Args | Returns | Events |
|---|---|---|---|---|
insurance_fund_balance() |
none | — | i128 |
— |
claim_insurance(project_id, recipient, amount) |
admin | project_id: u32, recipient: Address, amount: i128 |
() |
InsuranceClaimed { project_id, recipient, amount } |
| Function | Auth | Args | Returns | Events |
|---|---|---|---|---|
set_management_fee(fee_bps, recipient) |
admin | fee_bps: u32 (≤ 500), recipient: Address |
() |
ManagementFeeSet { recipient, fee_bps } |
get_management_fee_bps() |
none | — | u32 |
— |
The fee is 0 by default. Passing fee_bps = 0 disables it. The hard cap of 500 bps (5%) is enforced on-chain and cannot be overridden.
HBS is a SEP-41 fungible token and is natively tradeable on the Stellar DEX. These functions surface the official listing status so UIs and aggregators can discover the trading pair.
| Function | Auth | Args | Returns | Events |
|---|---|---|---|---|
enable_secondary_trading() |
admin | — | () |
TradingEnabled { enabled: true } |
is_trading_enabled() |
none | — | bool |
— |
get_hbs_token_info() |
none | — | HBSTokenInfo |
— |
pub struct HBSTokenInfo {
pub name: String, // "Heliobond Shares"
pub symbol: String, // "HBS"
pub decimals: u32, // 7
pub trading_enabled: bool, // mirrors is_trading_enabled()
}DEX integration notes:
- HBS contract ID (the vault address) is the SEP-41 asset identifier on Stellar
- To list on Stellar DEX, create an offer using the Stellar SDK:
ManageOfferOporPathPaymentOpusing the vault contract address as the asset code - Liquidity pools can be created via
ChangeTrustOpagainst the HBS/USDC pair - The
get_hbs_token_info()function returns all metadata required for DEX listing discovery
| Function | Auth | Args | Returns |
|---|---|---|---|
accepted_asset() |
none | — | Address (USDC SAC) |
pub struct PortfolioInfo {
pub shares: i128,
pub usdc_value: i128,
pub claimable_yield: i128,
pub share_of_pool_bps: i128,
pub total_deposited: i128,
}Investor InvestmentVault ProjectRegistry
| | |
|-- deposit(usdc_amount) -->| |
| |-- (deduct insurance + fee) |
| |-- mint HBS shares to Investor|
| | |
| | |
Admin | |
|-- fund_project(id, amt) ->| |
| |-- get_project(id) ---------->|
| |<-- ProjectData { owner } ----|
| |-- transfer(USDC → owner) |
| | |
| | |
Investor | |
|-- withdraw(shares) ------>| |
| |-- burn HBS shares |
| |-- transfer(USDC → Investor) |
|<-- USDC returned ---------| |
Step-by-step:
-
Investor calls
deposit(from, usdc_amount)- Vault deducts insurance premium (50 bps) + management fee (if set)
- Calls
convert_to_shares(investable)— 1:1 on first deposit, proportional thereafter - Transfers
usdc_amountfrom investor to vault contract - Mints
sharesof HBS to investor - Emits
Deposit
-
Admin calls
fund_project(project_id, amount)- Calls
registry.get_project(project_id)to resolve the project owner address - Verifies
amount ≤ liquid_balance − insurance_reserve - Transfers USDC from vault to project owner
- Updates
TotalInvestmentsandProjectInvestment(project_id)ledger entries - Emits
ProjectFunded
- Calls
-
Investor calls
withdraw(from, shares_amount)- Calls
convert_to_assets(shares_amount)to determine USDC to return - Burns HBS shares via
Base::burn - Transfers USDC from vault to investor
- Emits
Withdraw
- Calls