@@ -25,14 +25,10 @@ use soroban_sdk::{contract, contractimpl, token::TokenClient, Address, BytesN, E
2525
2626pub use errors:: ContractError ;
2727pub use types:: {
28- ArbitrationConfig , DisclosureGrant , DisputeResolution , Proposal , ProposalAction ,
29- ArbitrationConfig , ArbitratorVote , DisclosureGrant , DisputeResolution , MultiSigConfig ,
30- Proposal , ProposalAction , ProposalStatus , Subscription , SubscriptionTier , TierConfig ,
31- TemplateTerms , TemplateVersion , Trade , TradePrivacy , TradeStatus , TradeTemplate ,
32- UserTier , UserTierInfo , VotingSummary ,
33- ArbitratorReputation , DisclosureGrant , DisputeResolution , Proposal , ProposalAction ,
34- ProposalStatus , Subscription , SubscriptionTier , TierConfig , TemplateTerms , TemplateVersion ,
35- Trade , TradePrivacy , TradeStatus , TradeTemplate , UserTier , UserTierInfo ,
28+ ArbitrationConfig , ArbitratorReputation , ArbitratorVote , DisclosureGrant , DisputeResolution ,
29+ MultiSigConfig , PriceTrigger , Proposal , ProposalAction , ProposalStatus , Subscription ,
30+ SubscriptionTier , TemplateTerms , TemplateVersion , Trade , TradePrivacy , TradeStatus ,
31+ TradeTemplate , TriggerAction , UserTier , UserTierInfo , VotingSummary ,
3632} ;
3733pub use queries:: { PageParams , SortDirection , TradeFilter , TradeSortField , TradeStats } ;
3834pub use oracle:: { OracleEntry , PriceData , PriceValidation } ;
@@ -244,53 +240,6 @@ impl StellarEscrowContract {
244240 /// Create a trade with multi-signature arbitration.
245241 /// All arbitrators in `config` must be registered; threshold must be > 0
246242 /// and ≤ arbitrators count.
247- pub fn create_multisig_trade (
248- env : Env ,
249- seller : Address ,
250- buyer : Address ,
251- amount : u64 ,
252- config : MultiSigConfig ,
253- expiry_time : Option < u64 > ,
254- currency : Option < Address > ,
255- ) -> Result < u64 , ContractError > {
256- require_initialized ( & env) ?;
257- require_not_paused ( & env) ?;
258- if amount == 0 {
259- return Err ( ContractError :: InvalidAmount ) ;
260- }
261- if config. threshold == 0 || config. threshold > config. arbitrators . len ( ) {
262- return Err ( ContractError :: InvalidMultiSigConfig ) ;
263- }
264- for i in 0 ..config. arbitrators . len ( ) {
265- if !has_arbitrator ( & env, & config. arbitrators . get ( i) . unwrap ( ) ) {
266- return Err ( ContractError :: ArbitratorNotRegistered ) ;
267- }
268- }
269- if let Some ( expiry) = expiry_time {
270- if expiry <= env. ledger ( ) . timestamp ( ) {
271- return Err ( ContractError :: InvalidExpiry ) ;
272- }
273- }
274- seller. require_auth ( ) ;
275- let token = currency. unwrap_or ( get_usdc_token ( & env) ?) ;
276- let trade_id = increment_trade_counter ( & env) ?;
277- let fee = calc_fee ( & env, & seller, amount) ?;
278- let trade = Trade {
279- id : trade_id,
280- seller : seller. clone ( ) ,
281- buyer : buyer. clone ( ) ,
282- amount,
283- fee,
284- arbitrator : Some ( ArbitrationConfig :: MultiSig ( config) ) ,
285- status : TradeStatus :: Created ,
286- expiry_time,
287- currency : token,
288- metadata : None ,
289- } ;
290- save_trade ( & env, trade_id, & trade) ;
291- events:: emit_trade_created ( & env, trade_id, seller, buyer, amount, trade. currency ) ;
292- Ok ( trade_id)
293- }
294243
295244 /// Cast a vote on a disputed multi-sig trade.
296245 pub fn cast_vote (
@@ -566,8 +515,8 @@ impl StellarEscrowContract {
566515 arbitrator : Option < Address > ,
567516 expiry_time : Option < u64 > ,
568517 currency : Option < Address > ,
569- metadata : Option < TradeMetadata > ,
570- metadata : OptionalMetadata ,
518+ metadata : Option < soroban_sdk :: String > ,
519+ trigger : Option < PriceTrigger > ,
571520 ) -> Result < u64 , ContractError > {
572521 require_initialized ( & env) ?;
573522 require_not_paused ( & env) ?;
@@ -619,6 +568,7 @@ impl StellarEscrowContract {
619568 expiry_time,
620569 currency : token,
621570 metadata,
571+ trigger,
622572 } ;
623573 save_trade ( & env, trade_id, & trade) ;
624574 events:: emit_trade_created ( & env, trade_id, seller. clone ( ) , buyer. clone ( ) , amount) ;
@@ -637,7 +587,8 @@ impl StellarEscrowContract {
637587 multisig_config : MultiSigConfig ,
638588 expiry_time : Option < u64 > ,
639589 currency : Option < Address > ,
640- metadata : OptionalMetadata ,
590+ metadata : Option < soroban_sdk:: String > ,
591+ trigger : Option < PriceTrigger > ,
641592 ) -> Result < u64 , ContractError > {
642593 require_initialized ( & env) ?;
643594 require_not_paused ( & env) ?;
@@ -673,7 +624,7 @@ impl StellarEscrowContract {
673624 validate_user_compliance ( & env, & seller, amount) ?;
674625 validate_user_compliance ( & env, & buyer, amount) ?;
675626
676- if let OptionalMetadata :: Some ( ref meta) = metadata {
627+ if let Some ( ref meta) = metadata {
677628 validate_metadata ( meta) ?;
678629 }
679630
@@ -694,6 +645,7 @@ impl StellarEscrowContract {
694645 expiry_time,
695646 currency : token,
696647 metadata,
648+ trigger,
697649 } ;
698650 save_trade ( & env, trade_id, & trade) ;
699651 events:: emit_trade_created ( & env, trade_id, seller. clone ( ) , buyer. clone ( ) , amount) ;
@@ -1154,6 +1106,59 @@ impl StellarEscrowContract {
11541106 oracle:: validate_trade_price ( & env, & base, & quote, trade_amount, min_usd, max_usd)
11551107 }
11561108
1109+ /// Check and execute a price trigger for a trade.
1110+ /// Can be called by anyone; trigger logic is automated based on oracle price.
1111+ pub fn execute_price_trigger ( env : Env , trade_id : u64 ) -> Result < ( ) , ContractError > {
1112+ require_initialized ( & env) ?;
1113+ require_not_paused ( & env) ?;
1114+ let mut trade = get_trade ( & env, trade_id) ?;
1115+ let trigger = match & trade. trigger {
1116+ Some ( t) => t. clone ( ) ,
1117+ None => return Err ( ContractError :: NoTrigger ) ,
1118+ } ;
1119+ // Trigger can only execute for funded trades
1120+ if trade. status != TradeStatus :: Funded {
1121+ return Err ( ContractError :: InvalidStatus ) ;
1122+ }
1123+
1124+ if oracle:: check_trigger ( & env, & trigger) ? {
1125+ match trigger. action {
1126+ TriggerAction :: Cancel => {
1127+ // Refund entire escrowed amount to buyer
1128+ let token_client = token:: Client :: new ( & env, & trade. currency ) ;
1129+ token_client. transfer (
1130+ & env. current_contract_address ( ) ,
1131+ & trade. buyer ,
1132+ & ( trade. amount as i128 ) ,
1133+ ) ;
1134+ trade. status = TradeStatus :: Cancelled ;
1135+ }
1136+ TriggerAction :: Release => {
1137+ // Release to seller, minus platform fee
1138+ let token_client = token:: Client :: new ( & env, & trade. currency ) ;
1139+ let payout = trade. amount . checked_sub ( trade. fee ) . ok_or ( ContractError :: Overflow ) ?;
1140+ token_client. transfer (
1141+ & env. current_contract_address ( ) ,
1142+ & trade. seller ,
1143+ & ( payout as i128 ) ,
1144+ ) ;
1145+ // Add fee to contract's accumulated revenue
1146+ let current_fees = storage:: get_currency_fees ( & env, & trade. currency ) ;
1147+ let new_fees = current_fees. checked_add ( trade. fee ) . ok_or ( ContractError :: Overflow ) ?;
1148+ storage:: set_currency_fees ( & env, & trade. currency , new_fees) ;
1149+ storage:: add_accumulated_fees ( & env, trade. fee ) ?;
1150+ trade. status = TradeStatus :: Triggered ;
1151+ }
1152+ }
1153+ save_trade ( & env, trade_id, & trade) ;
1154+ events:: emit_trigger_executed ( & env, trade_id, & trigger. action ) ;
1155+ } else {
1156+ return Err ( ContractError :: PriceConditionNotMet ) ;
1157+ }
1158+
1159+ Ok ( ( ) )
1160+ }
1161+
11571162 // -------------------------------------------------------------------------
11581163 // Emergency Pause
11591164 // -------------------------------------------------------------------------
@@ -1682,7 +1687,8 @@ impl StellarEscrowContract {
16821687 status : TradeStatus :: AwaitingBridge ,
16831688 expiry_time : None ,
16841689 currency : get_usdc_token ( & env) ?,
1685- metadata : OptionalMetadata :: None ,
1690+ metadata : None ,
1691+ trigger : None ,
16861692 } ;
16871693 save_trade ( & env, trade_id, & trade) ;
16881694 save_cross_chain_info ( & env, trade_id, & CrossChainInfo {
0 commit comments