@@ -592,6 +592,16 @@ fn payer_payment_timestamps_key(invoice_id: u64, payer: &Address) -> (Symbol, u6
592592 ( symbol_short ! ( "pay_ts" ) , invoice_id, payer. clone ( ) )
593593}
594594
595+ /// Issue #451: per-invoice required memo hash.
596+ fn required_memo_hash_key ( invoice_id : u64 ) -> ( Symbol , u64 ) {
597+ ( symbol_short ! ( "req_memo" ) , invoice_id)
598+ }
599+
600+ /// Issue #452: per-invoice tags.
601+ fn invoice_tags_key ( invoice_id : u64 ) -> ( Symbol , u64 ) {
602+ ( symbol_short ! ( "inv_tags" ) , invoice_id)
603+ }
604+
595605fn invoice_rate_limit_window_key ( ) -> Symbol {
596606 symbol_short ! ( "inv_rl_w" )
597607}
@@ -6548,6 +6558,50 @@ impl SplitContract {
65486558 events:: payment_matched ( & env, memo, memo, & payer) ;
65496559 }
65506560
6561+ /// Issue #451: Creator sets a required payment memo hash on an invoice.
6562+ pub fn set_invoice_memo ( env : Env , creator : Address , invoice_id : u64 , memo_hash : BytesN < 32 > ) {
6563+ require_not_paused ( & env) ;
6564+ creator. require_auth ( ) ;
6565+ let invoice = load_invoice ( & env, invoice_id) ;
6566+ assert ! ( invoice. creator == creator, "only creator can set memo" ) ;
6567+ assert ! ( invoice. status == InvoiceStatus :: Pending , "invoice is not pending" ) ;
6568+ env. storage ( ) . persistent ( ) . set ( & required_memo_hash_key ( invoice_id) , & memo_hash) ;
6569+ }
6570+
6571+ /// Issue #451: Pay an invoice with memo validation.
6572+ pub fn pay_with_validated_memo (
6573+ env : Env ,
6574+ payer : Address ,
6575+ invoice_id : u64 ,
6576+ payment_memo : BytesN < 32 > ,
6577+ amount : i128 ,
6578+ nonce : u64 ,
6579+ auto_convert : bool ,
6580+ via : Option < Address > ,
6581+ ) {
6582+ require_not_paused ( & env) ;
6583+ payer. require_auth ( ) ;
6584+ if let Some ( required) = env. storage ( ) . persistent ( ) . get :: < _ , BytesN < 32 > > ( & required_memo_hash_key ( invoice_id) ) {
6585+ assert ! ( payment_memo == required, "MemoMismatch" ) ;
6586+ }
6587+ Self :: _pay ( & env, & payer, invoice_id, amount, nonce, auto_convert, via, None , false ) ;
6588+ events:: payment_matched ( & env, invoice_id, invoice_id, & payer) ;
6589+ }
6590+
6591+ /// Issue #452: Set tags on an invoice for searchable categorisation.
6592+ pub fn set_invoice_tags ( env : Env , creator : Address , invoice_id : u64 , tags : Vec < String > ) {
6593+ require_not_paused ( & env) ;
6594+ creator. require_auth ( ) ;
6595+ let invoice = load_invoice ( & env, invoice_id) ;
6596+ assert ! ( invoice. creator == creator, "only creator can set tags" ) ;
6597+ env. storage ( ) . persistent ( ) . set ( & invoice_tags_key ( invoice_id) , & tags) ;
6598+ }
6599+
6600+ /// Issue #452: Get tags for an invoice.
6601+ pub fn get_invoice_tags ( env : Env , invoice_id : u64 ) -> Vec < String > {
6602+ env. storage ( ) . persistent ( ) . get ( & invoice_tags_key ( invoice_id) ) . unwrap_or_else ( || Vec :: new ( & env) )
6603+ }
6604+
65516605 /// Claim vesting cliff share after cliff timestamp has passed (issue #27).
65526606 ///
65536607 /// Requires that the invoice status is Released and the cliff (if set) has passed.
0 commit comments