编译器
0.8.17+commit.8df45f5f
文件 1 的 13:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 13:BaseAdminOperation.sol
pragma solidity ^0.8.4;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import {TransferHelper} from "./util/TransferHelper.sol";
abstract contract BaseAdminOperation is Pausable, Ownable {
event AdminUpdated(address indexed addr, bool flag);
mapping(address => bool) public isAdmin;
modifier onlyAdmin() {
require(_msgSender() == owner() || isAdmin[_msgSender()], "BaseAdminOperation: !admin");
_;
}
function pause() public onlyAdmin {
_pause();
}
function unpause() public onlyAdmin {
_unpause();
}
function setAdmin(address addr, bool flag) public onlyAdmin {
isAdmin[addr] = flag;
emit AdminUpdated(addr, flag);
}
function inCaseTokenGotStuck(address stuckToken) external virtual onlyOwner {
if (stuckToken == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
TransferHelper.safeTransferETH(_msgSender(), address(this).balance);
} else {
uint256 amount = IERC20(stuckToken).balanceOf(address(this));
TransferHelper.safeTransfer(stuckToken, _msgSender(), amount);
}
}
}
文件 3 的 13:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 4 的 13: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);
}
文件 5 的 13:IWooStakingLocal.sol
pragma solidity 0.8.17;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWooStakingLocal {
event StakeOnLocal(address indexed user, uint256 amount);
event StakeForUsersOnLocal(address[] users, uint256[] amounts, uint256 total);
event UnstakeOnLocal(address indexed user, uint256 amount);
event SetAutoCompoundOnLocal(address indexed user, bool flag);
event CompoundMPOnLocal(address indexed user);
event CompoundAllOnLocal(address indexed user);
event SetStakingManagerOnLocal(address indexed manager);
function want() external view returns (IERC20);
function balances(address user) external view returns (uint256 balance);
function stake(uint256 _amount) external;
function stake(address _user, uint256 _amount) external;
function stakeForUsers(address[] memory _users, uint256[] memory _amounts, uint256 _total) external;
function unstake(uint256 _amount) external;
function unstakeAll() external;
function setAutoCompound(bool _flag) external;
function compoundMP() external;
function compoundAll() external;
}
文件 6 的 13:IWooStakingManager.sol
pragma solidity 0.8.17;
interface IWooStakingManager {
event StakeWooOnStakingManager(address indexed user, uint256 amount);
event UnstakeWooOnStakingManager(address indexed user, uint256 amount);
event AddMPOnStakingManager(address indexed user, uint256 amount);
event CompoundMPOnStakingManager(address indexed user);
event CompoundRewardsOnStakingManager(address indexed user, uint256 wooAmount);
event CompoundAllOnStakingManager(address indexed user);
event CompoundAllForUsersOnStakingManager(address[] users, uint256[] wooRewards);
event SetAutoCompoundOnStakingManager(address indexed user, bool flag);
event SetMPRewarderOnStakingManager(address indexed rewarder);
event SetWooPPOnStakingManager(address indexed wooPP);
event SetStakingLocalOnStakingManager(address indexed stakingProxy);
event SetCompounderOnStakingManager(address indexed compounder);
event AddRewarderOnStakingManager(address indexed rewarder);
event RemoveRewarderOnStakingManager(address indexed rewarder);
event ClaimRewardsOnStakingManager(address indexed user);
function stakeWoo(address _user, uint256 _amount) external;
function unstakeWoo(address _user, uint256 _amount) external;
function mpBalance(address _user) external view returns (uint256);
function wooBalance(address _user) external view returns (uint256);
function wooTotalBalance() external view returns (uint256);
function totalBalance(address _user) external view returns (uint256);
function totalBalance() external view returns (uint256);
function compoundMP(address _user) external;
function addMP(address _user, uint256 _amount) external;
function compoundRewards(address _user) external;
function compoundAll(address _user) external;
function compoundAllForUsers(address[] memory _users) external;
function setAutoCompound(address _user, bool _flag) external;
function pendingRewards(
address _user
) external view returns (uint256 mpRewardAmount, address[] memory rewardTokens, uint256[] memory amounts);
}
文件 7 的 13:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 8 的 13:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 9 的 13:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
}
文件 10 的 13:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 11 的 13:TransferHelper.sol
pragma solidity ^0.8.0;
library TransferHelper {
function safeApprove(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeApprove: approve failed"
);
}
function safeTransfer(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeTransfer: transfer failed"
);
}
function safeTransferFrom(address token, address from, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::transferFrom: transferFrom failed"
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "TransferHelper::safeTransferETH: ETH transfer failed");
}
}
文件 12 的 13:WooStakingLocal.sol
pragma solidity ^0.8.4;
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IWooStakingLocal} from "./interfaces/IWooStakingLocal.sol";
import {IWooStakingManager} from "./interfaces/IWooStakingManager.sol";
import {BaseAdminOperation} from "./BaseAdminOperation.sol";
import {TransferHelper} from "./util/TransferHelper.sol";
contract WooStakingLocal is IWooStakingLocal, BaseAdminOperation, ReentrancyGuard {
using SafeERC20 for IERC20;
bool public isEmergency;
IWooStakingManager public stakingManager;
IERC20 public immutable want;
mapping(address => uint256) public balances;
constructor(address _want, address _stakingManager) {
require(_want != address(0), "WooStakingLocal: !_want");
require(_stakingManager != address(0), "WooStakingLocal: !_stakingManager");
want = IERC20(_want);
stakingManager = IWooStakingManager(_stakingManager);
isEmergency = false;
}
function stake(uint256 _amount) external whenNotPaused nonReentrant {
_stake(msg.sender, _amount);
}
function stake(address _user, uint256 _amount) external whenNotPaused onlyAdmin {
_stake(_user, _amount);
}
function stakeForUsers(
address[] memory _users,
uint256[] memory _amounts,
uint256 _total
) external whenNotPaused onlyAdmin {
uint256 len = _users.length;
want.safeTransferFrom(msg.sender, address(this), _total);
for (uint256 i = 0; i < len; ++i) {
address _user = _users[i];
balances[_user] += _amounts[i];
stakingManager.stakeWoo(_user, _amounts[i]);
}
emit StakeForUsersOnLocal(_users, _amounts, _total);
}
function _stake(address _user, uint256 _amount) internal {
want.safeTransferFrom(msg.sender, address(this), _amount);
balances[_user] += _amount;
emit StakeOnLocal(_user, _amount);
stakingManager.stakeWoo(_user, _amount);
}
function unstake(uint256 _amount) external nonReentrant {
_unstake(msg.sender, _amount);
}
function unstakeAll() external nonReentrant {
_unstake(msg.sender, balances[msg.sender]);
}
function emergencyUnstake() external {
require(isEmergency, "WooStakingLocal: !allow");
uint256 _amount = balances[msg.sender];
balances[msg.sender] -= _amount;
want.safeTransfer(msg.sender, _amount);
emit UnstakeOnLocal(msg.sender, _amount);
}
function _unstake(address _user, uint256 _amount) internal {
require(balances[_user] >= _amount, "WooStakingLocal: !BALANCE");
balances[_user] -= _amount;
want.safeTransfer(_user, _amount);
emit UnstakeOnLocal(_user, _amount);
stakingManager.unstakeWoo(_user, _amount);
}
function setAutoCompound(bool _flag) external whenNotPaused nonReentrant {
address _user = msg.sender;
stakingManager.setAutoCompound(_user, _flag);
emit SetAutoCompoundOnLocal(_user, _flag);
}
function compoundMP() external whenNotPaused nonReentrant {
address _user = msg.sender;
stakingManager.compoundMP(_user);
emit CompoundMPOnLocal(_user);
}
function compoundAll() external whenNotPaused nonReentrant {
address _user = msg.sender;
stakingManager.compoundAll(_user);
emit CompoundAllOnLocal(_user);
}
function setStakingManager(address _stakingManager) external onlyAdmin {
stakingManager = IWooStakingManager(_stakingManager);
emit SetStakingManagerOnLocal(_stakingManager);
}
function setIsEmergency(bool _isEmergency) external onlyOwner {
isEmergency = _isEmergency;
}
function inCaseTokenGotStuck(address stuckToken) external override onlyOwner {
require(stuckToken != address(want), "WooStakingLocal: !want");
if (stuckToken == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
TransferHelper.safeTransferETH(_msgSender(), address(this).balance);
} else {
uint256 amount = IERC20(stuckToken).balanceOf(address(this));
TransferHelper.safeTransfer(stuckToken, _msgSender(), amount);
}
}
}
文件 13 的 13:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
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);
}
{
"compilationTarget": {
"contracts/WooStakingLocal.sol": "WooStakingLocal"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 20000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_want","type":"address"},{"internalType":"address","name":"_stakingManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bool","name":"flag","type":"bool"}],"name":"AdminUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"CompoundAllOnLocal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"CompoundMPOnLocal","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":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"flag","type":"bool"}],"name":"SetAutoCompoundOnLocal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"manager","type":"address"}],"name":"SetStakingManagerOnLocal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"users","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"total","type":"uint256"}],"name":"StakeForUsersOnLocal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeOnLocal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UnstakeOnLocal","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compoundAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"compoundMP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stuckToken","type":"address"}],"name":"inCaseTokenGotStuck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isEmergency","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"flag","type":"bool"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_flag","type":"bool"}],"name":"setAutoCompound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isEmergency","type":"bool"}],"name":"setIsEmergency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stakingManager","type":"address"}],"name":"setStakingManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_users","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"uint256","name":"_total","type":"uint256"}],"name":"stakeForUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingManager","outputs":[{"internalType":"contract IWooStakingManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"want","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"}]