Skip to content

Instantly share code, notes, and snippets.

@BrendanChou
Last active June 23, 2022 01:08
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BrendanChou/88a2eeb80947ff00bcf58ffdafeaeb61 to your computer and use it in GitHub Desktop.
Save BrendanChou/88a2eeb80947ff00bcf58ffdafeaeb61 to your computer and use it in GitHub Desktop.
Brendan's implementation of ERC20SafeTransfer
// Made as proof-of-concept fix for https://github.com/ethereum/solidity/issues/4116
pragma solidity 0.4.24;
library TokenInteract {
function balanceOf(
address token,
address owner
)
internal
view
returns (uint256)
{
return GeneralERC20(token).balanceOf(owner);
}
function allowance(
address token,
address owner,
address spender
)
internal
view
returns (uint256)
{
return GeneralERC20(token).allowance(owner, spender);
}
function approve(
address token,
address spender,
uint256 amount
)
internal
{
GeneralERC20(token).approve(spender, amount);
require(
checkSuccess(),
"TokenInteract#approve: Approval failed"
);
}
function transfer(
address token,
address to,
uint256 amount
)
internal
{
GeneralERC20(token).transfer(to, amount);
require(
checkSuccess(),
"TokenInteract#transfer: Transfer failed"
);
}
function transferFrom(
address token,
address from,
address to,
uint256 amount
)
internal
{
GeneralERC20(token).transferFrom(from, to, amount);
require(
checkSuccess(),
"TokenInteract#transferFrom: TransferFrom failed"
);
}
/**
* Checks the return value of the previous function. Returns true if the previous function
* function returned 32 non-zero bytes or returned zero bytes.
*/
function checkSuccess(
)
private
pure
returns (bool)
{
uint256 returnValue = 0;
/* solium-disable-next-line security/no-inline-assembly */
assembly {
// check number of bytes returned from last function call
switch returndatasize
// no bytes returned: assume success
case 0x0 {
returnValue := 1
}
// 32 bytes returned: check if non-zero
case 0x20 {
// copy 32 bytes into scratch space
returndatacopy(0x0, 0x0, 0x20)
// load those bytes into returnValue
returnValue := mload(0x0)
}
// not sure what was returned: dont mark as success
default { }
}
return returnValue != 0;
}
}
/**
* Interface for using ERC20 Tokens. We have to use a special interface to call ERC20 functions so
* that we dont automatically revert when calling non-compliant tokens that have no return value for
* transfer(), transferFrom(), or approve().
*/
interface GeneralERC20 {
function totalSupply(
)
external
view
returns (uint256);
function balanceOf(
address who
)
external
view
returns (uint256);
function allowance(
address owner,
address spender
)
external
view
returns (uint256);
function transfer(
address to,
uint256 value
)
external;
function transferFrom(
address from,
address to,
uint256 value
)
external;
function approve(
address spender,
uint256 value
)
external;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment