编译器
0.8.17+commit.8df45f5f
文件 1 的 17: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 的 17:CommandBuilder.sol
pragma solidity 0.8.17;
library CommandBuilder {
uint256 constant IDX_VARIABLE_LENGTH = 0x80;
uint256 constant IDX_VALUE_MASK = 0x7f;
uint256 constant IDX_END_OF_ARGS = 0xff;
uint256 constant IDX_USE_STATE = 0xfe;
function buildInputs(
bytes[] memory state,
bytes4 selector,
bytes32 indices
) internal view returns (bytes memory ret) {
uint256 count;
uint256 free;
bytes memory stateData;
uint256 idx;
for (uint256 i; i < 32;) {
idx = uint8(indices[i]);
if (idx == IDX_END_OF_ARGS) break;
if (idx & IDX_VARIABLE_LENGTH != 0) {
if (idx == IDX_USE_STATE) {
if (stateData.length == 0) {
stateData = abi.encode(state);
}
count += stateData.length;
} else {
uint256 arglen = state[idx & IDX_VALUE_MASK].length;
require(
arglen % 32 == 0,
"Dynamic state variables must be a multiple of 32 bytes"
);
count += arglen + 32;
}
} else {
require(
state[idx & IDX_VALUE_MASK].length == 32,
"Static state variables must be 32 bytes"
);
count += 32;
}
unchecked{free += 32;}
unchecked{++i;}
}
ret = new bytes(count + 4);
assembly {
mstore(add(ret, 32), selector)
}
count = 0;
for (uint256 i; i < 32;) {
idx = uint8(indices[i]);
if (idx == IDX_END_OF_ARGS) break;
if (idx & IDX_VARIABLE_LENGTH != 0) {
if (idx == IDX_USE_STATE) {
assembly {
mstore(add(add(ret, 36), count), free)
}
memcpy(stateData, 32, ret, free + 4, stateData.length - 32);
free += stateData.length - 32;
} else {
uint256 arglen = state[idx & IDX_VALUE_MASK].length;
assembly {
mstore(add(add(ret, 36), count), free)
}
memcpy(
state[idx & IDX_VALUE_MASK],
0,
ret,
free + 4,
arglen
);
free += arglen;
}
} else {
bytes memory statevar = state[idx & IDX_VALUE_MASK];
assembly {
mstore(add(add(ret, 36), count), mload(add(statevar, 32)))
}
}
unchecked{count += 32;}
unchecked{++i;}
}
}
function writeOutputs(
bytes[] memory state,
bytes1 index,
bytes memory output
) internal view returns (bytes[] memory) {
uint256 idx = uint8(index);
if (idx == IDX_END_OF_ARGS) return state;
if (idx & IDX_VARIABLE_LENGTH != 0) {
if (idx == IDX_USE_STATE) {
state = abi.decode(output, (bytes[]));
} else {
uint256 argptr;
assembly {
argptr := mload(add(output, 32))
}
require(
argptr == 32,
"Only one return value permitted (variable)"
);
assembly {
mstore(add(output, 32), sub(mload(output), 32))
mstore(
add(add(state, 32), mul(and(idx, IDX_VALUE_MASK), 32)),
add(output, 32)
)
}
}
} else {
require(output.length >= 32, "Return at least 32 bytes");
if (output.length > 32) {
bytes memory newOutput = new bytes(32);
memcpy(output, 0, newOutput, 0, output.length);
output = newOutput;
}
state[idx & IDX_VALUE_MASK] = output;
}
return state;
}
function writeTuple(
bytes[] memory state,
bytes1 index,
bytes memory output
) internal view {
uint256 idx = uint256(uint8(index));
if (idx == IDX_END_OF_ARGS) return;
bytes memory entry = state[idx] = new bytes(output.length + 32);
memcpy(output, 0, entry, 32, output.length);
assembly {
let l := mload(output)
mstore(add(entry, 32), l)
}
}
function memcpy(
bytes memory src,
uint256 srcidx,
bytes memory dest,
uint256 destidx,
uint256 len
) internal view {
assembly {
pop(
staticcall(
gas(),
4,
add(add(src, 32), srcidx),
len,
add(add(dest, 32), destidx),
len
)
)
}
}
}
文件 3 的 17: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 的 17:ERC2771Context.sol
pragma solidity ^0.8.9;
import "../utils/Context.sol";
abstract contract ERC2771Context is Context {
address private immutable _trustedForwarder;
constructor(address trustedForwarder) {
_trustedForwarder = trustedForwarder;
}
function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
return forwarder == _trustedForwarder;
}
function _msgSender() internal view virtual override returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
return super._msgSender();
}
}
function _msgData() internal view virtual override returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[:msg.data.length - 20];
} else {
return super._msgData();
}
}
}
文件 5 的 17: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);
}
文件 6 的 17:IFolio.sol
pragma solidity 0.8.17;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IVotes } from "@openzeppelin/contracts/governance/utils/IVotes.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
interface IFolio is IERC20 {
event AuctionApproved(uint256 indexed auctionId, address indexed from, address indexed to, Auction auction);
event AuctionOpened(uint256 indexed auctionId, Auction auction);
event AuctionBid(uint256 indexed auctionId, uint256 sellAmount, uint256 buyAmount);
event AuctionClosed(uint256 indexed auctionId);
event FolioFeePaid(address indexed recipient, uint256 amount);
event ProtocolFeePaid(address indexed recipient, uint256 amount);
event BasketTokenAdded(address indexed token);
event BasketTokenRemoved(address indexed token);
event TVLFeeSet(uint256 newFee, uint256 feeAnnually);
event MintFeeSet(uint256 newFee);
event FeeRecipientSet(address indexed recipient, uint96 portion);
event AuctionDelaySet(uint256 newAuctionDelay);
event AuctionLengthSet(uint256 newAuctionLength);
event MandateSet(string newMandate);
event FolioKilled();
error Folio__FolioKilled();
error Folio__Unauthorized();
error Folio__EmptyAssets();
error Folio__BasketModificationFailed();
error Folio__FeeRecipientInvalidAddress();
error Folio__FeeRecipientInvalidFeeShare();
error Folio__BadFeeTotal();
error Folio__TVLFeeTooHigh();
error Folio__TVLFeeTooLow();
error Folio__MintFeeTooHigh();
error Folio__ZeroInitialShares();
error Folio__InvalidAsset();
error Folio__InvalidAssetAmount(address asset);
error Folio__InvalidAuctionLength();
error Folio__InvalidSellLimit();
error Folio__InvalidBuyLimit();
error Folio__AuctionCannotBeOpened();
error Folio__AuctionCannotBeOpenedPermissionlesslyYet();
error Folio__AuctionNotOngoing();
error Folio__AuctionCollision();
error Folio__InvalidPrices();
error Folio__AuctionTimeout();
error Folio__SlippageExceeded();
error Folio__InsufficientBalance();
error Folio__InsufficientBid();
error Folio__ExcessiveBid();
error Folio__InvalidAuctionTokens();
error Folio__InvalidAuctionDelay();
error Folio__InvalidAuctionTTL();
error Folio__TooManyFeeRecipients();
error Folio__InvalidArrayLengths();
struct FolioBasicDetails {
string name;
string symbol;
address[] assets;
uint256[] amounts;
uint256 initialShares;
}
struct FolioAdditionalDetails {
uint256 auctionDelay;
uint256 auctionLength;
FeeRecipient[] feeRecipients;
uint256 tvlFee;
uint256 mintFee;
string mandate;
}
struct FeeRecipient {
address recipient;
uint96 portion;
}
struct BasketRange {
uint256 spot;
uint256 low;
uint256 high;
}
struct Prices {
uint256 start;
uint256 end;
}
struct Auction {
uint256 id;
IERC20 sell;
IERC20 buy;
BasketRange sellLimit;
BasketRange buyLimit;
Prices prices;
uint256 availableAt;
uint256 launchTimeout;
uint256 start;
uint256 end;
uint256 k;
}
function distributeFees() external;
function folio() external view returns (address[] memory _assets, uint256[] memory _amounts);
function toAssets(uint256 shares, Math.Rounding rounding) external view returns (address[] memory _assets, uint256[] memory _amounts);
function AUCTION_APPROVER() external view returns (bytes32);
function AUCTION_LAUNCHER() external view returns (bytes32);
function BRAND_MANAGER() external view returns (bytes32);
function mint(uint256 shares, address receiver) external returns (address[] memory _assets, uint256[] memory _amounts);
function redeem(
uint256 shares,
address receiver,
address[] calldata assets,
uint256[] calldata minAmountsOut
) external returns (uint256[] memory _amounts);
}
interface IGovernanceDeployer {
struct GovParams {
uint48 votingDelay;
uint32 votingPeriod;
uint256 proposalThreshold;
uint256 quorumPercent;
uint256 timelockDelay;
address[] guardians;
}
function deployGovernanceWithTimelock(
IGovernanceDeployer.GovParams calldata govParams,
IVotes stToken
) external returns (address governor, address timelock);
}
struct GovRoles {
address[] existingTradeProposers;
address[] tradeLaunchers;
address[] vibesOfficers;
}
interface IFolioDeployer {
error FolioDeployer__LengthMismatch();
event FolioDeployed(address indexed folioOwner, address indexed folio, address folioAdmin);
event GovernedFolioDeployed(
address indexed stToken,
address indexed folio,
address ownerGovernor,
address ownerTimelock,
address tradingGovernor,
address tradingTimelock
);
function folioImplementation() external view returns (address);
function deployFolio(
IFolio.FolioBasicDetails calldata basicDetails,
IFolio.FolioAdditionalDetails calldata additionalDetails,
address owner,
address[] memory auctionApprovers,
address[] memory auctionLaunchers,
address[] memory brandManagers,
bytes32 deploymentNonce
) external returns (address folio, address proxyAdmin);
function deployGovernedFolio(
IVotes stToken,
IFolio.FolioBasicDetails calldata basicDetails,
IFolio.FolioAdditionalDetails calldata additionalDetails,
IGovernanceDeployer.GovParams calldata ownerGovParams,
IGovernanceDeployer.GovParams calldata tradingGovParams,
GovRoles calldata govRoles,
bytes32 deploymentNonce
)
external
returns (
address folio,
address proxyAdmin,
address ownerGovernor,
address ownerTimelock,
address tradingGovernor,
address tradingTimelock
);
}
文件 7 的 17:IRTokenZapper.sol
pragma solidity 0.8.17;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
struct Call {
address to;
bytes data;
uint256 value;
}
struct ZapERC20Params {
IERC20 tokenIn;
uint256 amountIn;
bytes32[] commands;
bytes[] state;
IERC20[] tokens;
uint256 amountOut;
IERC20 tokenOut;
}
struct ZapParams {
address tokenIn;
uint256 amountIn;
bytes32[] commands;
bytes[] state;
IERC20[] tokens;
uint256 amountOut;
address tokenOut;
address recipient;
}
文件 8 的 17:IVotes.sol
pragma solidity ^0.8.0;
interface IVotes {
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
function getVotes(address account) external view returns (uint256);
function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
function delegates(address account) external view returns (address);
function delegate(address delegatee) external;
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
文件 9 的 17:IWrappedNative.sol
pragma solidity 0.8.17;
interface IWrappedNative {
function deposit() external payable;
function withdraw(uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
}
文件 10 的 17: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);
}
}
}
文件 11 的 17:PreventTampering.sol
pragma solidity 0.8.17;
abstract contract PreventTampering {
modifier revertOnCodeHashChange() {
bytes32 hashBefore;
assembly {
hashBefore := extcodehash(address())
}
_;
bytes32 hashPostExecution;
assembly {
hashPostExecution := extcodehash(address())
}
require(hashPostExecution == hashBefore, "PreventTampering: Code has changed");
}
}
contract SelfDestruct {
function destroy() external {
selfdestruct(payable(msg.sender));
}
function doNothing() external {}
}
contract TestPreventTampering is PreventTampering {
function shouldNotRevert() external {
SelfDestruct selfDestruct = new SelfDestruct();
address(selfDestruct).delegatecall(abi.encodeWithSelector(selfDestruct.destroy.selector));
}
function shouldRevert() revertOnCodeHashChange() external {
SelfDestruct selfDestruct = new SelfDestruct();
address(selfDestruct).delegatecall(abi.encodeWithSelector(selfDestruct.destroy.selector));
}
function markedRevertOnCodeHashChangeDontRevert() revertOnCodeHashChange() external {
SelfDestruct selfDestruct = new SelfDestruct();
address(selfDestruct).delegatecall(abi.encodeWithSelector(selfDestruct.doNothing.selector));
}
}
文件 12 的 17: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;
}
}
文件 13 的 17: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");
}
}
}
文件 14 的 17:VM.sol
pragma solidity 0.8.17;
import "./CommandBuilder.sol";
abstract contract VM {
using CommandBuilder for bytes[];
uint256 constant FLAG_CT_DELEGATECALL = 0x00;
uint256 constant FLAG_CT_CALL = 0x01;
uint256 constant FLAG_CT_STATICCALL = 0x02;
uint256 constant FLAG_CT_VALUECALL = 0x03;
uint256 constant FLAG_CT_MASK = 0x03;
uint256 constant FLAG_EXTENDED_COMMAND = 0x80;
uint256 constant FLAG_TUPLE_RETURN = 0x40;
uint256 constant SHORT_COMMAND_FILL = 0x000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
address immutable self;
error ExecutionFailed(
uint256 command_index,
address target,
string message
);
constructor() {
self = address(this);
}
function _execute(bytes32[] calldata commands, bytes[] memory state)
internal returns (bytes[] memory)
{
bytes32 command;
uint256 flags;
bytes32 indices;
bool success;
bytes memory outdata;
uint256 commandsLength = commands.length;
for (uint256 i; i < commandsLength;) {
command = commands[i];
flags = uint256(uint8(bytes1(command << 32)));
if (flags & FLAG_EXTENDED_COMMAND != 0) {
indices = commands[i++];
} else {
indices = bytes32(uint256(command << 40) | SHORT_COMMAND_FILL);
}
if (flags & FLAG_CT_MASK == FLAG_CT_DELEGATECALL) {
(success, outdata) = address(uint160(uint256(command))).delegatecall(
state.buildInputs(
bytes4(command),
indices
)
);
} else if (flags & FLAG_CT_MASK == FLAG_CT_CALL) {
(success, outdata) = address(uint160(uint256(command))).call(
state.buildInputs(
bytes4(command),
indices
)
);
} else if (flags & FLAG_CT_MASK == FLAG_CT_STATICCALL) {
(success, outdata) = address(uint160(uint256(command))).staticcall(
state.buildInputs(
bytes4(command),
indices
)
);
} else if (flags & FLAG_CT_MASK == FLAG_CT_VALUECALL) {
uint256 calleth;
bytes memory v = state[uint8(bytes1(indices))];
require(v.length == 32, "_execute: value call has no value indicated.");
assembly {
calleth := mload(add(v, 0x20))
}
(success, outdata) = address(uint160(uint256(command))).call{
value: calleth
}(
state.buildInputs(
bytes4(command),
bytes32(uint256(indices << 8) | CommandBuilder.IDX_END_OF_ARGS)
)
);
} else {
revert("Invalid calltype");
}
if (!success) {
if (outdata.length > 0) {
assembly {
outdata := add(outdata, 68)
}
}
revert ExecutionFailed({
command_index: i,
target: address(uint160(uint256(command))),
message: string(outdata)
});
}
if (flags & FLAG_TUPLE_RETURN != 0) {
state.writeTuple(bytes1(command << 88), outdata);
} else {
state = state.writeOutputs(bytes1(command << 88), outdata);
}
unchecked{++i;}
}
return state;
}
}
文件 15 的 17:Zapper2.sol
pragma solidity 0.8.17;
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ERC2771Context } from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import { IWrappedNative } from "./IWrappedNative.sol";
import { VM } from "./weiroll/VM.sol";
import { PreventTampering } from "./PreventTampering.sol";
import { ZapParams, ZapERC20Params } from "./IRTokenZapper.sol";
import { ZapperExecutor, DeployFolioConfig, ExecuteDeployOutput } from "./ZapperExecutor.sol";
struct ZapperOutput {
uint256[] dust;
uint256 amountOut;
uint256 gasUsed;
}
contract Zapper2 is ReentrancyGuard {
IWrappedNative internal immutable wrappedNative;
ZapperExecutor internal immutable zapperExecutor;
constructor(
IWrappedNative wrappedNative_,
ZapperExecutor executor_
) {
wrappedNative = wrappedNative_;
zapperExecutor = executor_;
}
receive() external payable {}
function zap(ZapParams calldata params) external payable nonReentrant returns (ZapperOutput memory) {
uint256 startGas = gasleft();
return zapInner(params, balanceOf(params.tokenOut, params.recipient), startGas);
}
function zapDeploy(
ZapParams calldata params,
DeployFolioConfig calldata config,
bytes32 nonce
) external payable nonReentrant returns (ZapperOutput memory out) {
uint256 startGas = gasleft();
pullFundsFromSender(params.tokenIn, params.amountIn, address(zapperExecutor));
ExecuteDeployOutput memory deployOutput = zapperExecutor.executeDeploy(
params.commands,
params.state,
params.tokens,
config,
params.recipient,
nonce
);
out.amountOut = deployOutput.amountOut;
out.dust = deployOutput.dust;
require(out.amountOut > params.amountOut, "INSUFFICIENT_OUT");
out.gasUsed = startGas - gasleft();
}
function validateTokenOut(address tokenOut) private {
uint256 codeSizeTokenOut = 0;
assembly {
codeSizeTokenOut := extcodesize(tokenOut)
}
require(codeSizeTokenOut == 0, "RETRY");
}
function zapInner(ZapParams memory params, uint256 initialBalance, uint256 startGas) private returns (ZapperOutput memory out) {
require(params.amountIn != 0, "INVALID_INPUT_AMOUNT");
require(params.amountOut != 0, "INVALID_OUTPUT_AMOUNT");
pullFundsFromSender(params.tokenIn, params.amountIn, address(zapperExecutor));
out.dust = zapperExecutor.execute(
params.commands,
params.state,
params.tokens
).dust;
uint256 newBalance = balanceOf(params.tokenOut, params.recipient);
require(newBalance > initialBalance, "INVALID_NEW_BALANCE");
uint256 difference = newBalance - initialBalance;
require(difference >= params.amountOut, "INSUFFICIENT_OUT");
out.amountOut = difference;
out.gasUsed = startGas - gasleft();
}
function pullFundsFromSender(
address token,
uint256 amount,
address to
) private {
if (token != address(0)) {
SafeERC20.safeTransferFrom(IERC20(token), msg.sender, to, amount);
} else {
require(msg.value >= amount, "INSUFFICIENT_ETH");
wrappedNative.deposit{ value: amount }();
SafeERC20.safeTransfer(IERC20(address(wrappedNative)), to, amount);
}
}
function balanceOf(address token, address account) private view returns (uint256) {
if (token != address(0)) {
return IERC20(token).balanceOf(account);
} else {
return account.balance;
}
}
function translateOldStyleZap(ZapERC20Params calldata params) private returns (ZapperOutput memory) {
uint256 startGas = gasleft();
ZapParams memory zapParams = ZapParams({
tokenIn: address(params.tokenIn),
amountIn: params.amountIn,
commands: params.commands,
state: params.state,
tokens: params.tokens,
amountOut: params.amountOut,
tokenOut: address(params.tokenOut),
recipient: msg.sender
});
return zapInner(zapParams, balanceOf(address(params.tokenOut), msg.sender), startGas);
}
function zapERC20(ZapERC20Params calldata params) external nonReentrant returns (ZapperOutput memory) {
return translateOldStyleZap(params);
}
function zapETH(ZapERC20Params calldata params) external payable nonReentrant returns (ZapperOutput memory) {
return translateOldStyleZap(params);
}
function zapToETH(ZapERC20Params calldata params) external payable nonReentrant returns (ZapperOutput memory) {
return translateOldStyleZap(params);
}
}
文件 16 的 17:ZapperExecutor.sol
pragma solidity 0.8.17;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { VM } from "./weiroll/VM.sol";
import { PreventTampering } from "./PreventTampering.sol";
import { IFolio, IVotes, GovRoles, IFolioDeployer, IGovernanceDeployer } from "./IFolio.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
struct DeployFolioConfig {
address deployer;
IFolio.FolioBasicDetails basicDetails;
IFolio.FolioAdditionalDetails additionalDetails;
GovRoles govRoles;
bool isGoverned;
IVotes stToken;
address owner;
IGovernanceDeployer.GovParams ownerGovParams;
IGovernanceDeployer.GovParams tradingGovParams;
}
struct ExecuteOutput {
uint256[] dust;
}
struct ExecuteDeployOutput {
uint256[] dust;
uint256 amountOut;
}
contract ZapperExecutor is VM, PreventTampering {
receive() external payable {}
function add(
uint256 a,
uint256 b
) external pure returns (uint256) {
return a + b;
}
function sub(
uint256 a,
uint256 b
) external pure returns (uint256) {
return a - b;
}
function fpMul(
uint256 a,
uint256 b,
uint256 scale
) external pure returns (uint256) {
return (a * b) / scale;
}
function assertLarger(
uint256 a,
uint256 b
) external pure returns (bool) {
require(a > b, "!ASSERT_GT");
return true;
}
function assertEqual(
uint256 a,
uint256 b
) external pure returns (bool) {
require(a == b, "!ASSERT_EQ");
return true;
}
function execute(
bytes32[] calldata commands,
bytes[] memory state,
IERC20[] memory tokens
)
revertOnCodeHashChange
public
payable
returns (ExecuteOutput memory out)
{
_execute(commands, state);
out.dust = new uint256[](tokens.length);
for(uint256 i; i < tokens.length; i++) {
out.dust[i] = tokens[i].balanceOf(address(this));
}
}
function executeDeploy(
bytes32[] calldata commands,
bytes[] memory state,
IERC20[] memory tokens,
DeployFolioConfig memory config,
address recipient,
bytes32 nonce
) revertOnCodeHashChange public payable returns (ExecuteDeployOutput memory out) {
_execute(commands, state);
uint256 initialShares = type(uint256).max;
for (uint256 i = 0; i < config.basicDetails.assets.length; i++) {
uint256 balance = IERC20(config.basicDetails.assets[i]).balanceOf(address(this));
if (balance == 0) {
revert('ZERO BALANCE');
}
uint256 quantityPrShare = config.basicDetails.amounts[i];
if (quantityPrShare == 0) {
revert('ZERO QUANTITY');
}
uint256 shares = balance * 1e18 / quantityPrShare;
if (shares < initialShares) {
initialShares = shares;
}
SafeERC20.safeApprove(IERC20(config.basicDetails.assets[i]), address(config.deployer), 0);
SafeERC20.safeApprove(IERC20(config.basicDetails.assets[i]), address(config.deployer), type(uint256).max);
}
if (initialShares == type(uint256).max) {
revert('NO SHARES');
}
for (uint256 i = 0; i < config.basicDetails.assets.length; i++) {
config.basicDetails.amounts[i] = initialShares * config.basicDetails.amounts[i] / 1e18;
}
config.basicDetails.initialShares = initialShares;
if (config.isGoverned) {
(address folio, , , , ,) = IFolioDeployer(config.deployer).deployGovernedFolio(
config.stToken,
config.basicDetails,
config.additionalDetails,
config.ownerGovParams,
config.tradingGovParams,
config.govRoles,
nonce
);
out.amountOut = IERC20(folio).balanceOf(address(this));
SafeERC20.safeTransfer(IERC20(folio), recipient, out.amountOut);
} else {
(address folio, ) = IFolioDeployer(config.deployer).deployFolio(
config.basicDetails,
config.additionalDetails,
config.owner,
config.govRoles.existingTradeProposers,
config.govRoles.tradeLaunchers,
config.govRoles.vibesOfficers,
nonce
);
out.amountOut = IERC20(folio).balanceOf(address(this));
SafeERC20.safeTransfer(IERC20(folio), recipient, out.amountOut);
}
out.dust = new uint256[](tokens.length);
for(uint256 i; i < tokens.length; i++) {
out.dust[i] = tokens[i].balanceOf(address(this));
SafeERC20.safeTransfer(tokens[i], recipient, out.dust[i]);
}
}
function rawCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success, bytes memory out) {
require(msg.sender == address(this), "ZapperExecutor: Only callable by Zapper");
(success, out) = to.call{value: value}(data);
}
}
文件 17 的 17: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/Zapper2.sol": "Zapper2"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IWrappedNative","name":"wrappedNative_","type":"address"},{"internalType":"contract ZapperExecutor","name":"executor_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"commands","type":"bytes32[]"},{"internalType":"bytes[]","name":"state","type":"bytes[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct ZapParams","name":"params","type":"tuple"}],"name":"zap","outputs":[{"components":[{"internalType":"uint256[]","name":"dust","type":"uint256[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"internalType":"struct ZapperOutput","name":"","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"commands","type":"bytes32[]"},{"internalType":"bytes[]","name":"state","type":"bytes[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct ZapParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"deployer","type":"address"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"initialShares","type":"uint256"}],"internalType":"struct IFolio.FolioBasicDetails","name":"basicDetails","type":"tuple"},{"components":[{"internalType":"uint256","name":"auctionDelay","type":"uint256"},{"internalType":"uint256","name":"auctionLength","type":"uint256"},{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint96","name":"portion","type":"uint96"}],"internalType":"struct IFolio.FeeRecipient[]","name":"feeRecipients","type":"tuple[]"},{"internalType":"uint256","name":"tvlFee","type":"uint256"},{"internalType":"uint256","name":"mintFee","type":"uint256"},{"internalType":"string","name":"mandate","type":"string"}],"internalType":"struct IFolio.FolioAdditionalDetails","name":"additionalDetails","type":"tuple"},{"components":[{"internalType":"address[]","name":"existingTradeProposers","type":"address[]"},{"internalType":"address[]","name":"tradeLaunchers","type":"address[]"},{"internalType":"address[]","name":"vibesOfficers","type":"address[]"}],"internalType":"struct GovRoles","name":"govRoles","type":"tuple"},{"internalType":"bool","name":"isGoverned","type":"bool"},{"internalType":"contract IVotes","name":"stToken","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"uint48","name":"votingDelay","type":"uint48"},{"internalType":"uint32","name":"votingPeriod","type":"uint32"},{"internalType":"uint256","name":"proposalThreshold","type":"uint256"},{"internalType":"uint256","name":"quorumPercent","type":"uint256"},{"internalType":"uint256","name":"timelockDelay","type":"uint256"},{"internalType":"address[]","name":"guardians","type":"address[]"}],"internalType":"struct IGovernanceDeployer.GovParams","name":"ownerGovParams","type":"tuple"},{"components":[{"internalType":"uint48","name":"votingDelay","type":"uint48"},{"internalType":"uint32","name":"votingPeriod","type":"uint32"},{"internalType":"uint256","name":"proposalThreshold","type":"uint256"},{"internalType":"uint256","name":"quorumPercent","type":"uint256"},{"internalType":"uint256","name":"timelockDelay","type":"uint256"},{"internalType":"address[]","name":"guardians","type":"address[]"}],"internalType":"struct IGovernanceDeployer.GovParams","name":"tradingGovParams","type":"tuple"}],"internalType":"struct DeployFolioConfig","name":"config","type":"tuple"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"zapDeploy","outputs":[{"components":[{"internalType":"uint256[]","name":"dust","type":"uint256[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"internalType":"struct ZapperOutput","name":"out","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"commands","type":"bytes32[]"},{"internalType":"bytes[]","name":"state","type":"bytes[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"}],"internalType":"struct ZapERC20Params","name":"params","type":"tuple"}],"name":"zapERC20","outputs":[{"components":[{"internalType":"uint256[]","name":"dust","type":"uint256[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"internalType":"struct ZapperOutput","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"commands","type":"bytes32[]"},{"internalType":"bytes[]","name":"state","type":"bytes[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"}],"internalType":"struct ZapERC20Params","name":"params","type":"tuple"}],"name":"zapETH","outputs":[{"components":[{"internalType":"uint256[]","name":"dust","type":"uint256[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"internalType":"struct ZapperOutput","name":"","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"commands","type":"bytes32[]"},{"internalType":"bytes[]","name":"state","type":"bytes[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"}],"internalType":"struct ZapERC20Params","name":"params","type":"tuple"}],"name":"zapToETH","outputs":[{"components":[{"internalType":"uint256[]","name":"dust","type":"uint256[]"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"internalType":"struct ZapperOutput","name":"","type":"tuple"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]