@@ -1078,6 +1078,21 @@ impl CrowdfundingTrait for CrowdfundingContract {
10781078 return Err ( CrowdfundingError :: InvalidPoolState ) ;
10791079 }
10801080
1081+ feature/asset-based-discount
1082+ // Calculate platform fee with discount
1083+ let base_fee_bps = Self :: get_platform_fee_percentage ( env. clone ( ) ) ;
1084+ let discount_bps = Self :: get_asset_discount ( env. clone ( ) , asset. clone ( ) ) ;
1085+
1086+ // Apply discount: effective_fee = base_fee * (1 - discount/10000)
1087+ let effective_fee_bps = if discount_bps > 0 {
1088+ base_fee_bps. saturating_sub ( ( base_fee_bps * discount_bps) / 10000 )
1089+ } else {
1090+ base_fee_bps
1091+ } ;
1092+
1093+ // Calculate fee amount: fee = amount * effective_fee_bps / 10000
1094+ let platform_fee = ( amount * effective_fee_bps as i128 ) / 10000 ;
1095+ let net_contribution = amount - platform_fee;
10811096 // Load pool configuration to enforce minimum contribution
10821097 let pool_key = StorageKey :: Pool ( pool_id) ;
10831098 let pool: PoolConfig = env
@@ -1089,15 +1104,27 @@ impl CrowdfundingTrait for CrowdfundingContract {
10891104 if amount < pool. min_contribution {
10901105 return Err ( CrowdfundingError :: InvalidAmount ) ;
10911106 }
1107+ main
10921108
10931109 // Transfer tokens
1094- // Note: In a real implementation we would use the token client.
1095- // For this task we assume the token interface is available via soroban_sdk::token
10961110 use soroban_sdk:: token;
10971111 let token_client = token:: Client :: new ( & env, & asset) ;
10981112 token_client. transfer ( & contributor, env. current_contract_address ( ) , & amount) ;
10991113
1100- // Update metrics
1114+ // Track platform fees if any
1115+ if platform_fee > 0 {
1116+ let platform_fees_key = StorageKey :: PlatformFees ;
1117+ let current_fees: i128 = env
1118+ . storage ( )
1119+ . instance ( )
1120+ . get ( & platform_fees_key)
1121+ . unwrap_or ( 0 ) ;
1122+ env. storage ( )
1123+ . instance ( )
1124+ . set ( & platform_fees_key, & ( current_fees + platform_fee) ) ;
1125+ }
1126+
1127+ // Update metrics with net contribution
11011128 let metrics_key = StorageKey :: PoolMetrics ( pool_id) ;
11021129 let mut metrics: PoolMetrics = env
11031130 . storage ( )
@@ -1123,16 +1150,16 @@ impl CrowdfundingTrait for CrowdfundingContract {
11231150 metrics. contributor_count += 1 ;
11241151 }
11251152
1126- metrics. total_raised += amount ;
1153+ metrics. total_raised += net_contribution ;
11271154 metrics. last_donation_at = env. ledger ( ) . timestamp ( ) ;
11281155
11291156 env. storage ( ) . instance ( ) . set ( & metrics_key, & metrics) ;
11301157
1131- // Update per-user contribution tracking
1158+ // Update per-user contribution tracking with net contribution
11321159 let updated_contribution = PoolContribution {
11331160 pool_id,
11341161 contributor : contributor. clone ( ) ,
1135- amount : existing_contribution. amount + amount ,
1162+ amount : existing_contribution. amount + net_contribution ,
11361163 asset : asset. clone ( ) ,
11371164 } ;
11381165 env. storage ( )
@@ -1159,7 +1186,7 @@ impl CrowdfundingTrait for CrowdfundingContract {
11591186 pool_id,
11601187 contributor,
11611188 asset,
1162- amount ,
1189+ net_contribution ,
11631190 env. ledger ( ) . timestamp ( ) ,
11641191 is_private,
11651192 ) ;
@@ -1580,10 +1607,124 @@ impl CrowdfundingTrait for CrowdfundingContract {
15801607 . ok_or ( CrowdfundingError :: NotInitialized )
15811608 }
15821609
1610+ feature/asset-based-discount
1611+ fn set_asset_discount (
1612+ env : Env ,
1613+ asset : Address ,
1614+ discount_bps : u32 ,
1615+ ) -> Result < ( ) , CrowdfundingError > {
1616+ let admin: Address = env
1617+ . storage ( )
1618+ . instance ( )
1619+ . get ( & StorageKey :: Admin )
1620+ . ok_or ( CrowdfundingError :: NotInitialized ) ?;
1621+ admin. require_auth ( ) ;
1622+
1623+ // Validate discount is not more than 100% (10000 basis points)
1624+ if discount_bps > 10000 {
1625+ return Err ( CrowdfundingError :: InvalidFee ) ;
1626+ }
1627+
1628+ let key = StorageKey :: AssetDiscount ( asset. clone ( ) ) ;
1629+ env. storage ( ) . instance ( ) . set ( & key, & discount_bps) ;
1630+
1631+ events:: asset_discount_set ( & env, admin, asset, discount_bps) ;
1632+
1633+ Ok ( ( ) )
1634+ }
1635+
1636+ fn get_asset_discount ( env : Env , asset : Address ) -> u32 {
1637+ let key = StorageKey :: AssetDiscount ( asset) ;
1638+ env. storage ( ) . instance ( ) . get ( & key) . unwrap_or ( 0 )
1639+ }
1640+
1641+ fn set_platform_fee_percentage ( env : Env , fee_bps : u32 ) -> Result < ( ) , CrowdfundingError > {
1642+ let admin: Address = env
1643+ . storage ( )
1644+ . instance ( )
1645+ . get ( & StorageKey :: Admin )
1646+ . ok_or ( CrowdfundingError :: NotInitialized ) ?;
1647+ admin. require_auth ( ) ;
1648+
1649+ // Validate fee is not more than 100% (10000 basis points)
1650+ if fee_bps > 10000 {
1651+ return Err ( CrowdfundingError :: InvalidFee ) ;
1652+ }
1653+
1654+ let key = StorageKey :: PlatformFeePercentage ;
1655+ env. storage ( ) . instance ( ) . set ( & key, & fee_bps) ;
1656+
1657+ events:: platform_fee_percentage_set ( & env, admin, fee_bps) ;
1658+
1659+ Ok ( ( ) )
1660+ }
1661+
1662+ fn get_platform_fee_percentage ( env : Env ) -> u32 {
1663+ let key = StorageKey :: PlatformFeePercentage ;
1664+ env. storage ( ) . instance ( ) . get ( & key) . unwrap_or ( 0 )
1665+ }
1666+
1667+ main
15831668 fn get_contract_version ( env : Env ) -> String {
15841669 String :: from_str ( & env, "1.2.0" )
15851670 }
15861671
1672+ feature/asset-based-discount
1673+ fn blacklist_address ( env : Env , address : Address ) -> Result < ( ) , CrowdfundingError > {
1674+ let admin: Address = env
1675+ . storage ( )
1676+ . instance ( )
1677+ . get ( & StorageKey :: Admin )
1678+ . ok_or ( CrowdfundingError :: NotInitialized ) ?;
1679+ admin. require_auth ( ) ;
1680+
1681+ let blacklist_key = StorageKey :: Blacklist ( address. clone ( ) ) ;
1682+ env. storage ( ) . persistent ( ) . set ( & blacklist_key, & true ) ;
1683+
1684+ events:: address_blacklisted ( & env, admin, address) ;
1685+
1686+ Ok ( ( ) )
1687+ }
1688+
1689+ fn unblacklist_address ( env : Env , address : Address ) -> Result < ( ) , CrowdfundingError > {
1690+ let admin: Address = env
1691+ . storage ( )
1692+ . instance ( )
1693+ . get ( & StorageKey :: Admin )
1694+ . ok_or ( CrowdfundingError :: NotInitialized ) ?;
1695+ admin. require_auth ( ) ;
1696+
1697+ let blacklist_key = StorageKey :: Blacklist ( address. clone ( ) ) ;
1698+ env. storage ( ) . persistent ( ) . remove ( & blacklist_key) ;
1699+
1700+ events:: address_unblacklisted ( & env, admin, address) ;
1701+
1702+ Ok ( ( ) )
1703+ }
1704+
1705+ fn is_blacklisted ( env : Env , address : Address ) -> bool {
1706+ let blacklist_key = StorageKey :: Blacklist ( address) ;
1707+ env. storage ( )
1708+ . persistent ( )
1709+ . get ( & blacklist_key)
1710+ . unwrap_or ( false )
1711+ }
1712+
1713+ fn get_campaign_fee_history (
1714+ env : Env ,
1715+ campaign_id : BytesN < 32 > ,
1716+ ) -> Result < i128 , CrowdfundingError > {
1717+ // Validate campaign exists
1718+ Self :: get_campaign ( env. clone ( ) , campaign_id. clone ( ) ) ?;
1719+
1720+ let fee_history_key = StorageKey :: CampaignFeeHistory ( campaign_id) ;
1721+ let current_fees: i128 = env
1722+ . storage ( )
1723+ . persistent ( )
1724+ . get ( & fee_history_key)
1725+ . unwrap_or ( 0 ) ;
1726+ Ok ( current_fees)
1727+
15871728 fn get_pool_contributions_paginated (
15881729 env : Env ,
15891730 pool_id : u64 ,
@@ -1632,6 +1773,7 @@ impl CrowdfundingTrait for CrowdfundingContract {
16321773 }
16331774
16341775 Ok ( result)
1776+ main
16351777 }
16361778}
16371779
0 commit comments