@@ -177,12 +177,7 @@ contract ICS20Transfer is
177177 );
178178 // transfer the tokens to us with permit
179179 IEscrow escrow = _getOrCreateEscrow (msg_.sourceClient);
180- _getPermit2 ().permitTransferFrom (
181- permit,
182- ISignatureTransfer.SignatureTransferDetails ({ to: address (escrow), requestedAmount: msg_.amount }),
183- _msgSender (),
184- signature
185- );
180+ _transferFromWithPermit2 (_msgSender (), address (escrow), msg_.denom, msg_.amount, permit, signature);
186181 escrow.recvCallback (msg_.denom, _msgSender (), msg_.amount);
187182
188183 return _sendTransferFromEscrowWithSender (msg_, address (escrow), _msgSender ());
@@ -435,6 +430,50 @@ contract ICS20Transfer is
435430 );
436431 }
437432
433+ /// @notice Transfer tokens from sender to receiver using permit2
434+ /// @param sender The sender of the tokens
435+ /// @param receiver The receiver of the tokens
436+ /// @param tokenContract The address of the token contract
437+ /// @param amount The amount of tokens to transfer
438+ /// @param permit The permit data
439+ /// @param signature The signature of the permit data
440+ // NOTE: Balance reentrancy here is intentionally allowed, as we are checking the balance before and after
441+ // slither-disable-next-line reentrancy-balance
442+ function _transferFromWithPermit2 (
443+ address sender ,
444+ address receiver ,
445+ address tokenContract ,
446+ uint256 amount ,
447+ ISignatureTransfer.PermitTransferFrom calldata permit ,
448+ bytes calldata signature
449+ )
450+ private
451+ {
452+ // we snapshot current balance of this token
453+ uint256 ourStartingBalance = IERC20 (tokenContract).balanceOf (receiver);
454+
455+ _getPermit2 ().permitTransferFrom (
456+ permit,
457+ ISignatureTransfer.SignatureTransferDetails ({ to: receiver, requestedAmount: amount }),
458+ sender,
459+ signature
460+ );
461+
462+ // check what this particular ERC20 implementation actually gave us, since it doesn't
463+ // have to be at all related to the _amount
464+ uint256 actualEndingBalance = IERC20 (tokenContract).balanceOf (receiver);
465+
466+ uint256 expectedEndingBalance = ourStartingBalance + amount;
467+ // a very strange ERC20 may trigger this condition, if we didn't have this we would
468+ // underflow, so it's mostly just an error message printer
469+ // NOTE: This is not a security check, but rather a sanity check.
470+ // slither-disable-next-line incorrect-equality
471+ require (
472+ actualEndingBalance > ourStartingBalance && actualEndingBalance == expectedEndingBalance,
473+ ICS20UnexpectedERC20Balance (expectedEndingBalance, actualEndingBalance)
474+ );
475+ }
476+
438477 /// @notice Finds a contract in the foreign mapping, or creates a new IBCERC20 contract
439478 /// @notice This function will never return address(0)
440479 /// @param fullDenomPath The full path denom to find or create the contract for (which will be the name for the
0 commit comments