编译器
0.8.19+commit.7dd6d404
文件 1 的 30: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 的 30:BytesCheck.sol
pragma solidity ^0.8.17;
library BytesCheck {
function checkFirstDigit0x0(uint8 x) public pure returns (bool) {
uint8 y = uint8(x & 0xF0);
uint8 z = y >> 4;
return (z == 0x0);
}
function checkFirstDigit0x1(uint8 x) public pure returns (bool) {
uint8 y = uint8(x & 0xF0);
uint8 z = y >> 4;
return (z == 0x1);
}
function checkFirstDigit0x2(uint8 x) public pure returns (bool) {
uint8 y = uint8(x & 0xF0);
uint8 z = y >> 4;
return (z == 0x2);
}
function checkFirstDigit0x3(uint8 x) public pure returns (bool) {
uint8 y = uint8(x & 0xF0);
uint8 z = y >> 4;
return (z == 0x3);
}
}
文件 3 的 30:BytesLib.sol
pragma solidity ^0.8.0;
library BytesLib {
function toAddress(bytes calldata _bytes) internal pure returns (address tempAddress) {
assembly {
tempAddress := shr(96, calldataload(_bytes.offset))
}
}
function toPool(bytes calldata _bytes) internal pure returns (address token0, uint24 fee, address token1) {
assembly {
token0 := shr(96, calldataload(_bytes.offset))
fee := shr(232, calldataload(add(_bytes.offset, 20)))
token1 := shr(96, calldataload(add(_bytes.offset, 23)))
}
}
function toLengthOffset(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (uint256 length, uint256 offset)
{
assembly {
let lengthPtr := add(_bytes.offset, calldataload(add(_bytes.offset, mul(0x20, _arg))))
length := calldataload(lengthPtr)
offset := add(lengthPtr, 0x20)
}
}
function toBytes(bytes calldata _bytes, uint256 _arg) internal pure returns (bytes calldata res) {
(uint256 length, uint256 offset) = toLengthOffset(_bytes, _arg);
assembly {
res.length := length
res.offset := offset
}
}
function toAddressArray(bytes calldata _bytes, uint256 _arg) internal pure returns (address[] calldata res) {
(uint256 length, uint256 offset) = toLengthOffset(_bytes, _arg);
assembly {
res.length := length
res.offset := offset
}
}
function toBytesArray(bytes calldata _bytes, uint256 _arg) internal pure returns (bytes[] calldata res) {
(uint256 length, uint256 offset) = toLengthOffset(_bytes, _arg);
assembly {
res.length := length
res.offset := offset
}
}
}
文件 4 的 30:Clones.sol
pragma solidity ^0.8.0;
library Clones {
function clone(address implementation) internal returns (address instance) {
assembly {
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
assembly {
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
function predictDeterministicAddress(address implementation, bytes32 salt)
internal
view
returns (address predicted)
{
return predictDeterministicAddress(implementation, salt, address(this));
}
}
文件 5 的 30:Commands.sol
pragma solidity ^0.8.17;
library Commands {
bytes1 internal constant FLAG_ALLOW_REVERT = 0x80;
bytes1 internal constant COMMAND_TYPE_MASK = 0x3f;
uint256 constant GMX = 0x00;
uint256 constant PERP = 0x01;
uint256 constant CAP = 0x02;
uint256 constant KWENTA = 0x03;
uint256 constant UNI = 0x10;
uint256 constant SUSHI = 0x11;
uint256 constant ONE_INCH = 0x12;
uint256 constant TRADER_JOE = 0x13;
uint256 constant PANCAKE = 0x14;
uint256 constant CROSS_CHAIN = 0x30;
uint256 constant MODIFY_ORDER = 0x31;
uint256 constant CLAIM_REWARDS = 0x32;
}
文件 6 的 30:ECDSA.sol
pragma solidity ^0.8.0;
import "../Strings.sol";
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
文件 7 的 30:Errors.sol
pragma solidity ^0.8.17;
library Errors {
error ZeroAmount();
error ZeroAddress();
error ZeroTotalRaised();
error ZeroClaimableAmount();
error NotOwner();
error NotAdmin();
error CallerNotVault();
error CallerNotTrade();
error CallerNotVaultOwner();
error CallerNotGenerate();
error NoAccess();
error NotPlugin();
error BelowMinFundraisingPeriod();
error AboveMaxFundraisingPeriod();
error BelowMinLeverage();
error AboveMaxLeverage();
error BelowMinEndTime();
error TradeTokenNotApplicable();
error StvDoesNotExist();
error AlreadyOpened();
error MoreThanTotalRaised();
error MoreThanTotalReceived();
error StvNotOpen();
error StvNotClose();
error ClaimNotApplicable();
error StvStatusMismatch();
error BalanceLessThanAmount();
error FundraisingPeriodEnded();
error TotalRaisedMoreThanCapacity();
error StillFundraising();
error CommandMisMatch();
error TradeCommandMisMatch();
error NotInitialised();
error Initialised();
error LengthMismatch();
error TransferFailed();
error DelegateCallFailed();
error CallFailed(bytes);
error AccountAlreadyExists();
error SwapFailed();
error ExchangeDataMismatch();
error AccountNotExists();
error InputMismatch();
error AboveMaxDistributeIndex();
error BelowMinStvDepositAmount();
error GmxFeesMisMatch();
error UpdateOrderRequestMisMatch();
error CancelOrderRequestMisMatch();
error NotASubscriber();
error AlreadySubscribed();
error MoreThanLimit();
}
文件 8 的 30:Generate.sol
pragma solidity ^0.8.17;
import {Errors} from "src/libraries/Errors.sol";
import {IVault} from "src/interfaces/IVault.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {IOperator} from "src/storage/interfaces/IOperator.sol";
library Generate {
function generate(uint96 capacityOfStv, address manager, address operator, uint40 maxFundraisingPeriod)
external
returns (IVault.StvInfo memory stv)
{
address stvAccountImplementation = IOperator(operator).getAddress("STVACCOUNT");
address defaultStableCoin = IOperator(operator).getAddress("DEFAULTSTABLECOIN");
if (capacityOfStv < 1e6) revert Errors.InputMismatch();
stv.manager = manager;
stv.endTime = uint40(block.timestamp) + maxFundraisingPeriod;
stv.capacityOfStv = capacityOfStv;
bytes32 salt = keccak256(
abi.encodePacked(
manager, defaultStableCoin, capacityOfStv, maxFundraisingPeriod, block.timestamp, block.chainid
)
);
address contractAddress = Clones.cloneDeterministic(stvAccountImplementation, salt);
stv.stvId = contractAddress;
}
}
文件 9 的 30:IAccount.sol
pragma solidity ^0.8.17;
interface IAccount {
function execute(address adapter, bytes calldata data, uint256 ethToSend)
external
payable
returns (bytes memory returnData);
}
文件 10 的 30:IERC1155Receiver.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 11 的 30:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 12 的 30: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);
function decimals() external view returns (uint8);
}
文件 13 的 30:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 14 的 30:IOperator.sol
pragma solidity ^0.8.17;
interface IOperator {
function getMaxDistributeIndex() external view returns (uint256);
function getAddress(string calldata adapter) external view returns (address);
function getAddresses(string[] calldata adapters) external view returns (address[] memory);
function getTraderAccount(address trader) external view returns (address);
function getPlugin(address plugin) external view returns (bool);
function getPlugins(address[] calldata plugins) external view returns (bool[] memory);
function setAddress(string calldata adapter, address addr) external;
function setAddresses(string[] calldata adapters, address[] calldata addresses) external;
function setPlugin(address plugin, bool isPlugin) external;
function setPlugins(address[] calldata plugins, bool[] calldata isPlugin) external;
function setTraderAccount(address trader, address account) external;
function getAllSubscribers(address manager) external view returns (address[] memory);
function getIsSubscriber(address manager, address subscriber) external view returns (bool);
function getSubscriptionAmount(address manager, address subscriber) external view returns (uint96);
function getTotalSubscribedAmountPerManager(address manager) external view returns (uint96);
function setSubscribe(address manager, address subscriber, uint96 maxLimit) external;
function setUnsubscribe(address manager, address subscriber) external;
}
文件 15 的 30:IPermit2.sol
pragma solidity ^0.8.15;
interface IPermit2 {
error AllowanceExpired(uint256 deadline);
error InsufficientAllowance(uint256 amount);
error ExcessiveInvalidation();
event NonceInvalidation(
address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce
);
event Approval(
address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration
);
event Permit(
address indexed owner,
address indexed token,
address indexed spender,
uint160 amount,
uint48 expiration,
uint48 nonce
);
event Lockdown(address indexed owner, address token, address spender);
struct PermitDetails {
address token;
uint160 amount;
uint48 expiration;
uint48 nonce;
}
struct PermitSingle {
PermitDetails details;
address spender;
uint256 sigDeadline;
}
struct PermitBatch {
PermitDetails[] details;
address spender;
uint256 sigDeadline;
}
struct PackedAllowance {
uint160 amount;
uint48 expiration;
uint48 nonce;
}
struct TokenSpenderPair {
address token;
address spender;
}
struct AllowanceTransferDetails {
address from;
address to;
uint160 amount;
address token;
}
function allowance(address, address, address) external view returns (uint160, uint48, uint48);
function approve(address token, address spender, uint160 amount, uint48 expiration) external;
function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;
function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;
function transferFrom(address from, address to, uint160 amount, address token) external;
function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;
function lockdown(TokenSpenderPair[] calldata approvals) external;
function invalidateNonces(address token, address spender, uint48 newNonce) external;
}
文件 16 的 30:IPerpTrade.sol
pragma solidity ^0.8.17;
interface IPerpTrade {
function execute(uint256 command, bytes calldata data, bool isOpen) external payable;
}
文件 17 的 30:IQ.sol
pragma solidity ^0.8.17;
interface IQ {
function owner() external view returns (address);
function admin() external view returns (address);
function perpTrade() external view returns (address);
function whitelistedPlugins(address) external view returns (bool);
function defaultStableCoin() external view returns (address);
function traderAccount(address) external view returns (address);
function createAccount(address) external returns (address);
}
文件 18 的 30:IStvAccount.sol
pragma solidity ^0.8.17;
import {IVault} from "src/interfaces/IVault.sol";
interface IStvAccount {
function stvInfo() external view returns (IVault.StvInfo memory);
function stvBalance() external view returns (IVault.StvBalance memory);
function investorInfo(address investorAccount) external view returns (IVault.InvestorInfo memory);
function investors() external view returns (address[] memory);
function getInvestors() external view returns (address[] memory);
function totalTradeTokenReceivedAfterOpen(address token) external view returns (uint96);
function totalTradeTokenUsedForClose(address token) external view returns (uint96);
function execute(address adapter, bytes calldata data, uint256 ethToSend) external payable;
function createStv(IVault.StvInfo memory stv) external;
function deposit(address investorAccount, uint96 amount, bool isFirstDeposit) external;
function liquidate() external;
function execute(uint96 amount, address tradeToken, uint96 totalReceived, bool isOpen) external;
function distribute(uint96 totalRemainingAfterDistribute, uint96 mFee, uint96 pFee) external;
function distributeOut(bool isCancel, uint256 indexFrom, uint256 indexTo) external;
function updateStatus(IVault.StvStatus status) external;
function cancel() external;
}
文件 19 的 30:IUniswapV2Router02.sol
pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountToken, uint256 amountETH);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)
external
payable
returns (uint256[] memory amounts);
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapETHForExactTokens(uint256 amountOut, address[] calldata path, address to, uint256 deadline)
external
payable
returns (uint256[] memory amounts);
function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB);
function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut)
external
pure
returns (uint256 amountOut);
function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut)
external
pure
returns (uint256 amountIn);
function getAmountsOut(uint256 amountIn, address[] calldata path)
external
view
returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] calldata path)
external
view
returns (uint256[] memory amounts);
}
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
}
文件 20 的 30:IUniversalRouter.sol
pragma solidity ^0.8.13;
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
interface IRewardsCollector {
function collectRewards(bytes calldata looksRareClaim) external;
}
interface IUniversalRouter is IRewardsCollector, IERC721Receiver, IERC1155Receiver {
error ExecutionFailed(uint256 commandIndex, bytes message);
error ETHNotAccepted();
error TransactionDeadlinePassed();
error LengthMismatch();
function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external payable;
function execute(bytes calldata commands, bytes[] calldata inputs) external payable;
}
文件 21 的 30:IVault.sol
pragma solidity ^0.8.17;
interface IVault {
enum StvStatus {
NOT_OPENED,
OPEN,
CANCELLED_WITH_ZERO_RAISE,
CANCELLED_WITH_NO_FILL,
CANCELLED_BY_MANAGER,
DISTRIBUTED,
LIQUIDATED
}
struct StvInfo {
address stvId;
uint40 endTime;
StvStatus status;
address manager;
uint96 capacityOfStv;
}
struct StvBalance {
uint96 totalRaised;
uint96 totalRemainingAfterDistribute;
}
struct InvestorInfo {
uint96 depositAmount;
uint96 claimedAmount;
bool claimed;
}
function getQ() external view returns (address);
function maxFundraisingPeriod() external view returns (uint40);
function distributeOut(address stvId, bool isCancel, uint256 indexFrom, uint256 indexTo) external;
}
文件 22 的 30:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1);
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
文件 23 的 30: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;
}
}
文件 24 的 30: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");
}
}
}
文件 25 的 30:SpotTrade.sol
pragma solidity ^0.8.17;
import {Commands} from "src/libraries/Commands.sol";
import {Errors} from "src/libraries/Errors.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IUniversalRouter} from "src/protocols/uni/interfaces/IUniversalRouter.sol";
import {IPermit2} from "src/protocols/uni/interfaces/IPermit2.sol";
import {IUniswapV2Router02} from "src/protocols/sushi/interfaces/IUniswapV2Router02.sol";
import {Commands as UniCommands} from "test/libraries/Commands.sol";
import {BytesLib} from "test/libraries/BytesLib.sol";
import {IOperator} from "src/storage/interfaces/IOperator.sol";
library SpotTrade {
using BytesLib for bytes;
using SafeERC20 for IERC20;
function uni(
address tokenIn,
address tokenOut,
uint96 amountIn,
bytes calldata commands,
bytes[] calldata inputs,
uint256 deadline,
bytes memory addresses
) external returns (uint96) {
(address receiver, address operator) = abi.decode(addresses, (address, address));
address universalRouter = IOperator(operator).getAddress("UNIVERSALROUTER");
address permit2 = IOperator(operator).getAddress("PERMIT2");
_check(tokenIn, tokenOut, amountIn, commands, inputs, receiver);
IERC20(tokenIn).approve(address(permit2), amountIn);
IPermit2(permit2).approve(tokenIn, address(universalRouter), uint160(amountIn), type(uint48).max);
uint96 balanceBeforeSwap = uint96(IERC20(tokenOut).balanceOf(receiver));
if (deadline > 0) IUniversalRouter(universalRouter).execute(commands, inputs, deadline);
else IUniversalRouter(universalRouter).execute(commands, inputs);
uint96 balanceAfterSwap = uint96(IERC20(tokenOut).balanceOf(receiver));
return balanceAfterSwap - balanceBeforeSwap;
}
function _check(
address tokenIn,
address tokenOut,
uint96 amountIn,
bytes calldata commands,
bytes[] calldata inputs,
address receiver
) internal pure {
uint256 amount;
for (uint256 i = 0; i < commands.length;) {
bytes calldata input = inputs[i];
if (address(bytes20(input[12:32])) != receiver) revert Errors.InputMismatch();
amount += uint256(bytes32(input[32:64]));
if (commands[i] == bytes1(uint8(UniCommands.V2_SWAP_EXACT_IN))) {
address[] calldata path = input.toAddressArray(3);
if (path[0] != tokenIn) revert Errors.InputMismatch();
if (path[path.length - 1] != tokenOut) revert Errors.InputMismatch();
} else if (commands[i] == bytes1(uint8(UniCommands.V3_SWAP_EXACT_IN))) {
bytes calldata path = input.toBytes(3);
if (address(bytes20(path[:20])) != tokenIn) revert Errors.InputMismatch();
if (address(bytes20(path[path.length - 20:])) != tokenOut) revert Errors.InputMismatch();
} else {
revert Errors.CommandMisMatch();
}
unchecked {
++i;
}
}
if (amount != uint256(amountIn)) revert Errors.InputMismatch();
}
function sushi(
address tokenIn,
address tokenOut,
uint96 amountIn,
uint256 amountOutMin,
address receiver,
address operator
) external returns (uint96) {
address router = IOperator(operator).getAddress("SUSHIROUTER");
IERC20(tokenIn).approve(router, amountIn);
address[] memory tokenPath;
address wrappedToken = IOperator(operator).getAddress("WRAPPEDTOKEN");
if (tokenIn == wrappedToken || tokenOut == wrappedToken) {
tokenPath = new address[](2);
tokenPath[0] = tokenIn;
tokenPath[1] = tokenOut;
} else {
tokenPath = new address[](3);
tokenPath[0] = tokenIn;
tokenPath[1] = wrappedToken;
tokenPath[2] = tokenOut;
}
uint256[] memory amounts = IUniswapV2Router02(router).swapExactTokensForTokens(
amountIn, amountOutMin, tokenPath, receiver, block.timestamp
);
uint256 length = amounts.length;
return uint96(amounts[length - 1]);
}
function oneInch(address tokenIn, address tokenOut, address receiver, bytes memory exchangeData, address operator)
external
returns (uint96)
{
if (exchangeData.length == 0) revert Errors.ExchangeDataMismatch();
address router = IOperator(operator).getAddress("ONEINCHROUTER");
address vault = IOperator(operator).getAddress("VAULT");
uint256 tokenInBalanceBefore = IERC20(tokenIn).balanceOf(vault);
uint256 tokenOutBalanceBefore = IERC20(tokenOut).balanceOf(receiver);
IERC20(tokenIn).safeApprove(router, type(uint256).max);
(bool success, bytes memory returnData) = router.call(exchangeData);
uint256 returnAmount;
if (success) {
IERC20(tokenIn).safeApprove(router, 0);
returnAmount = abi.decode(returnData, (uint256));
uint256 tokenInBalanceAfter = IERC20(tokenIn).balanceOf(vault);
uint256 tokenOutBalanceAfter = IERC20(tokenOut).balanceOf(receiver);
if (tokenInBalanceAfter >= tokenInBalanceBefore) revert Errors.BalanceLessThanAmount();
if (tokenOutBalanceAfter <= tokenOutBalanceBefore) revert Errors.BalanceLessThanAmount();
} else {
revert Errors.SwapFailed();
}
return uint96(returnAmount);
}
}
文件 26 的 30:Strings.sol
pragma solidity ^0.8.0;
import "./math/Math.sol";
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
文件 27 的 30:Trade.sol
pragma solidity ^0.8.17;
import {Commands} from "src/libraries/Commands.sol";
import {Errors} from "src/libraries/Errors.sol";
import {IStvAccount} from "src/interfaces/IStvAccount.sol";
import {SpotTrade} from "src/SpotTrade/SpotTrade.sol";
import {IOperator} from "src/storage/interfaces/IOperator.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IPerpTrade} from "src/PerpTrade/interfaces/IPerpTrade.sol";
library Trade {
function execute(uint256 command, bytes calldata data, bool isOpen, address operator)
external
returns (uint96 totalReceived)
{
(address stvId, uint96 amount, address tradeToken) = _getParams(data);
address defaultStableCoin = IOperator(operator).getAddress("DEFAULTSTABLECOIN");
if (tradeToken == defaultStableCoin) revert Errors.InputMismatch();
address tokenIn = isOpen ? defaultStableCoin : tradeToken;
address tokenOut = isOpen ? tradeToken : defaultStableCoin;
if (command == Commands.UNI) {
(,,, bytes memory commands, bytes[] memory inputs, uint256 deadline) =
abi.decode(data, (address, uint96, address, bytes, bytes[], uint256));
bytes memory addresses = abi.encode(stvId, operator);
_transferTokens(stvId, amount, tokenIn, operator);
totalReceived = SpotTrade.uni(tokenIn, tokenOut, amount, commands, inputs, deadline, addresses);
} else if (command == Commands.SUSHI) {
(,,, uint256 amountOutMin) = abi.decode(data, (address, uint96, address, uint256));
if (amountOutMin < 1) revert Errors.ZeroAmount();
_transferTokens(stvId, amount, tokenIn, operator);
totalReceived = SpotTrade.sushi(tokenIn, tokenOut, amount, amountOutMin, stvId, operator);
} else if (command == Commands.ONE_INCH) {
(,,, bytes memory exchangeData) = abi.decode(data, (address, uint96, address, bytes));
_transferTokens(stvId, amount, tokenIn, operator);
totalReceived = SpotTrade.oneInch(tokenIn, tokenOut, stvId, exchangeData, operator);
} else {
revert Errors.CommandMisMatch();
}
}
function distribute(
address stvId,
uint256 command,
uint96 totalDepositTokenUsed,
uint96 managerFees,
uint96 protocolFees,
address[] calldata tradeTokens,
bytes[] calldata exchangeData,
address operator
) external returns (uint96 totalRemainingAfterDistribute, uint96 mFee, uint96 pFee) {
address id = stvId;
address defaultStableCoin = IOperator(operator).getAddress("DEFAULTSTABLECOIN");
uint256 depositTokenBalance = IERC20(defaultStableCoin).balanceOf(id);
{
uint256 c = command;
if (c == Commands.GMX) {
address[] memory tts = tradeTokens;
bytes[] memory tokenSwapExchangeData = exchangeData;
if (tts.length != tokenSwapExchangeData.length) revert Errors.LengthMismatch();
_swap(id, operator, tts, tokenSwapExchangeData);
} else if (c == Commands.KWENTA) {
address perpTrade = IOperator(operator).getAddress("PERPTRADE");
IPerpTrade(perpTrade).execute(Commands.KWENTA, exchangeData[0], false);
}
uint256 depositTokenBalanceAfter = IERC20(defaultStableCoin).balanceOf(id);
if (depositTokenBalanceAfter > depositTokenBalance) depositTokenBalance = depositTokenBalanceAfter;
if (depositTokenBalance < 1) revert Errors.ZeroAmount();
}
(totalRemainingAfterDistribute, mFee, pFee) =
_distribute(totalDepositTokenUsed, uint96(depositTokenBalance), managerFees, protocolFees);
}
function _getParams(bytes calldata data) internal pure returns (address stvId, uint96 amount, address tradeToken) {
assembly {
stvId := calldataload(data.offset)
amount := calldataload(add(data.offset, 0x20))
tradeToken := calldataload(add(data.offset, 0x40))
}
}
function _transferTokens(address stvId, uint96 amount, address tokenIn, address operator) internal {
address vault = IOperator(operator).getAddress("VAULT");
bytes memory tradeData = abi.encodeWithSignature("transfer(address,uint256)", vault, amount);
IStvAccount(stvId).execute(tokenIn, tradeData, 0);
}
function _distribute(uint96 totalRaised, uint96 totalReceivedAfterClose, uint96 managerFees, uint96 protocolFees)
internal
pure
returns (uint96 totalRemainingAfterDistribute, uint96 mFee, uint96 pFee)
{
if (totalReceivedAfterClose > totalRaised) {
uint96 profits = totalReceivedAfterClose - totalRaised;
mFee = (profits * (managerFees / 1e18)) / 100;
pFee = (profits * (protocolFees / 1e18)) / 100;
totalRemainingAfterDistribute = totalReceivedAfterClose - mFee - pFee;
} else {
totalRemainingAfterDistribute = totalReceivedAfterClose;
}
}
function _swap(address account, address operator, address[] memory tokensIn, bytes[] memory exchangeData)
internal
{
if (tokensIn.length != exchangeData.length) revert Errors.LengthMismatch();
address exchangeRouter = IOperator(operator).getAddress("ONEINCHROUTER");
uint256 i;
for (; i < tokensIn.length;) {
if (tokensIn[i] != address(0)) {
address defaultStableCoin = IOperator(operator).getAddress("DEFAULTSTABLECOIN");
uint256 balanceBefore = IERC20(defaultStableCoin).balanceOf(account);
uint256 tokenInBalance = IERC20(tokensIn[i]).balanceOf(account);
bytes memory tokenApprovalData =
abi.encodeWithSignature("approve(address,uint256)", exchangeRouter, tokenInBalance);
IStvAccount(account).execute(tokensIn[i], tokenApprovalData, 0);
IStvAccount(account).execute(exchangeRouter, exchangeData[i], 0);
uint256 balanceAfter = IERC20(defaultStableCoin).balanceOf(account);
if (balanceAfter <= balanceBefore) revert Errors.BalanceLessThanAmount();
} else {
uint256 ethBalance = account.balance;
bytes memory ethSwapExchangeData = exchangeData[0];
if (ethBalance > 0) IStvAccount(account).execute(exchangeRouter, ethSwapExchangeData, ethBalance);
}
unchecked {
++i;
}
}
}
}
文件 28 的 30:Vault.sol
pragma solidity ^0.8.17;
import {IVault} from "src/interfaces/IVault.sol";
import {Errors} from "src/libraries/Errors.sol";
import {BytesCheck} from "src/libraries/BytesCheck.sol";
import {VaultEvents} from "src/storage/VaultEvents.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IAccount} from "src/q/interfaces/IAccount.sol";
import {IStvAccount} from "src/interfaces/IStvAccount.sol";
import {IQ} from "src/q/interfaces/IQ.sol";
import {Generate} from "src/Generate.sol";
import {Trade} from "src/Trade.sol";
import {IOperator} from "src/storage/interfaces/IOperator.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract Vault is ReentrancyGuard, IVault, VaultEvents {
using SafeERC20 for IERC20;
address public operator;
uint40 public maxFundraisingPeriod;
mapping(address => uint256) public nonces;
bytes32 public constant EXECUTE_TYPEHASH = keccak256("executeData(bytes data,address user,uint256 nonce)");
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 private immutable _hashedName = keccak256(bytes("vault"));
bytes32 private immutable _hashedVersion = keccak256(bytes("1"));
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
constructor(address _operator, uint40 _maxFundraisingPeriod) {
operator = _operator;
maxFundraisingPeriod = _maxFundraisingPeriod;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedChainId = block.chainid;
_cachedThis = address(this);
emit InitVault(_operator, _maxFundraisingPeriod, _cachedDomainSeparator, EXECUTE_TYPEHASH);
}
modifier onlyOwner() {
address owner = IOperator(operator).getAddress("OWNER");
if (msg.sender != owner) revert Errors.NotOwner();
_;
}
modifier onlyAdmin() {
address admin = IOperator(operator).getAddress("ADMIN");
if (msg.sender != admin) revert Errors.NotAdmin();
_;
}
function DOMAIN_SEPARATOR() public view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
function getQ() external view returns (address) {
address q = IOperator(operator).getAddress("Q");
return q;
}
function getStvInfo(address stvId) public view returns (StvInfo memory) {
return IStvAccount(stvId).stvInfo();
}
function getStvBalance(address stvId) public view returns (StvBalance memory) {
return IStvAccount(stvId).stvBalance();
}
function getInvestorInfo(address investor, address stvId) public view returns (InvestorInfo memory) {
return IStvAccount(stvId).investorInfo(investor);
}
function getInvestors(address stvId) public view returns (address[] memory) {
return IStvAccount(stvId).getInvestors();
}
function setMaxFundraisingPeriod(uint40 _maxFundraisingPeriod) external onlyOwner {
if (_maxFundraisingPeriod == 0) revert Errors.ZeroAmount();
maxFundraisingPeriod = _maxFundraisingPeriod;
emit MaxFundraisingPeriod(_maxFundraisingPeriod);
}
function createStv(
uint96 capacityOfStv,
uint96 subscriptionFundLimit,
bytes32 metadataHash,
bytes calldata signature
) external returns (address stvId) {
if (subscriptionFundLimit > capacityOfStv) revert Errors.InputMismatch();
bytes memory data = abi.encode(capacityOfStv, metadataHash);
_verifyData(data, signature);
address op = operator;
address managerAccount = IOperator(op).getTraderAccount(msg.sender);
address q = IOperator(op).getAddress("Q");
if (managerAccount == address(0)) IQ(q).createAccount(msg.sender);
StvInfo memory stv = Generate.generate(capacityOfStv, msg.sender, op, maxFundraisingPeriod);
stvId = stv.stvId;
IStvAccount(stvId).createStv(stv);
emit CreateStv(metadataHash, stv.stvId, stv.manager, stv.endTime, stv.capacityOfStv);
if (subscriptionFundLimit > 0) {
_investSubscribers(stvId, op, subscriptionFundLimit);
}
}
function createStvWithDeposit(
uint96 capacityOfStv,
uint96 subscriptionFundLimit,
bytes32 metadataHash,
address token,
uint96 amount,
bytes memory exchangeData,
bytes calldata signature
) external payable nonReentrant returns (address stvId) {
bytes memory validateData = abi.encode(capacityOfStv, metadataHash, exchangeData);
_verifyData(validateData, signature);
address op = operator;
address traderAccount;
{
traderAccount = IOperator(op).getTraderAccount(msg.sender);
address q = IOperator(op).getAddress("Q");
if (traderAccount == address(0)) traderAccount = IQ(q).createAccount(msg.sender);
}
{
StvInfo memory stv = Generate.generate(capacityOfStv, msg.sender, op, maxFundraisingPeriod);
stvId = stv.stvId;
IStvAccount(stvId).createStv(stv);
emit CreateStv(metadataHash, stvId, stv.manager, stv.endTime, stv.capacityOfStv);
}
{
uint96 totalDepositWithSubscription;
if (subscriptionFundLimit > 0) {
totalDepositWithSubscription = _investSubscribers(stvId, op, subscriptionFundLimit);
}
uint256 returnAmount = _swap(token, stvId, amount, exchangeData, traderAccount);
if (totalDepositWithSubscription + uint96(returnAmount) > capacityOfStv) {
revert Errors.TotalRaisedMoreThanCapacity();
}
IStvAccount(stvId).deposit(traderAccount, uint96(returnAmount), true);
emit Deposit(stvId, msg.sender, msg.sender, uint96(returnAmount));
}
}
function deposit(address stvId, uint96 amount) external nonReentrant {
address account = IOperator(operator).getTraderAccount(msg.sender);
StvInfo memory stv = getStvInfo(stvId);
StvBalance memory sBalance = getStvBalance(stvId);
InvestorInfo memory investorInfo = getInvestorInfo(account, stvId);
address defaultStableCoin = IOperator(operator).getAddress("DEFAULTSTABLECOIN");
uint256 accountBalance = IERC20(defaultStableCoin).balanceOf(account);
uint256 minDepositAmount = 10 ** IERC20(defaultStableCoin).decimals();
if (amount < minDepositAmount) revert Errors.BelowMinStvDepositAmount();
if (account == address(0)) revert Errors.AccountNotExists();
if (accountBalance < amount) revert Errors.BalanceLessThanAmount();
if (stv.manager == address(0)) revert Errors.StvDoesNotExist();
if (uint40(block.timestamp) > stv.endTime) revert Errors.FundraisingPeriodEnded();
if (stv.status != StvStatus.NOT_OPENED) revert Errors.AlreadyOpened();
if (sBalance.totalRaised + amount > stv.capacityOfStv) {
revert Errors.TotalRaisedMoreThanCapacity();
}
if (investorInfo.depositAmount == 0) IStvAccount(stvId).deposit(account, amount, true);
else IStvAccount(stvId).deposit(account, amount, false);
bytes memory transferData = abi.encodeWithSignature("transfer(address,uint256)", stvId, amount);
IAccount(payable(account)).execute(defaultStableCoin, transferData, 0);
emit Deposit(stvId, msg.sender, msg.sender, amount);
}
function depositTo(
address to,
address stvId,
uint96 amount,
address token,
bytes memory exchangeData,
bytes calldata signature
) external payable nonReentrant {
_verifyData(exchangeData, signature);
address account = IOperator(operator).getTraderAccount(to);
address q = IOperator(operator).getAddress("Q");
if (account == address(0)) account = IQ(q).createAccount(to);
StvInfo memory stv = getStvInfo(stvId);
StvBalance memory sBalance = getStvBalance(stvId);
InvestorInfo memory investorInfo = getInvestorInfo(account, stvId);
if (token == address(0)) {
if (msg.value != amount) revert Errors.InputMismatch();
} else {
uint256 accountBalance = IERC20(token).balanceOf(msg.sender);
if (amount > accountBalance) revert Errors.BalanceLessThanAmount();
}
if (stv.manager == address(0)) revert Errors.StvDoesNotExist();
if (uint40(block.timestamp) > stv.endTime) revert Errors.FundraisingPeriodEnded();
if (stv.status != StvStatus.NOT_OPENED) revert Errors.AlreadyOpened();
amount = uint96(_swap(token, stvId, amount, exchangeData, account));
if (sBalance.totalRaised + amount > stv.capacityOfStv) {
revert Errors.TotalRaisedMoreThanCapacity();
}
if (investorInfo.depositAmount == 0) IStvAccount(stvId).deposit(account, amount, true);
else IStvAccount(stvId).deposit(account, amount, false);
emit Deposit(stvId, msg.sender, to, amount);
}
function liquidate(address stvId) external onlyAdmin {
IStvAccount(stvId).liquidate();
emit Liquidate(stvId, uint8(IVault.StvStatus.LIQUIDATED));
}
function execute(uint256 command, bytes calldata data, bool isOpen)
external
payable
onlyAdmin
returns (address tradeToken, uint96 totalReceived)
{
(address stvId, uint96 amount) = _getAmountAndStvId(data);
StvInfo memory stv = getStvInfo(stvId);
StvBalance memory sBalance = getStvBalance(stvId);
if (amount == 0) revert Errors.ZeroAmount();
if (sBalance.totalRaised < 1) revert Errors.ZeroTotalRaised();
if (stv.status != IVault.StvStatus.NOT_OPENED && stv.status != IVault.StvStatus.OPEN) {
revert Errors.StvStatusMismatch();
}
if (BytesCheck.checkFirstDigit0x1(uint8(command))) {
tradeToken = _getTradeToken(data);
if (!isOpen) {
if (
IStvAccount(stvId).totalTradeTokenUsedForClose(tradeToken) + amount
> IStvAccount(stvId).totalTradeTokenReceivedAfterOpen(tradeToken)
) {
revert Errors.MoreThanTotalRaised();
}
}
totalReceived = Trade.execute(command, data, isOpen, operator);
} else {
address perpTrade = IOperator(operator).getAddress("PERPTRADE");
bytes memory perpTradeData = abi.encodeWithSignature("execute(uint256,bytes,bool)", command, data, isOpen);
(bool success,) = perpTrade.call{value: msg.value}(perpTradeData);
if (!success) revert Errors.CallFailed(perpTradeData);
}
IStvAccount(stvId).execute(amount, tradeToken, totalReceived, isOpen);
emit Execute(stvId, amount, totalReceived, command, data, msg.value, isOpen);
}
function multiExecute(
uint256[] memory commands,
bytes[] calldata data,
uint256[] memory msgValue,
bool[] memory isOpen
) external payable onlyAdmin {
uint256 length = commands.length;
if (length != data.length) revert Errors.LengthMismatch();
if (length != msgValue.length) revert Errors.LengthMismatch();
uint256 i;
address tradeToken;
uint96 amountReceived;
for (; i < length;) {
uint256 command = commands[i];
bytes calldata tradeData = data[i];
uint256 value = msgValue[i];
bool openOrClose = isOpen[i];
(address stvId, uint96 amount) = _getAmountAndStvId(tradeData);
StvInfo memory stv = getStvInfo(stvId);
StvBalance memory sBalance = getStvBalance(stvId);
if (amount == 0) revert Errors.ZeroAmount();
if (sBalance.totalRaised < 1) revert Errors.ZeroTotalRaised();
if (stv.status != IVault.StvStatus.NOT_OPENED && stv.status != IVault.StvStatus.OPEN) {
revert Errors.StvStatusMismatch();
}
if (BytesCheck.checkFirstDigit0x1(uint8(command))) {
tradeToken = _getTradeToken(tradeData);
if (!openOrClose) {
if (
IStvAccount(stvId).totalTradeTokenUsedForClose(tradeToken) + amount
> IStvAccount(stvId).totalTradeTokenReceivedAfterOpen(tradeToken)
) {
revert Errors.MoreThanTotalRaised();
}
}
amountReceived = Trade.execute(command, tradeData, openOrClose, operator);
} else {
address perpTrade = IOperator(operator).getAddress("PERPTRADE");
bytes memory perpTradeData =
abi.encodeWithSignature("execute(uint256,bytes,bool)", command, tradeData, openOrClose);
(bool success,) = perpTrade.call{value: value}(perpTradeData);
if (!success) revert Errors.CallFailed(perpTradeData);
}
IStvAccount(stvId).execute(amount, tradeToken, amountReceived, openOrClose);
emit Execute(stvId, amount, amountReceived, command, tradeData, value, openOrClose);
unchecked {
++i;
}
}
}
function distribute(
address stvId,
uint256 command,
uint96 totalDepositTokenUsed,
uint96 managerFees,
uint96 protocolFees,
address[] calldata tradeTokens,
bytes[] calldata exchangeData
) external onlyAdmin {
uint256 c = command;
{
StvInfo memory stv = getStvInfo(stvId);
if (stv.status != StvStatus.OPEN) revert Errors.StvNotOpen();
}
(uint96 totalRemainingAfterDistribute, uint96 mFee, uint96 pFee) = Trade.distribute(
stvId, c, totalDepositTokenUsed, managerFees, protocolFees, tradeTokens, exchangeData, operator
);
IStvAccount(stvId).distribute(totalRemainingAfterDistribute, mFee, pFee);
emit Distribute(stvId, totalRemainingAfterDistribute, mFee, pFee, c);
}
function distributeOut(address stvId, bool isCancel, uint256 indexFrom, uint256 indexTo) external onlyAdmin {
IStvAccount(stvId).distributeOut(isCancel, indexFrom, indexTo);
}
function cancelStv(address stvId) external {
StvInfo memory stv = getStvInfo(stvId);
StvBalance memory sBalance = getStvBalance(stvId);
address admin = IOperator(operator).getAddress("ADMIN");
if (stv.status != StvStatus.NOT_OPENED) revert Errors.AlreadyOpened();
if (msg.sender == admin) {
if (uint40(block.timestamp) <= stv.endTime) revert Errors.BelowMinEndTime();
if (sBalance.totalRaised == 0) {
IStvAccount(stvId).updateStatus(StvStatus.CANCELLED_WITH_ZERO_RAISE);
} else {
IStvAccount(stvId).updateStatus(StvStatus.CANCELLED_WITH_NO_FILL);
}
} else if (msg.sender == stv.manager) {
IStvAccount(stvId).updateStatus(StvStatus.CANCELLED_BY_MANAGER);
} else {
revert Errors.NoAccess();
}
IStvAccount(stvId).cancel();
emit Cancel(stvId, uint8(stv.status));
}
function claimStvTradingReward(uint256[] calldata commands, bytes[] calldata data) external onlyAdmin {
address perpTrade = IOperator(operator).getAddress("PERPTRADE");
uint256 i;
for (; i < data.length;) {
uint256 command = commands[i];
bytes memory rewardData = data[i];
bytes memory perpTradeData =
abi.encodeWithSignature("execute(uint256,bytes,bool)", command, rewardData, false);
(bool success,) = perpTrade.call(perpTradeData);
if (!success) revert Errors.CallFailed(perpTradeData);
(address stvId,) = _getAmountAndStvId(data[i]);
emit ClaimRewards(stvId, command, rewardData);
unchecked {
++i;
}
}
}
function _investSubscribers(address stvId, address op, uint96 subscriptionFundLimit)
internal
returns (uint96 totalDepositWithSubscription)
{
address defaultStableCoin = IOperator(op).getAddress("DEFAULTSTABLECOIN");
address[] memory subscribers = IOperator(op).getAllSubscribers(msg.sender);
(bytes[] memory users, uint256 ratio) =
_getSubscriptionRatio(subscribers, subscriptionFundLimit, defaultStableCoin, op);
uint256 i;
for (; i < users.length;) {
(address traderAccount, uint96 amountToUse) = abi.decode(users[i], (address, uint96));
uint96 amountAfterRatio = uint96(uint256(amountToUse) * ratio / 1e18);
if (amountAfterRatio > 0) {
totalDepositWithSubscription += amountAfterRatio;
IStvAccount(stvId).deposit(traderAccount, amountAfterRatio, true);
bytes memory transferData = abi.encodeWithSignature("transfer(address,uint256)", stvId, amountAfterRatio);
IAccount(payable(traderAccount)).execute(defaultStableCoin, transferData, 0);
emit DepositWithSubscription(stvId, msg.sender, traderAccount, amountAfterRatio);
}
unchecked {
++i;
}
}
}
function _getAmountAndStvId(bytes calldata data) internal pure returns (address stvId, uint96 amount) {
assembly {
stvId := calldataload(data.offset)
amount := calldataload(add(data.offset, 0x20))
}
}
function _getTradeToken(bytes calldata data) internal pure returns (address tradeToken) {
assembly {
tradeToken := calldataload(add(data.offset, 0x40))
}
}
function _getSubscriptionRatio(address[] memory subscribers, uint96 capacity, address defaultStableCoin, address op)
internal
view
returns (bytes[] memory, uint256)
{
uint256 totalLiquidity;
uint256 i;
uint256 ratio;
bytes[] memory users = new bytes[](subscribers.length);
for (; i < subscribers.length;) {
address subscriber = subscribers[i];
uint96 maxLimit = IOperator(op).getSubscriptionAmount(msg.sender, subscriber);
uint96 traderAccountBalance = uint96(IERC20(defaultStableCoin).balanceOf(subscriber));
uint256 amountToUse = traderAccountBalance < maxLimit ? traderAccountBalance : maxLimit;
users[i] = abi.encode(subscriber, amountToUse);
totalLiquidity += amountToUse;
unchecked {
++i;
}
}
if (totalLiquidity > 0) {
uint256 capacityToSubscriptions = uint256(capacity) * 1e18 / uint256(totalLiquidity);
ratio = capacityToSubscriptions < 1e18 ? capacityToSubscriptions : 1e18;
}
return (users, ratio);
}
function _swap(address token, address to, uint96 amount, bytes memory exchangeData, address traderAccount)
internal
returns (uint256 returnAmount)
{
address defaultStableCoin = IOperator(operator).getAddress("DEFAULTSTABLECOIN");
if (token != defaultStableCoin) {
if (exchangeData.length == 0) revert Errors.ExchangeDataMismatch();
address exchangeRouter = IOperator(operator).getAddress("ONEINCHROUTER");
if (token != address(0)) {
IERC20(token).safeTransferFrom(msg.sender, to, amount);
bytes memory approveData = abi.encodeWithSelector(IERC20.approve.selector, exchangeRouter, amount);
IStvAccount(to).execute(token, approveData, 0);
}
uint256 balanceBefore = IERC20(defaultStableCoin).balanceOf(to);
IStvAccount(to).execute{value: msg.value}(exchangeRouter, exchangeData, msg.value);
uint256 balanceAfter = IERC20(defaultStableCoin).balanceOf(to);
if (balanceAfter <= balanceBefore) revert Errors.BalanceLessThanAmount();
returnAmount = balanceAfter - balanceBefore;
if (token != address(0) && (IERC20(token).allowance(to, exchangeRouter) != 0)) {
revert Errors.InputMismatch();
}
} else {
if (exchangeData.length != 0) revert Errors.ExchangeDataMismatch();
uint96 traderAccountBalance = uint96(IERC20(defaultStableCoin).balanceOf(traderAccount));
if (traderAccountBalance >= amount) {
bytes memory transferData = abi.encodeWithSignature("transfer(address,uint256)", to, amount);
IAccount(payable(traderAccount)).execute(defaultStableCoin, transferData, 0);
} else {
IERC20(defaultStableCoin).transferFrom(msg.sender, to, amount);
}
returnAmount = amount;
}
uint256 minDepositAmount = 10 ** IERC20(defaultStableCoin).decimals();
if (returnAmount < minDepositAmount) revert Errors.BelowMinStvDepositAmount();
}
function _verifyData(bytes memory data, bytes calldata signature) internal {
bytes32 structHash = keccak256(abi.encode(EXECUTE_TYPEHASH, keccak256(data), msg.sender, nonces[msg.sender]++));
bytes32 signedData = ECDSA.toTypedDataHash(DOMAIN_SEPARATOR(), structHash);
address signer = ECDSA.recover(signedData, signature);
address admin = IOperator(operator).getAddress("ADMIN");
if (signer != admin) revert Errors.NotAdmin();
}
}
文件 29 的 30:VaultEvents.sol
pragma solidity ^0.8.17;
contract VaultEvents {
event InitVault(
address indexed operator,
uint40 maxFundraisingPeriod,
bytes32 indexed domainSeparator,
bytes32 indexed executeTypeHash
);
event CreateStv(
bytes32 indexed metadataHash,
address indexed stvId,
address indexed manager,
uint40 endTime,
uint96 capacityOfStv
);
event Deposit(address indexed stvId, address indexed caller, address indexed investor, uint96 amount);
event DepositWithSubscription(
address indexed stvId, address indexed caller, address indexed investor, uint96 amount
);
event Liquidate(address indexed stvId, uint8 status);
event Execute(
address indexed stvId,
uint96 amount,
uint96 totalReceived,
uint256 command,
bytes data,
uint256 msgValue,
bool isIncrease
);
event Distribute(
address indexed stvId, uint96 totalRemainingAfterDistribute, uint96 mFee, uint96 pFee, uint256 command
);
event Cancel(address indexed stvId, uint8 status);
event MaxFundraisingPeriod(uint40 maxFundraisingPeriod);
event ClaimRewards(address indexed stvId, uint256 command, bytes indexed rewardData);
}
文件 30 的 30: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": {
"src/Vault.sol": "Vault"
},
"evmVersion": "paris",
"libraries": {
"src/Generate.sol:Generate": "0x74e0ca6e1ecfb462a80f3b7ab6840013ee32c1c5",
"src/SpotTrade/SpotTrade.sol:SpotTrade": "0x019dfb87e218a07091c83cec604cb2d48fbdf194",
"src/Trade.sol:Trade": "0x16766913fae839da226a669c76f04b2b5e2380a0",
"src/libraries/BytesCheck.sol:BytesCheck": "0x3f3a5da6dbb99dc879a8ed2ec26c831da962231f"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
":@openzeppelin/=lib/openzeppelin-contracts/",
":@synthetix/=src/interfaces/synthetix/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":solmate/=lib/solmate/src/"
]
}
[{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"uint40","name":"_maxFundraisingPeriod","type":"uint40"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountNotExists","type":"error"},{"inputs":[],"name":"AlreadyOpened","type":"error"},{"inputs":[],"name":"BalanceLessThanAmount","type":"error"},{"inputs":[],"name":"BelowMinEndTime","type":"error"},{"inputs":[],"name":"BelowMinStvDepositAmount","type":"error"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"CallFailed","type":"error"},{"inputs":[],"name":"ExchangeDataMismatch","type":"error"},{"inputs":[],"name":"FundraisingPeriodEnded","type":"error"},{"inputs":[],"name":"InputMismatch","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"MoreThanTotalRaised","type":"error"},{"inputs":[],"name":"NoAccess","type":"error"},{"inputs":[],"name":"NotAdmin","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"StvDoesNotExist","type":"error"},{"inputs":[],"name":"StvNotOpen","type":"error"},{"inputs":[],"name":"StvStatusMismatch","type":"error"},{"inputs":[],"name":"TotalRaisedMoreThanCapacity","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroTotalRaised","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stvId","type":"address"},{"indexed":false,"internalType":"uint8","name":"status","type":"uint8"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stvId","type":"address"},{"indexed":false,"internalType":"uint256","name":"command","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"rewardData","type":"bytes"}],"name":"ClaimRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"metadataHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"stvId","type":"address"},{"indexed":true,"internalType":"address","name":"manager","type":"address"},{"indexed":false,"internalType":"uint40","name":"endTime","type":"uint40"},{"indexed":false,"internalType":"uint96","name":"capacityOfStv","type":"uint96"}],"name":"CreateStv","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stvId","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"investor","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stvId","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"investor","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"DepositWithSubscription","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stvId","type":"address"},{"indexed":false,"internalType":"uint96","name":"totalRemainingAfterDistribute","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"mFee","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"pFee","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"command","type":"uint256"}],"name":"Distribute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stvId","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"totalReceived","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"command","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"msgValue","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isIncrease","type":"bool"}],"name":"Execute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint40","name":"maxFundraisingPeriod","type":"uint40"},{"indexed":true,"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"executeTypeHash","type":"bytes32"}],"name":"InitVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stvId","type":"address"},{"indexed":false,"internalType":"uint8","name":"status","type":"uint8"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"maxFundraisingPeriod","type":"uint40"}],"name":"MaxFundraisingPeriod","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stvId","type":"address"}],"name":"cancelStv","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"commands","type":"uint256[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"claimStvTradingReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"capacityOfStv","type":"uint96"},{"internalType":"uint96","name":"subscriptionFundLimit","type":"uint96"},{"internalType":"bytes32","name":"metadataHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"createStv","outputs":[{"internalType":"address","name":"stvId","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"capacityOfStv","type":"uint96"},{"internalType":"uint96","name":"subscriptionFundLimit","type":"uint96"},{"internalType":"bytes32","name":"metadataHash","type":"bytes32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"bytes","name":"exchangeData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"createStvWithDeposit","outputs":[{"internalType":"address","name":"stvId","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"stvId","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"stvId","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes","name":"exchangeData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"depositTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"stvId","type":"address"},{"internalType":"uint256","name":"command","type":"uint256"},{"internalType":"uint96","name":"totalDepositTokenUsed","type":"uint96"},{"internalType":"uint96","name":"managerFees","type":"uint96"},{"internalType":"uint96","name":"protocolFees","type":"uint96"},{"internalType":"address[]","name":"tradeTokens","type":"address[]"},{"internalType":"bytes[]","name":"exchangeData","type":"bytes[]"}],"name":"distribute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stvId","type":"address"},{"internalType":"bool","name":"isCancel","type":"bool"},{"internalType":"uint256","name":"indexFrom","type":"uint256"},{"internalType":"uint256","name":"indexTo","type":"uint256"}],"name":"distributeOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"command","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bool","name":"isOpen","type":"bool"}],"name":"execute","outputs":[{"internalType":"address","name":"tradeToken","type":"address"},{"internalType":"uint96","name":"totalReceived","type":"uint96"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"investor","type":"address"},{"internalType":"address","name":"stvId","type":"address"}],"name":"getInvestorInfo","outputs":[{"components":[{"internalType":"uint96","name":"depositAmount","type":"uint96"},{"internalType":"uint96","name":"claimedAmount","type":"uint96"},{"internalType":"bool","name":"claimed","type":"bool"}],"internalType":"struct IVault.InvestorInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stvId","type":"address"}],"name":"getInvestors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getQ","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stvId","type":"address"}],"name":"getStvBalance","outputs":[{"components":[{"internalType":"uint96","name":"totalRaised","type":"uint96"},{"internalType":"uint96","name":"totalRemainingAfterDistribute","type":"uint96"}],"internalType":"struct IVault.StvBalance","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stvId","type":"address"}],"name":"getStvInfo","outputs":[{"components":[{"internalType":"address","name":"stvId","type":"address"},{"internalType":"uint40","name":"endTime","type":"uint40"},{"internalType":"enum IVault.StvStatus","name":"status","type":"uint8"},{"internalType":"address","name":"manager","type":"address"},{"internalType":"uint96","name":"capacityOfStv","type":"uint96"}],"internalType":"struct IVault.StvInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stvId","type":"address"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxFundraisingPeriod","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"commands","type":"uint256[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"uint256[]","name":"msgValue","type":"uint256[]"},{"internalType":"bool[]","name":"isOpen","type":"bool[]"}],"name":"multiExecute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint40","name":"_maxFundraisingPeriod","type":"uint40"}],"name":"setMaxFundraisingPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"}]