This document describes the stellar-give Soroban contract public API, error variants, storage layout, and example payloads for integrators.
The contract exposes five public methods:
create_campaign– create a new campaign with a target, deadline, beneficiaries, accepted token, category, and metadata.donate– transfer tokens from a donor to a campaign.claim_funds– release raised funds to beneficiaries once the campaign is funded or expired.get_campaign– read campaign state.get_top_donors– read the top five donors for a campaign.
All state-changing methods require caller authentication via require_auth().
pub fn create_campaign(
env: Env,
creator: Address,
beneficiaries: Vec<(Address, u32)>,
title: String,
metadata_uri: String,
category: Symbol,
target_amount: i128,
deadline: u64,
accepted_token: Address,
max_per_donor: Option<i128>,
) -> Result<u64, ContractError>Arguments
env- Contract environment.creator- Authorized address creating the campaign. Must callrequire_auth().beneficiaries- Vector of(Address, u32)share recipients. Must contain at least one entry and sum to10_000basis points.title- Campaign title. Must be non-empty.target_amount- Funding goal in stroops.deadline- Unix timestamp after which new donations are no longer accepted.accepted_token- Address of a Soroban token contract that must implement the token interface.website- Optional website URL. If provided, must start withhttps://.twitter- Optional Twitter link. If provided, must start withhttps://.
Warning
No ownership verification: The contract only validates that the URLs start with https:// to encourage secure links. There is no on-chain cryptographic verification of ownership. These links are informational only.
Returns
Ok(campaign_id)on success.
Errors
Unauthorizedifcreatoris not authenticated.EmptyTitleif the title is empty.InvalidAmountiftarget_amount <= 0or if the auto-increment ID overflows.InvalidDeadlineif the deadline is not strictly in the future.InvalidTokenif the accepted token contract does not implement the expected token interface.InvalidSharesifbeneficiariesis empty or if shares do not sum to10_000.
Example JSON-RPC payload
{
"method": "create_campaign",
"params": [
"GC...CREATOR_ADDRESS...",
[["GB...BENEFICIARY_ADDRESS...", 10000]],
"My Campaign",
"100000000",
1717000000,
"GC...TOKEN_CONTRACT_ADDRESS..."
]
}pub fn donate(
env: Env,
donor: Address,
campaign_id: u64,
amount: i128,
is_anonymous: bool,
) -> Result<(), ContractError>Arguments
env- Contract environment.donor- Authorized donor address. Must callrequire_auth().campaign_id- ID of the campaign to donate to.amount- Donation amount in stroops.is_anonymous- Iftrue, masks the donor address in emitted events and top donor listings with the zero address (GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF).
Note
Privacy Trade-offs: On-chain ledger transfers remain public. The underlying token contract still records a transfer originating from the donor's address. is_anonymous only masks application-level events and dashboard displays.
Returns
Ok(())on success.
Errors
Unauthorizedifdonoris not authenticated.InvalidAmountifamount <= 0.CampaignNotFoundif the campaign ID does not exist.CampaignNotActiveif the campaign is not currently active.TokenTransferFailedif the token transfer from donor to contract fails.
Example JSON-RPC payload
{
"method": "donate",
"params": [
"GD...DONOR_ADDRESS...",
1,
"1000000"
]
}pub fn claim_funds(
env: Env,
caller: Address,
campaign_id: u64,
) -> Result<i128, ContractError>Arguments
env- Contract environment.caller- Authorized address requesting the payout. Must callrequire_auth().campaign_id- Campaign ID to claim.
Returns
Ok(total)wheretotalis the amount distributed in stroops.
Errors
Unauthorizedifcalleris neither the campaign creator nor a beneficiary.CampaignNotFoundif the campaign ID does not exist.AlreadyClaimedif funds have already been claimed.ClaimNotAllowedif the campaign is still active and not eligible for payout.NothingToClaimif there is no raised amount to distribute.TokenTransferFailedif a payout transfer fails during distribution.
Example JSON-RPC payload
{
"method": "claim_funds",
"params": [
"GB...CALLER_ADDRESS...",
1
]
}pub fn get_campaign(env: Env, campaign_id: u64) -> Result<Campaign, ContractError>Arguments
env- Contract environment.campaign_id- Campaign ID to retrieve.
Returns
Ok(Campaign)with full campaign state.
Errors
CampaignNotFoundif the campaign ID does not exist.
Example JSON-RPC payload
{
"method": "get_campaign",
"params": [1]
}pub fn get_top_donors(env: Env, campaign_id: u64) -> Result<Vec<(Address, i128)>, ContractError>Arguments
env- Contract environment.campaign_id- Campaign ID.
Returns
Ok(Vec<(Address, i128)>)with the top five donors sorted by amount.
Errors
CampaignNotFoundif the campaign ID does not exist.
Example JSON-RPC payload
{
"method": "get_top_donors",
"params": [1]
}| Variant | Trigger Condition |
|---|---|
Unauthorized |
Caller is not authorized for a state-changing request. |
InvalidDeadline |
Deadline is not strictly in the future. |
InvalidAmount |
Amount is zero/negative or arithmetic overflow occurs. |
CampaignNotFound |
No campaign exists for the requested ID. |
InvalidToken |
Accepted token contract does not implement the required interface. |
CampaignNotActive |
Donation attempted for non-active campaign. |
ClaimNotAllowed |
Claim attempted before campaign is funded or expired. |
AlreadyClaimed |
Campaign funds have already been claimed. |
ReentrancyDetected |
Reentrant call detected by temporary lock. |
EmptyTitle |
Campaign title is empty on creation. |
NothingToClaim |
Claim attempted but raised amount is zero. |
InvalidShares |
Beneficiary shares missing or do not sum to 10_000. |
TokenTransferFailed |
Token transfer failed during donate or claim. |
symbol_short!("NEXT")(instance storage) ->u64next campaign ID.(symbol_short!("CMP"), campaign_id)(persistent storage) ->Campaignstruct.(symbol_short!("TDON"), campaign_id)(persistent storage) ->Vec<(Address, i128)>top donors.symbol_short!("LOCK")(temporary storage) ->boolreentrancy lock flag.
id- campaign IDcreator- address of campaign creatorbeneficiaries- share recipients and basis pointstitle- campaign titletarget_amount- funding goal in stroopsraised_amount- current donated total in stroopsdeadline- Unix timestamp when donations endaccepted_token- token contract address for donationsstatus- campaign lifecycle state
The contract is deployed as a Soroban contract and is invoked through reflected method calls.
External integrators may use generic JSON-RPC bodies that map function names to parameter arrays. Example payloads above use the method name and parameter order expected by the contract.
A real invocation must be wrapped in a signed transaction envelope and submitted via Soroban RPC. The action uses the contract ID and a host function call to the named contract method.
- Build a transaction with a
invokeHostFunctionop. - Set the contract ID and method name.
- Append arguments in Soroban Value form.
- Sign the transaction with the caller's Stellar key.
- Submit via RPC
send_transaction.
soroban contract invoke --id <CONTRACT_ID> --fn create_campaign --arg <CREATOR_ADDRESS> --arg <BENEFICIARY_ADDRESS> --arg 10000 --arg "My Campaign" --arg 100000000 --arg 1717000000 --arg <TOKEN_ADDRESS>Replace
<CONTRACT_ID>with the deployed contract ID and use the proper Soroban CLI syntax for your environment.