@@ -387,6 +387,7 @@ where
387387 escrow_account : & BRIDGE_POOL_ADDRESS ,
388388 expected_debit : expected_gas_debit,
389389 expected_credit : expected_gas_credit,
390+ transferred_amount : & transfer. gas_fee . amount ,
390391 _kind : PhantomData ,
391392 } ,
392393 token_check : EscrowDelta {
@@ -395,6 +396,7 @@ where
395396 escrow_account : token_check_escrow_acc,
396397 expected_debit : expected_token_debit,
397398 expected_credit : expected_token_credit,
399+ transferred_amount : & transfer. transfer . amount ,
398400 _kind : PhantomData ,
399401 } ,
400402 } )
@@ -409,21 +411,72 @@ struct EscrowDelta<'a, KIND> {
409411 escrow_account : & ' a Address ,
410412 expected_debit : Amount ,
411413 expected_credit : Amount ,
414+ transferred_amount : & ' a Amount ,
412415 _kind : PhantomData < * const KIND > ,
413416}
414417
415418impl < KIND > EscrowDelta < ' _ , KIND > {
416- fn validate_changed_keys ( & self , changed_keys : & BTreeSet < Key > ) -> bool {
419+ /// Validate an [`EscrowDelta`].
420+ ///
421+ /// # Conditions for validation
422+ ///
423+ /// If the transferred amount in the [`EscrowDelta`] is nil,
424+ /// then no keys could have been changed. If the transferred
425+ /// amount is greater than zero, then the appropriate escrow
426+ /// keys must have been written to by some wasm tx.
427+ #[ inline]
428+ fn validate ( & self , changed_keys : & BTreeSet < Key > ) -> bool {
429+ if hints:: unlikely ( self . transferred_amount_is_nil ( ) ) {
430+ self . check_escrow_keys_unchanged ( changed_keys)
431+ } else {
432+ self . check_escrow_keys_changed ( changed_keys)
433+ }
434+ }
435+
436+ /// Check if all required escrow keys in `changed_keys` were modified.
437+ #[ inline]
438+ fn check_escrow_keys_changed ( & self , changed_keys : & BTreeSet < Key > ) -> bool {
417439 let EscrowDelta {
418440 token,
419441 payer_account,
420442 escrow_account,
421443 ..
422444 } = self ;
445+
423446 let owner_key = balance_key ( token, payer_account) ;
424447 let escrow_key = balance_key ( token, escrow_account) ;
448+
425449 changed_keys. contains ( & owner_key) && changed_keys. contains ( & escrow_key)
426450 }
451+
452+ /// Check if no escrow keys in `changed_keys` were modified.
453+ #[ inline]
454+ fn check_escrow_keys_unchanged (
455+ & self ,
456+ changed_keys : & BTreeSet < Key > ,
457+ ) -> bool {
458+ let EscrowDelta {
459+ token,
460+ payer_account,
461+ escrow_account,
462+ ..
463+ } = self ;
464+
465+ let owner_key = balance_key ( token, payer_account) ;
466+ let escrow_key = balance_key ( token, escrow_account) ;
467+
468+ !changed_keys. contains ( & owner_key)
469+ && !changed_keys. contains ( & escrow_key)
470+ }
471+
472+ /// Check if the amount transferred to escrow is nil.
473+ #[ inline]
474+ fn transferred_amount_is_nil ( & self ) -> bool {
475+ let EscrowDelta {
476+ transferred_amount, ..
477+ } = self ;
478+ transferred_amount. is_zero ( )
479+ }
427480}
428481
429482/// There are two checks we must do when minting wNam.
@@ -437,9 +490,9 @@ struct EscrowCheck<'a> {
437490
438491impl EscrowCheck < ' _ > {
439492 #[ inline]
440- fn validate_changed_keys ( & self , changed_keys : & BTreeSet < Key > ) -> bool {
441- self . gas_check . validate_changed_keys ( changed_keys)
442- && self . token_check . validate_changed_keys ( changed_keys)
493+ fn validate ( & self , changed_keys : & BTreeSet < Key > ) -> bool {
494+ self . gas_check . validate ( changed_keys)
495+ && self . token_check . validate ( changed_keys)
443496 }
444497}
445498
@@ -541,7 +594,7 @@ where
541594 let wnam_address = read_native_erc20_address ( & self . ctx . pre ( ) ) ?;
542595 let escrow_checks =
543596 self . determine_escrow_checks ( & wnam_address, & transfer) ?;
544- if !escrow_checks. validate_changed_keys ( keys_changed) {
597+ if !escrow_checks. validate ( keys_changed) {
545598 tracing:: debug!(
546599 ?transfer,
547600 "Missing storage modifications in the Bridge pool"
@@ -1845,4 +1898,94 @@ mod test_bridge_pool_vp {
18451898 Expect :: True ,
18461899 ) ;
18471900 }
1901+
1902+ /// Test that the Bridge pool native VP validates transfers that
1903+ /// do not contain gas fees and no associated changed keys.
1904+ #[ test]
1905+ fn test_no_gas_fees_with_no_changed_keys ( ) {
1906+ let nam_addr = nam ( ) ;
1907+ let delta = EscrowDelta {
1908+ token : Cow :: Borrowed ( & nam_addr) ,
1909+ payer_account : & bertha_address ( ) ,
1910+ escrow_account : & BRIDGE_ADDRESS ,
1911+ expected_debit : Amount :: zero ( ) ,
1912+ expected_credit : Amount :: zero ( ) ,
1913+ // NOTE: testing 0 amount
1914+ transferred_amount : & Amount :: zero ( ) ,
1915+ // NOTE: testing gas fees
1916+ _kind : PhantomData :: < * const GasCheck > ,
1917+ } ;
1918+ // NOTE: testing no changed keys
1919+ let empty_keys = BTreeSet :: new ( ) ;
1920+
1921+ assert ! ( delta. validate( & empty_keys) ) ;
1922+ }
1923+
1924+ /// Test that the Bridge pool native VP rejects transfers that
1925+ /// do not contain gas fees and has associated changed keys.
1926+ #[ test]
1927+ fn test_no_gas_fees_with_changed_keys ( ) {
1928+ let nam_addr = nam ( ) ;
1929+ let delta = EscrowDelta {
1930+ token : Cow :: Borrowed ( & nam_addr) ,
1931+ payer_account : & bertha_address ( ) ,
1932+ escrow_account : & BRIDGE_ADDRESS ,
1933+ expected_debit : Amount :: zero ( ) ,
1934+ expected_credit : Amount :: zero ( ) ,
1935+ // NOTE: testing 0 amount
1936+ transferred_amount : & Amount :: zero ( ) ,
1937+ // NOTE: testing gas fees
1938+ _kind : PhantomData :: < * const GasCheck > ,
1939+ } ;
1940+ let owner_key = balance_key ( & nam_addr, & bertha_address ( ) ) ;
1941+ // NOTE: testing changed keys
1942+ let some_changed_keys = BTreeSet :: from ( [ owner_key] ) ;
1943+
1944+ assert ! ( !delta. validate( & some_changed_keys) ) ;
1945+ }
1946+
1947+ /// Test that the Bridge pool native VP validates transfers
1948+ /// moving no value and with no associated changed keys.
1949+ #[ test]
1950+ fn test_no_amount_with_no_changed_keys ( ) {
1951+ let nam_addr = nam ( ) ;
1952+ let delta = EscrowDelta {
1953+ token : Cow :: Borrowed ( & nam_addr) ,
1954+ payer_account : & bertha_address ( ) ,
1955+ escrow_account : & BRIDGE_ADDRESS ,
1956+ expected_debit : Amount :: zero ( ) ,
1957+ expected_credit : Amount :: zero ( ) ,
1958+ // NOTE: testing 0 amount
1959+ transferred_amount : & Amount :: zero ( ) ,
1960+ // NOTE: testing token transfers
1961+ _kind : PhantomData :: < * const TokenCheck > ,
1962+ } ;
1963+ // NOTE: testing no changed keys
1964+ let empty_keys = BTreeSet :: new ( ) ;
1965+
1966+ assert ! ( delta. validate( & empty_keys) ) ;
1967+ }
1968+
1969+ /// Test that the Bridge pool native VP rejects transfers
1970+ /// moving no value and with associated changed keys.
1971+ #[ test]
1972+ fn test_no_amount_with_changed_keys ( ) {
1973+ let nam_addr = nam ( ) ;
1974+ let delta = EscrowDelta {
1975+ token : Cow :: Borrowed ( & nam_addr) ,
1976+ payer_account : & bertha_address ( ) ,
1977+ escrow_account : & BRIDGE_ADDRESS ,
1978+ expected_debit : Amount :: zero ( ) ,
1979+ expected_credit : Amount :: zero ( ) ,
1980+ // NOTE: testing 0 amount
1981+ transferred_amount : & Amount :: zero ( ) ,
1982+ // NOTE: testing token transfers
1983+ _kind : PhantomData :: < * const TokenCheck > ,
1984+ } ;
1985+ let owner_key = balance_key ( & nam_addr, & bertha_address ( ) ) ;
1986+ // NOTE: testing changed keys
1987+ let some_changed_keys = BTreeSet :: from ( [ owner_key] ) ;
1988+
1989+ assert ! ( !delta. validate( & some_changed_keys) ) ;
1990+ }
18481991}
0 commit comments