@@ -5098,3 +5098,206 @@ fn test_migrate_escrow_zero_balance() {
50985098 let tk = token_client ( & env, & token_id) ;
50995099 assert_eq ! ( tk. balance( & new_contract) , 0 ) ;
51005100}
5101+
5102+
5103+ // ---------------------------------------------------------------------------
5104+ // Creator Self-Imposed Spending Limit Tests (Issue #241)
5105+ // ---------------------------------------------------------------------------
5106+
5107+ #[ test]
5108+ fn test_creator_self_limit_immediate_lower ( ) {
5109+ let ( env, contract_id, token_id) = setup ( ) ;
5110+ let c = client ( & env, & contract_id) ;
5111+
5112+ let creator = Address :: generate ( & env) ;
5113+ let recipient = Address :: generate ( & env) ;
5114+
5115+ env. ledger ( ) . set_timestamp ( 1_000 ) ;
5116+
5117+ // Creator sets self limit to 500
5118+ c. set_self_limit ( & creator, & 500_i128 ) ;
5119+ assert_eq ! ( c. get_self_limit( & creator) , 500 ) ;
5120+
5121+ // Creator immediately lowers it to 200
5122+ c. set_self_limit ( & creator, & 200_i128 ) ;
5123+ assert_eq ! ( c. get_self_limit( & creator) , 200 ) ;
5124+ }
5125+
5126+ #[ test]
5127+ #[ should_panic( expected = "cannot raise limit directly" ) ]
5128+ fn test_creator_self_limit_immediate_raise_blocked ( ) {
5129+ let ( env, contract_id, token_id) = setup ( ) ;
5130+ let c = client ( & env, & contract_id) ;
5131+
5132+ let creator = Address :: generate ( & env) ;
5133+
5134+ env. ledger ( ) . set_timestamp ( 1_000 ) ;
5135+
5136+ // Creator sets self limit to 200
5137+ c. set_self_limit ( & creator, & 200_i128 ) ;
5138+ assert_eq ! ( c. get_self_limit( & creator) , 200 ) ;
5139+
5140+ // Creator attempts to immediately raise it (should panic)
5141+ c. set_self_limit ( & creator, & 500_i128 ) ;
5142+ }
5143+
5144+ #[ test]
5145+ fn test_creator_self_limit_raise_via_timelock ( ) {
5146+ let ( env, contract_id, token_id) = setup ( ) ;
5147+ let c = client ( & env, & contract_id) ;
5148+ let admin = Address :: generate ( & env) ;
5149+ let treasury = Address :: generate ( & env) ;
5150+ let creator = Address :: generate ( & env) ;
5151+
5152+ // Initialize with a timelock delay of 7 days
5153+ let timelock_secs = 7 * 24 * 60 * 60u64 ; // 7 days in seconds
5154+ c. initialize ( & admin, & 0_i128 , & treasury, & token_id, & 0_u32 , & None , & 0_u32 , & 0_u32 , & 0_u64 ) ;
5155+ c. set_timelock_secs ( & admin, timelock_secs) ;
5156+
5157+ env. ledger ( ) . set_timestamp ( 1_000 ) ;
5158+
5159+ // Creator sets self limit to 200
5160+ c. set_self_limit ( & creator, & 200_i128 ) ;
5161+ assert_eq ! ( c. get_self_limit( & creator) , 200 ) ;
5162+
5163+ // Creator requests to raise limit to 500
5164+ let action_id = c. request_raise_self_limit ( & creator, & 500_i128 ) ;
5165+
5166+ // Attempt to use the raised limit immediately (should still be 200)
5167+ assert_eq ! ( c. get_self_limit( & creator) , 200 ) ;
5168+
5169+ // Advance time past timelock
5170+ env. ledger ( ) . set_timestamp ( 1_000 + timelock_secs + 1 ) ;
5171+
5172+ // Execute the action
5173+ c. execute_action ( & action_id) ;
5174+
5175+ // Now the limit should be raised to 500
5176+ assert_eq ! ( c. get_self_limit( & creator) , 500 ) ;
5177+ }
5178+
5179+ #[ test]
5180+ fn test_creator_self_limit_enforced_in_create_invoice ( ) {
5181+ let ( env, contract_id, token_id) = setup ( ) ;
5182+ let c = client ( & env, & contract_id) ;
5183+
5184+ let creator = Address :: generate ( & env) ;
5185+ let payer = Address :: generate ( & env) ;
5186+ let recipient = Address :: generate ( & env) ;
5187+
5188+ StellarAssetClient :: new ( & env, & token_id) . mint ( & payer, & 1_000_i128 ) ;
5189+ env. ledger ( ) . set_timestamp ( 1_000 ) ;
5190+
5191+ // Creator sets self limit to 300
5192+ c. set_self_limit ( & creator, & 300_i128 ) ;
5193+
5194+ // Create invoice for 200 - should succeed
5195+ let id1 = make_invoice ( & env, & c, & creator, & recipient, 200 , & token_id, 9_999 ) ;
5196+ assert_eq ! ( c. get_invoice( & id1) . status, InvoiceStatus :: Pending ) ;
5197+
5198+ // Try to create another invoice for 200 - should fail (total would be 400 > 300)
5199+ let err_result = std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
5200+ make_invoice ( & env, & c, & creator, & recipient, 200 , & token_id, 9_999 )
5201+ } ) ) ;
5202+ assert ! ( err_result. is_err( ) , "Expected panic when self limit exceeded" ) ;
5203+ }
5204+
5205+ #[ test]
5206+ fn test_creator_self_limit_daily_reset ( ) {
5207+ let ( env, contract_id, token_id) = setup ( ) ;
5208+ let c = client ( & env, & contract_id) ;
5209+
5210+ let creator = Address :: generate ( & env) ;
5211+ let recipient = Address :: generate ( & env) ;
5212+
5213+ StellarAssetClient :: new ( & env, & token_id) . mint ( & creator, & 1_000_i128 ) ;
5214+ env. ledger ( ) . set_timestamp ( 1_000 ) ;
5215+
5216+ // Creator sets self limit to 500
5217+ c. set_self_limit ( & creator, & 500_i128 ) ;
5218+
5219+ // Create invoice for 300
5220+ let _id1 = make_invoice ( & env, & c, & creator, & recipient, 300 , & token_id, 9_999 ) ;
5221+ assert_eq ! ( c. get_self_limit_used( & creator) , 300 ) ;
5222+
5223+ // Try to create another invoice for 300 on the same day (would exceed 500)
5224+ let err_result = std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
5225+ make_invoice ( & env, & c, & creator, & recipient, 300 , & token_id, 9_999 )
5226+ } ) ) ;
5227+ assert ! ( err_result. is_err( ) , "Expected panic when exceeding daily self limit" ) ;
5228+
5229+ // Advance to next day (add 86400 seconds)
5230+ env. ledger ( ) . set_timestamp ( 1_000 + 86_400 + 1 ) ;
5231+
5232+ // Now creating invoice for 300 should succeed (daily reset)
5233+ let _id2 = make_invoice ( & env, & c, & creator, & recipient, 300 , & token_id, 9_999 ) ;
5234+ assert_eq ! ( c. get_self_limit_used( & creator) , 300 ) ; // Reset for new day
5235+ }
5236+
5237+ #[ test]
5238+ fn test_creator_self_limit_zero_means_unlimited ( ) {
5239+ let ( env, contract_id, token_id) = setup ( ) ;
5240+ let c = client ( & env, & contract_id) ;
5241+
5242+ let creator = Address :: generate ( & env) ;
5243+ let recipient = Address :: generate ( & env) ;
5244+
5245+ StellarAssetClient :: new ( & env, & token_id) . mint ( & creator, & 10_000_i128 ) ;
5246+ env. ledger ( ) . set_timestamp ( 1_000 ) ;
5247+
5248+ // Creator sets self limit to 0 (no limit)
5249+ c. set_self_limit ( & creator, & 0_i128 ) ;
5250+
5251+ // Create multiple large invoices - should all succeed
5252+ let _id1 = make_invoice ( & env, & c, & creator, & recipient, 5_000 , & token_id, 9_999 ) ;
5253+ let _id2 = make_invoice ( & env, & c, & creator, & recipient, 3_000 , & token_id, 9_999 ) ;
5254+ let _id3 = make_invoice ( & env, & c, & creator, & recipient, 1_000 , & token_id, 9_999 ) ;
5255+
5256+ // No panic should occur
5257+ }
5258+
5259+ #[ test]
5260+ #[ should_panic( expected = "only creator can" ) ]
5261+ fn test_creator_self_limit_requires_creator_auth ( ) {
5262+ let ( env, contract_id, token_id) = setup ( ) ;
5263+ let c = client ( & env, & contract_id) ;
5264+
5265+ let creator = Address :: generate ( & env) ;
5266+ let other_addr = Address :: generate ( & env) ;
5267+
5268+ // Try to set limit for creator with different address's auth (should panic)
5269+ let _old_auth = env. mock_all_auths_allow_address ( other_addr. clone ( ) ) ;
5270+ c. set_self_limit ( & creator, & 500_i128 ) ;
5271+ }
5272+
5273+ #[ test]
5274+ fn test_creator_self_limit_with_admin_cap ( ) {
5275+ let ( env, contract_id, token_id) = setup ( ) ;
5276+ let c = client ( & env, & contract_id) ;
5277+ let admin = Address :: generate ( & env) ;
5278+ let treasury = Address :: generate ( & env) ;
5279+
5280+ let creator = Address :: generate ( & env) ;
5281+ let recipient = Address :: generate ( & env) ;
5282+
5283+ c. initialize ( & admin, & 0_i128 , & treasury, & token_id, & 0_u32 , & None , & 0_u32 , & 0_u32 , & 0_u64 ) ;
5284+
5285+ StellarAssetClient :: new ( & env, & token_id) . mint ( & creator, & 1_000_i128 ) ;
5286+ env. ledger ( ) . set_timestamp ( 1_000 ) ;
5287+
5288+ // Set admin cap to 600
5289+ c. set_creator_volume_cap ( & admin, & creator, & 600_i128 ) ;
5290+
5291+ // Set creator self limit to 400
5292+ c. set_self_limit ( & creator, & 400_i128 ) ;
5293+
5294+ // Create invoice for 300 - should succeed
5295+ let _id1 = make_invoice ( & env, & c, & creator, & recipient, 300 , & token_id, 9_999 ) ;
5296+
5297+ // Try to create invoice for 200 - should fail
5298+ // (would exceed self limit of 400, even though admin cap is 600)
5299+ let err_result = std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
5300+ make_invoice ( & env, & c, & creator, & recipient, 200 , & token_id, 9_999 )
5301+ } ) ) ;
5302+ assert ! ( err_result. is_err( ) , "Expected panic when exceeding self limit" ) ;
5303+ }
0 commit comments