Skip to content

My #2

@mymusic23

Description

@mymusic23

https://github.com/BTCGPU/BTCGPU/releases/tag/v0.17.3// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity ^0.7.6;

import "../interfaces/IERC20.sol";

/// @title Gnosis Protocol v2 Safe ERC20 Transfer Library
/// @author Gnosis Developers
/// @dev Gas-efficient version of Openzeppelin's SafeERC20 contract that notably
/// does not revert when calling a non-contract.
library GPv2SafeERC20 {
/// @dev Wrapper around a call to the ERC20 function transfer that reverts
/// also when the token returns false.
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
bytes4 selector_ = token.transfer.selector;

    // solhint-disable-next-line no-inline-assembly
    assembly {
        let freeMemoryPointer := mload(0x40)
        mstore(freeMemoryPointer, selector_)
        mstore(
            add(freeMemoryPointer, 4),
            and(to, 0xffffffffffffffffffffffffffffffffffffffff)
        )
        mstore(add(freeMemoryPointer, 36), value)

        if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)) {
            returndatacopy(0, 0, returndatasize())
            revert(0, returndatasize())
        }
    }

    require(getLastTansferResult(token), "GPv2: failed transfer");
}

/// @dev Wrapper around a call to the ERC20 function `transferFrom` that
/// reverts also when the token returns `false`.
function safeTransferFrom(
    IERC20 token,
    address from,
    address to,
    uint256 value
) internal {
    bytes4 selector_ = token.transferFrom.selector;

    // solhint-disable-next-line no-inline-assembly
    assembly {
        let freeMemoryPointer := mload(0x40)
        mstore(freeMemoryPointer, selector_)
        mstore(
            add(freeMemoryPointer, 4),
            and(from, 0xffffffffffffffffffffffffffffffffffffffff)
        )
        mstore(
            add(freeMemoryPointer, 36),
            and(to, 0xffffffffffffffffffffffffffffffffffffffff)
        )
        mstore(add(freeMemoryPointer, 68), value)

        if iszero(call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)) {
            returndatacopy(0, 0, returndatasize())
            revert(0, returndatasize())
        }
    }

    require(getLastTansferResult(token), "GPv2: failed transferFrom");
}

/// @dev Verifies that the last return was a successful `transfer*` call.
/// This is done by checking that the return data is either empty, or
/// is a valid ABI encoded boolean.
function getLastTansferResult(IERC20 token)
    private
    view
    returns (bool success)
{
    // NOTE: Inspecting previous return data requires assembly. Note that
    // we write the return data to memory 0 in the case where the return
    // data size is 32, this is OK since the first 64 bytes of memory are
    // reserved by Solidy as a scratch space that can be used within
    // assembly blocks.
    // <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html>
    // solhint-disable-next-line no-inline-assembly
    assembly {
        /// @dev Revert with an ABI encoded Solidity error with a message
        /// that fits into 32-bytes.
        ///
        /// An ABI encoded Solidity error has the following memory layout:
        ///
        /// ------------+----------------------------------
        ///  byte range | value
        /// ------------+----------------------------------
        ///  0x00..0x04 |        selector("Error(string)")
        ///  0x04..0x24 |      string offset (always 0x20)
        ///  0x24..0x44 |                    string length
        ///  0x44..0x64 | string value, padded to 32-bytes
        function revertWithMessage(length, message) {
            mstore(0x00, "\x08\xc3\x79\xa0")
            mstore(0x04, 0x20)
            mstore(0x24, length)
            mstore(0x44, message)
            revert(0x00, 0x64)
        }

        switch returndatasize()
            // Non-standard ERC20 transfer without return.
            case 0 {
                // NOTE: When the return data size is 0, verify that there
                // is code at the address. This is done in order to maintain
                // compatibility with Solidity calling conventions.
                // <https://docs.soliditylang.org/en/v0.7.6/control-structures.html#external-function-calls>
                if iszero(extcodesize(token)) {
                    revertWithMessage(20, "GPv2: not a contract")
                }

                success := 1
            }
            // Standard ERC20 transfer returning boolean success value.
            case 32 {
                returndatacopy(0, 0, returndatasize())

                // NOTE: For ABI encoding v1, any non-zero value is accepted
                // as `true` for a boolean. In order to stay compatible with
                // OpenZeppelin's `SafeERC20` library which is known to work
                // with the existing ERC20 implementation we care about,
                // make sure we return success for any non-zero return value
                // from the `transfer*` call.
                success := iszero(iszero(mload(0)))
            }
            default {
                revertWithMessage(31, "GPv2: malformed transfer result")
            }
    }
}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions