Move the full milestone total into escrow.
All-or-nothing on purpose: partial funding would let a sponsor advertise three milestones while only backing one, which is exactly the ambiguity SprintOS exists to remove.
fn fund(env: soroban_sdk::Env, engagement_id: u64) -> Result<(), soroban_sdk::Error>
Send the milestone back for revision. The builder may resubmit.
fn hold(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
engagement_id: u64,
milestone_idx: u32,
) -> Result<(), soroban_sdk::Error>
Let the builder recover an already-approved payment if the reviewer
cannot return for the second signature. The binding human judgement has
already happened in approve; this path cannot approve work.
fn claim(
env: soroban_sdk::Env,
engagement_id: u64,
milestone_idx: u32,
) -> Result<(), soroban_sdk::Error>
The SEP-41 asset every engagement settles in.
fn token(env: soroban_sdk::Env) -> Result
Reclaim a milestone the builder did not deliver in time.
Only after the deadline, and never once the reviewer has approved — an approved milestone is owed to the builder regardless of the clock.
fn refund(
env: soroban_sdk::Env,
engagement_id: u64,
milestone_idx: u32,
) -> Result<(), soroban_sdk::Error>
Record the reviewer's decision that the milestone is met.
Approving does not pay. release is a separate signature so that the
judgement and the money movement are two distinct, auditable acts.
fn approve(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
engagement_id: u64,
milestone_idx: u32,
) -> Result<(), soroban_sdk::Error>
Pay an approved milestone out to the builder.
The reviewer-controlled payout path. Requires the reviewer's signature
and an Approved status — no score or recommendation can reach this
line. After that human approval, claim is the builder's recovery path.
fn release(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
engagement_id: u64,
milestone_idx: u32,
) -> Result<(), soroban_sdk::Error>
Whether this address may approve, hold or release on this engagement.
fn can_decide(
env: soroban_sdk::Env,
engagement_id: u64,
who: soroban_sdk::Address,
) -> Result
Value still held in escrow for this engagement.
fn get_balance(
env: soroban_sdk::Env,
engagement_id: u64,
) -> Result
Authorise another wallet to decide payouts on this engagement.
Only the sponsor may call this. The builder is refused however the call is dressed up: a builder who could approve would sign off their own work and release their own payment, and that is the one collision this contract will not allow at any point in an engagement's life.
fn add_reviewer(
env: soroban_sdk::Env,
engagement_id: u64,
who: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Pin the settlement asset once, at deploy time.
Deliberately not re-callable: if the token could be swapped later, an
engagement funded in USDC could be released in something worthless.
first_id starts the engagement counter above whatever the previous
deployment reached, so an id names exactly one engagement across both and
a link written against the old contract never resolves to a new one.
fn __constructor(env: soroban_sdk::Env, token: soroban_sdk::Address, first_id: u64)
fn get_milestone(
env: soroban_sdk::Env,
engagement_id: u64,
milestone_idx: u32,
) -> Result
fn get_engagement(
env: soroban_sdk::Env,
engagement_id: u64,
) -> Result
Withdraw that authority again.
The sponsor cannot remove themselves. Their authority comes from having funded the work rather than from a list entry, and an engagement nobody can decide would leave the builder waiting for a deadline instead of a decision.
fn remove_reviewer(
env: soroban_sdk::Env,
engagement_id: u64,
who: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Attach an evidence bundle to a milestone.
Legal from Pending (first submission) and from Held (revision after
the reviewer asked for changes).
fn submit_evidence(
env: soroban_sdk::Env,
engagement_id: u64,
milestone_idx: u32,
evidence_hash: soroban_sdk::BytesN<32>,
evidence_uri: soroban_sdk::String,
) -> Result<(), soroban_sdk::Error>
fn engagement_count(env: soroban_sdk::Env) -> u64
Define an engagement and its milestones. Does not move funds — see fund.
The sponsor signs, and by signing becomes the account that decides every
payout. reviewers is who else may — it can be empty, and the sponsor can
change it later with add_reviewer and remove_reviewer.
fn create_engagement(
env: soroban_sdk::Env,
sponsor: soroban_sdk::Address,
builder: soroban_sdk::Address,
reviewers: soroban_sdk::Vec,
milestones: soroban_sdk::Vec,
) -> Result