编译器
0.8.22+commit.4fc1097e
文件 1 的 8:IERC20.sol
pragma solidity ^0.8.17;
interface IERC20 {
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(
address recipient,
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 sender,
address recipient,
uint256 amount
) external returns (bool);
}
文件 2 的 8:IThorchainRouterV4.sol
pragma solidity ^0.8.17;
interface IThorchainRouterV4 {
function depositWithExpiry(
address payable vault,
address asset,
uint amount,
string memory memo,
uint expiration
) external payable;
}
文件 3 的 8:Owners.sol
pragma solidity ^0.8.17;
abstract contract Owners {
event OwnerSet(address indexed owner, bool active);
mapping(address => bool) public owners;
modifier isOwner() {
require(owners[msg.sender], "Unauthorized");
_;
}
function _setOwner(address owner, bool active) internal virtual {
owners[owner] = active;
emit OwnerSet(owner, active);
}
function setOwner(address owner, bool active) external virtual isOwner {
_setOwner(owner, active);
}
}
文件 4 的 8:ReentrancyGuard.sol
pragma solidity >=0.8.0;
abstract contract ReentrancyGuard {
uint256 private locked = 1;
modifier nonReentrant() {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
}
文件 5 的 8:SafeTransferLib.sol
pragma solidity >=0.8.0;
library SafeTransferLib {
function safeTransferETH(address to, uint256 amount) internal {
bool callStatus;
assembly {
callStatus := call(gas(), to, amount, 0, 0, 0, 0)
}
require(callStatus, "ETH_TRANSFER_FAILED");
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 amount
) internal {
bool callStatus;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(
freeMemoryPointer,
0x23b872dd00000000000000000000000000000000000000000000000000000000
)
mstore(
add(freeMemoryPointer, 4),
and(from, 0xffffffffffffffffffffffffffffffffffffffff)
)
mstore(
add(freeMemoryPointer, 36),
and(to, 0xffffffffffffffffffffffffffffffffffffffff)
)
mstore(add(freeMemoryPointer, 68), amount)
callStatus := call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)
}
require(
didLastOptionalReturnCallSucceed(callStatus),
"TRANSFER_FROM_FAILED"
);
}
function safeTransfer(address token, address to, uint256 amount) internal {
bool callStatus;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(
freeMemoryPointer,
0xa9059cbb00000000000000000000000000000000000000000000000000000000
)
mstore(
add(freeMemoryPointer, 4),
and(to, 0xffffffffffffffffffffffffffffffffffffffff)
)
mstore(add(freeMemoryPointer, 36), amount)
callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
}
require(
didLastOptionalReturnCallSucceed(callStatus),
"TRANSFER_FAILED"
);
}
function safeApprove(address token, address to, uint256 amount) internal {
bool callStatus;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(
freeMemoryPointer,
0x095ea7b300000000000000000000000000000000000000000000000000000000
)
mstore(
add(freeMemoryPointer, 4),
and(to, 0xffffffffffffffffffffffffffffffffffffffff)
)
mstore(add(freeMemoryPointer, 36), amount)
callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
}
require(didLastOptionalReturnCallSucceed(callStatus), "APPROVE_FAILED");
}
function didLastOptionalReturnCallSucceed(
bool callStatus
) private pure returns (bool success) {
assembly {
let returnDataSize := returndatasize()
if iszero(callStatus) {
returndatacopy(0, 0, returnDataSize)
revert(0, returnDataSize)
}
switch returnDataSize
case 32 {
returndatacopy(0, 0, returnDataSize)
success := iszero(iszero(mload(0)))
}
case 0 {
success := 1
}
default {
success := 0
}
}
}
}
文件 6 的 8:TSAggregatorTokenTransferProxy.sol
pragma solidity ^0.8.17;
import {SafeTransferLib} from "../../lib/SafeTransferLib.sol";
import {Owners} from "../../lib/Owners.sol";
contract TSAggregatorTokenTransferProxy is Owners {
using SafeTransferLib for address;
constructor() {
_setOwner(msg.sender, true);
}
function transferTokens(
address token,
address from,
address to,
uint256 amount
) external isOwner {
require(from == tx.origin || _isContract(from), "Invalid from address");
token.safeTransferFrom(from, to, amount);
}
function _isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
}
文件 7 的 8:TSAggregator_V5.sol
pragma solidity ^0.8.17;
import {SafeTransferLib} from "../../lib/SafeTransferLib.sol";
import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol";
import {Owners} from "../../lib/Owners.sol";
import {TSAggregatorTokenTransferProxy} from "../misc/TSAggregatorTokenTransferProxy.sol";
abstract contract TSAggregator_V5 is Owners, ReentrancyGuard {
using SafeTransferLib for address;
event FeeSet(uint256 fee, address feeRecipient);
uint256 public fee;
address public feeRecipient;
TSAggregatorTokenTransferProxy public tokenTransferProxy;
mapping(address => bool) public tokensWithTransferFee;
mapping(address => bool) public revTokens;
bool public revOnAllTokens;
constructor(address _tokenTransferProxy) {
_setOwner(msg.sender, true);
tokenTransferProxy = TSAggregatorTokenTransferProxy(
_tokenTransferProxy
);
revOnAllTokens = false;
}
receive() external payable {}
function setFee(uint256 _fee, address _feeRecipient) external isOwner {
require(_fee <= 1000, "fee can not be more than 10%");
fee = _fee;
feeRecipient = _feeRecipient;
emit FeeSet(_fee, _feeRecipient);
}
function takeFeeGas(uint256 amount) internal returns (uint256) {
uint256 amountFee = getFee(amount);
if (amountFee > 0) {
feeRecipient.safeTransferETH(amountFee);
amount -= amountFee;
}
return amount;
}
function takeFeeToken(
address token,
uint256 amount
) internal returns (uint256) {
if (revOnAllTokens || revTokens[token]) {
token.safeTransfer(feeRecipient, amount);
uint256 amountFee = getFee(amount);
if (amountFee > 0) {
token.safeTransfer(feeRecipient, amountFee);
amount -= amountFee;
}
return amount;
}
return amount;
}
function getFee(uint256 amount) internal view returns (uint256) {
if (fee != 0 && feeRecipient != address(0)) {
return (amount * fee) / 10000;
}
return 0;
}
function _parseAmountOutMin(
uint256 amount
) internal pure returns (uint256) {
return (amount / 100) * (10 ** (amount % 100));
}
function addTokenWithTransferFee(address token) external isOwner {
tokensWithTransferFee[token] = true;
}
function setRevToken(address token, bool rev) external isOwner {
revTokens[token] = rev;
}
function setRevOnAllTokens(bool rev) external isOwner {
revOnAllTokens = rev;
}
function rescueFunds(
address asset,
uint256 amount,
address destination
) public isOwner {
if (asset == address(0)) {
payable(destination).transfer(amount);
} else {
asset.safeTransfer(destination, amount);
}
}
}
文件 8 的 8:TSWrapperTCRouterV4_V1.sol
pragma solidity ^0.8.17;
import {Owners} from "../../lib/Owners.sol";
import {SafeTransferLib} from "../../lib/SafeTransferLib.sol";
import {IERC20} from "../../interfaces/IERC20.sol";
import {IThorchainRouterV4} from "../../interfaces/IThorchainRouterV4.sol";
import {TSAggregator_V5} from "../abstract/TSAggregator_V5.sol";
contract TSWrapperTCRouterV4_V1 is Owners, TSAggregator_V5 {
using SafeTransferLib for address;
IThorchainRouterV4 public tcRouter;
constructor(address _ttp, address _tcRouter) TSAggregator_V5(_ttp) {
tcRouter = IThorchainRouterV4(_tcRouter);
_setOwner(msg.sender, true);
}
function depositWithExpiry(
address payable vault,
address asset,
uint amount,
string memory memo,
uint expiration
) public payable nonReentrant {
uint safeAmount;
if (asset == address(0)) {
safeAmount = takeFeeGas(msg.value);
} else {
safeAmount = takeFeeToken(asset, amount);
}
tcRouter.depositWithExpiry{value: asset == address(0) ? safeAmount : 0}(
vault,
asset,
safeAmount,
memo,
expiration
);
}
function swapOut(
address token,
address to,
uint256 amountOutMin
) public payable nonReentrant {
uint256 safeAmount = takeFeeGas(msg.value);
to.safeTransferETH(safeAmount);
}
}
{
"compilationTarget": {
"src/contracts/wrappers/TSWrapperTCRouterV4_V1.sol": "TSWrapperTCRouterV4_V1"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_ttp","type":"address"},{"internalType":"address","name":"_tcRouter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"}],"name":"FeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"OwnerSet","type":"event"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"addTokenWithTransferFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"vault","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"memo","type":"string"},{"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"depositWithExpiry","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"owners","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"destination","type":"address"}],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revOnAllTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"revTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"active","type":"bool"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"rev","type":"bool"}],"name":"setRevOnAllTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"rev","type":"bool"}],"name":"setRevToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapOut","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"tcRouter","outputs":[{"internalType":"contract IThorchainRouterV4","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenTransferProxy","outputs":[{"internalType":"contract TSAggregatorTokenTransferProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokensWithTransferFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]