fix: Migrate transformers to smart contract compatible unsafeTransformerTransfer [TKR-587] (#594)

* Use `call` instead of `transfer` in `LibERC20Transformer`

* Since `transfer` only forwards 2300 gas it can cause an `out of gas`
revert when the receipient is a smart contract.

* Add `unsafeTransformerTransfer` and migrate `transformers` to use
`unsafeTransformerTransfer` instead of `transformerTransfer`

* Update .prettierignore
This commit is contained in:
Kyu 2022-10-28 11:39:22 -07:00 committed by GitHub
parent 66846c8aec
commit 4ace7c8c43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 25 additions and 4 deletions

View File

@ -60,6 +60,7 @@ lib
/contracts/dev-utils/test/generated-wrappers /contracts/dev-utils/test/generated-wrappers
/contracts/dev-utils/generated-artifacts /contracts/dev-utils/generated-artifacts
/contracts/dev-utils/test/generated-artifacts /contracts/dev-utils/test/generated-artifacts
/contracts/zero-ex/foundry-artifacts
/contracts/zero-ex/generated-wrappers /contracts/zero-ex/generated-wrappers
/contracts/zero-ex/test/generated-wrappers /contracts/zero-ex/test/generated-wrappers
/contracts/zero-ex/generated-artifacts /contracts/zero-ex/generated-artifacts

View File

@ -61,7 +61,7 @@ contract AffiliateFeeTransformer is Transformer {
amount = LibERC20Transformer.getTokenBalanceOf(fees[i].token, address(this)); amount = LibERC20Transformer.getTokenBalanceOf(fees[i].token, address(this));
} }
if (amount != 0) { if (amount != 0) {
fees[i].token.transformerTransfer(fees[i].recipient, amount); fees[i].token.unsafeTransformerTransfer(fees[i].recipient, amount);
} }
} }

View File

@ -34,7 +34,9 @@ library LibERC20Transformer {
/// This is just `keccak256('TRANSFORMER_SUCCESS')`. /// This is just `keccak256('TRANSFORMER_SUCCESS')`.
bytes4 internal constant TRANSFORMER_SUCCESS = 0x13c9929e; bytes4 internal constant TRANSFORMER_SUCCESS = 0x13c9929e;
/// @dev Transfer ERC20 tokens and ETH. /// @dev Transfer ERC20 tokens and ETH. Since it relies on `transfer` it may run out of gas when
/// the `recipient` is a smart contract wallet. See `unsafeTransformerTransfer` for smart contract
/// compatible transfer.
/// @param token An ERC20 or the ETH pseudo-token address (`ETH_TOKEN_ADDRESS`). /// @param token An ERC20 or the ETH pseudo-token address (`ETH_TOKEN_ADDRESS`).
/// @param to The recipient. /// @param to The recipient.
/// @param amount The transfer amount. /// @param amount The transfer amount.
@ -50,6 +52,24 @@ library LibERC20Transformer {
} }
} }
/// @dev Transfer ERC20 tokens and ETH. For ETH transfer. It's not safe from re-entrancy attacks and the
/// caller is responsible for gurading against a potential re-entrancy attack.
/// @param token An ERC20 or the ETH pseudo-token address (`ETH_TOKEN_ADDRESS`).
/// @param to The recipient.
/// @param amount The transfer amount.
function unsafeTransformerTransfer(
IERC20TokenV06 token,
address payable to,
uint256 amount
) internal {
if (isTokenETH(token)) {
(bool sent, ) = to.call{value: amount}("");
require(sent, "LibERC20Transformer/FAILED_TO_SEND_ETHER");
} else {
token.compatTransfer(to, amount);
}
}
/// @dev Check if a token is the ETH pseudo-token. /// @dev Check if a token is the ETH pseudo-token.
/// @param token The token to check. /// @param token The token to check.
/// @return isETH `true` if the token is the ETH pseudo-token. /// @return isETH `true` if the token is the ETH pseudo-token.

View File

@ -65,7 +65,7 @@ contract PayTakerTransformer is Transformer {
amount = data.tokens[i].getTokenBalanceOf(address(this)); amount = data.tokens[i].getTokenBalanceOf(address(this));
} }
if (amount != 0) { if (amount != 0) {
data.tokens[i].transformerTransfer(context.recipient, amount); data.tokens[i].unsafeTransformerTransfer(context.recipient, amount);
} }
} }
return LibERC20Transformer.TRANSFORMER_SUCCESS; return LibERC20Transformer.TRANSFORMER_SUCCESS;

View File

@ -53,7 +53,7 @@ contract PositiveSlippageFeeTransformer is Transformer {
uint256 transformerAmount = LibERC20Transformer.getTokenBalanceOf(fee.token, address(this)); uint256 transformerAmount = LibERC20Transformer.getTokenBalanceOf(fee.token, address(this));
if (transformerAmount > fee.bestCaseAmount) { if (transformerAmount > fee.bestCaseAmount) {
uint256 positiveSlippageAmount = transformerAmount - fee.bestCaseAmount; uint256 positiveSlippageAmount = transformerAmount - fee.bestCaseAmount;
fee.token.transformerTransfer(fee.recipient, positiveSlippageAmount); fee.token.unsafeTransformerTransfer(fee.recipient, positiveSlippageAmount);
} }
return LibERC20Transformer.TRANSFORMER_SUCCESS; return LibERC20Transformer.TRANSFORMER_SUCCESS;