文件 1 的 2:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 2 的 2:Swap0x.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IMulticall {
function multicall(bytes[] calldata data)
external
payable
returns (bytes[] memory results);
}
abstract contract Multicall is IMulticall {
function _getRevertMsg(bytes memory _returnData)
internal
pure
returns (string memory)
{
if (_returnData.length < 68) return "Transaction reverted silently";
assembly {
_returnData := add(_returnData, 0x04)
}
return abi.decode(_returnData, (string));
}
function multicall(bytes[] calldata data)
public
payable
override
returns (bytes[] memory results)
{
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
(bool success, bytes memory result) = address(this).delegatecall(
data[i]
);
require(success, _getRevertMsg(result));
results[i] = result;
}
}
}
contract Swap0x is Multicall {
receive() external payable {}
function swap(
address sellToken,
address buyToken,
uint256 sellAmount,
address allowanceTarget,
address payable swapTarget,
bytes calldata swapData
) public payable {
if (sellToken != address(0)) {
IERC20(sellToken).transferFrom(
msg.sender,
address(this),
sellAmount
);
} else {
require(msg.value >= sellAmount, "Swap0x: ETH value invalid");
}
if (allowanceTarget != address(0) && sellToken != address(0)) {
require(
IERC20(sellToken).approve(allowanceTarget, type(uint256).max),
"Swap0x: allowance failed"
);
}
uint256 buyTokenBalanceBefore = 0;
if (buyToken != address(0)) {
buyTokenBalanceBefore = IERC20(buyToken).balanceOf(address(this));
} else {
buyTokenBalanceBefore = address(this).balance;
}
if (sellToken != address(0)) {
(bool success, bytes memory retdata) = swapTarget.call(swapData);
require(success, _getRevertMsg(retdata));
} else {
(bool success, bytes memory retdata) = swapTarget.call{
value: sellAmount
}(swapData);
require(success, _getRevertMsg(retdata));
}
if (buyToken != address(0)) {
uint256 buyTokenBalanceAfter = IERC20(buyToken).balanceOf(
address(this)
);
uint256 boughtAmount = buyTokenBalanceAfter - buyTokenBalanceBefore;
IERC20(buyToken).transfer(msg.sender, boughtAmount);
} else {
uint256 buyTokenBalanceAfter = address(this).balance;
uint256 boughtAmount = buyTokenBalanceAfter - buyTokenBalanceBefore;
payable(msg.sender).transfer(boughtAmount);
}
}
}
{
"compilationTarget": {
"contracts/Swap0x.sol": "Swap0x"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"address","name":"allowanceTarget","type":"address"},{"internalType":"address payable","name":"swapTarget","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"}],"name":"swap","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]