编译器
0.8.25+commit.b61c2a91
文件 1 的 11:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 2 的 11:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 3 的 11:IERC20.sol
pragma solidity ^0.8.20;
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 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 4 的 11:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 5 的 11:ITokenBridge.sol
pragma solidity >=0.6.0;
pragma experimental ABIEncoderV2;
import "@layerzerolabs/solidity-examples/contracts/libraries/LzLib.sol";
interface ITokenBridge {
enum PacketType {
SEND_TO_APTOS,
RECEIVE_FROM_APTOS
}
function sendToAptos(
address _token,
bytes32 _toAddress,
uint _amountLD,
LzLib.CallParams calldata _callParams,
bytes calldata _adapterParams
) external payable;
function sendETHToAptos(
bytes32 _toAddress,
uint _amountLD,
LzLib.CallParams calldata _callParams,
bytes calldata _adapterParams
) external payable;
function quoteForSend(LzLib.CallParams calldata _callParams, bytes calldata _adapterParams)
external
view
returns (uint nativeFee, uint zroFee);
event Send(address indexed token, address indexed from, bytes32 indexed to, uint amountLD);
event Receive(address indexed token, address indexed to, uint amountLD);
event RegisterToken(address token);
event SetBridgeBP(uint bridgeFeeBP);
event SetWETH(address weth);
event SetGlobalPause(bool paused);
event SetTokenPause(address token, bool paused);
event SetLocalChainId(uint16 localChainId);
event SetAptosChainId(uint16 aptosChainId);
event SetUseCustomAdapterParams(bool useCustomAdapterParams);
event WithdrawFee(address indexed token, address to, uint amountLD);
event WithdrawTVL(address indexed token, address to, uint amountLD);
event EnableEmergencyWithdraw(bool enabled, uint unlockTime);
}
文件 6 的 11:LzLib.sol
pragma solidity >=0.6.0;
pragma experimental ABIEncoderV2;
library LzLib {
struct CallParams {
address payable refundAddress;
address zroPaymentAddress;
}
struct AirdropParams {
uint airdropAmount;
bytes32 airdropAddress;
}
function buildAdapterParams(LzLib.AirdropParams memory _airdropParams, uint _uaGasLimit) internal pure returns (bytes memory adapterParams) {
if (_airdropParams.airdropAmount == 0 && _airdropParams.airdropAddress == bytes32(0x0)) {
adapterParams = buildDefaultAdapterParams(_uaGasLimit);
} else {
adapterParams = buildAirdropAdapterParams(_uaGasLimit, _airdropParams);
}
}
function buildDefaultAdapterParams(uint _uaGas) internal pure returns (bytes memory) {
return abi.encodePacked(uint16(1), _uaGas);
}
function buildAirdropAdapterParams(uint _uaGas, AirdropParams memory _params) internal pure returns (bytes memory) {
require(_params.airdropAmount > 0, "Airdrop amount must be greater than 0");
require(_params.airdropAddress != bytes32(0x0), "Airdrop address must be set");
return abi.encodePacked(uint16(2), _uaGas, _params.airdropAmount, _params.airdropAddress);
}
function getGasLimit(bytes memory _adapterParams) internal pure returns (uint gasLimit) {
require(_adapterParams.length == 34 || _adapterParams.length > 66, "Invalid adapterParams");
assembly {
gasLimit := mload(add(_adapterParams, 34))
}
}
function decodeAdapterParams(bytes memory _adapterParams)
internal
pure
returns (
uint16 txType,
uint uaGas,
uint airdropAmount,
address payable airdropAddress
)
{
require(_adapterParams.length == 34 || _adapterParams.length > 66, "Invalid adapterParams");
assembly {
txType := mload(add(_adapterParams, 2))
uaGas := mload(add(_adapterParams, 34))
}
require(txType == 1 || txType == 2, "Unsupported txType");
require(uaGas > 0, "Gas too low");
if (txType == 2) {
assembly {
airdropAmount := mload(add(_adapterParams, 66))
airdropAddress := mload(add(_adapterParams, 86))
}
}
}
function bytes32ToAddress(bytes32 _bytes32Address) internal pure returns (address _address) {
return address(uint160(uint(_bytes32Address)));
}
function addressToBytes32(address _address) internal pure returns (bytes32 _bytes32Address) {
return bytes32(uint(uint160(_address)));
}
}
文件 7 的 11:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 8 的 11:Ownable2Step.sol
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
文件 9 的 11:Pausable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Pausable is Context {
bool private _paused;
event Paused(address account);
event Unpaused(address account);
error EnforcedPause();
error ExpectedPause();
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 10 的 11:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
文件 11 的 11:SwapBridge.sol
pragma solidity 0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ITokenBridge} from "LayerZero-Aptos-Contract/apps/bridge-evm/contracts/interfaces/ITokenBridge.sol";
import {LzLib} from "@layerzerolabs/solidity-examples/contracts/libraries/LzLib.sol";
contract SwapBridge is Ownable2Step, Pausable {
uint256 private constant APT_AIRDROP_AMOUNT = 9904;
bool private isInit;
ITokenBridge private tokenBridge;
address private swapTarget;
event SwapAndSendToAptos(
address fromToken,
address toToken,
uint256 fromAmount,
uint256 minToAmount,
uint256 toAmount,
bytes32 aptosAddress
);
event SendToAptos(uint256 amount, bytes32 aptosAddress);
error AlreadyInitialized();
error InsufficientOutputAmount();
error NothingToRescue();
constructor(address _owner) Ownable(_owner) {}
function initialize(address _tokenBridgeAddress, address _swapTarget) external onlyOwner {
if (isInit) revert AlreadyInitialized();
isInit = true;
tokenBridge = ITokenBridge(_tokenBridgeAddress);
swapTarget = _swapTarget;
}
function approveMax(IERC20 _token, address _spender) external whenNotPaused {
SafeERC20.forceApprove(_token, _spender, type(uint256).max);
}
function _lzParams(bytes32 _aptosAddress)
private
view
returns (LzLib.CallParams memory callParams, bytes memory adapterParams)
{
callParams = LzLib.CallParams({refundAddress: payable(msg.sender), zroPaymentAddress: address(0x0)});
adapterParams = LzLib.buildAirdropAdapterParams(
10000,
LzLib.AirdropParams({airdropAmount: APT_AIRDROP_AMOUNT, airdropAddress: _aptosAddress})
);
}
function quoteForSend() external view returns (uint256 nativeFee, uint256 zroFee) {
(LzLib.CallParams memory callParams, bytes memory adapterParams) = _lzParams(hex"01");
(nativeFee, zroFee) = tokenBridge.quoteForSend(callParams, adapterParams);
}
function swapAndSendToAptos(
IERC20 _fromToken,
uint256 _fromAmount,
IERC20 _toToken,
uint256 _minToAmount,
bytes32 _aptosAddress,
bytes calldata _swapBytes
) external payable whenNotPaused {
uint256 fromTokenOrgBalance = _fromToken.balanceOf(address(this));
uint256 toTokenOrgBalance = _toToken.balanceOf(address(this));
SafeERC20.safeTransferFrom(_fromToken, msg.sender, address(this), _fromAmount);
Address.functionCall(swapTarget, _swapBytes);
uint256 toAmount = _toToken.balanceOf(address(this)) - toTokenOrgBalance;
if (toAmount < _minToAmount) revert InsufficientOutputAmount();
uint256 residue = _fromToken.balanceOf(address(this)) - fromTokenOrgBalance;
if (residue > 0) {
SafeERC20.safeTransfer(_fromToken, msg.sender, residue);
}
_sendToAptos(address(_toToken), toAmount, _aptosAddress);
if (_toToken.balanceOf(address(this)) > toTokenOrgBalance) {
SafeERC20.safeTransfer(_toToken, msg.sender, _toToken.balanceOf(address(this)) - toTokenOrgBalance);
}
emit SwapAndSendToAptos(address(_fromToken), address(_toToken), _fromAmount, _minToAmount, toAmount, _aptosAddress);
}
function sendToAptos(IERC20 _token, uint256 _amount, bytes32 _aptosAddress) external payable whenNotPaused {
uint256 tokenOrgBalance = _token.balanceOf(address(this));
SafeERC20.safeTransferFrom(_token, msg.sender, address(this), _amount);
_sendToAptos(address(_token), _amount, _aptosAddress);
if (_token.balanceOf(address(this)) > tokenOrgBalance) {
SafeERC20.safeTransfer(_token, msg.sender, _token.balanceOf(address(this)) - tokenOrgBalance);
}
emit SendToAptos(_amount, _aptosAddress);
}
function _sendToAptos(address _tokenAddress, uint256 _amount, bytes32 _aptosAddress) private {
(LzLib.CallParams memory callParams, bytes memory adapterParams) = _lzParams(_aptosAddress);
tokenBridge.sendToAptos{value: msg.value}(_tokenAddress, _aptosAddress, _amount, callParams, adapterParams);
}
function rescueToken(IERC20 _token, address _recipient) external onlyOwner {
uint256 tokenBalance = _token.balanceOf(address(this));
if (tokenBalance == 0) revert NothingToRescue();
SafeERC20.safeTransfer(_token, _recipient, tokenBalance);
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
}
{
"compilationTarget": {
"src/SwapBridge.sol": "SwapBridge"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@layerzerolabs/solidity-examples/contracts/libraries/=lib/solidity-examples/contracts/lzApp/libs/",
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":LayerZero-Aptos-Contract/=lib/LayerZero-Aptos-Contract/",
":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":solidity-examples/=lib/solidity-examples/contracts/"
]
}
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"NothingToRescue","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"aptosAddress","type":"bytes32"}],"name":"SendToAptos","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"fromToken","type":"address"},{"indexed":false,"internalType":"address","name":"toToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minToAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"aptosAddress","type":"bytes32"}],"name":"SwapAndSendToAptos","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"approveMax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenBridgeAddress","type":"address"},{"internalType":"address","name":"_swapTarget","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteForSend","outputs":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"zroFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"rescueToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_aptosAddress","type":"bytes32"}],"name":"sendToAptos","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_fromToken","type":"address"},{"internalType":"uint256","name":"_fromAmount","type":"uint256"},{"internalType":"contract IERC20","name":"_toToken","type":"address"},{"internalType":"uint256","name":"_minToAmount","type":"uint256"},{"internalType":"bytes32","name":"_aptosAddress","type":"bytes32"},{"internalType":"bytes","name":"_swapBytes","type":"bytes"}],"name":"swapAndSendToAptos","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]