文件 1 的 1:MainnetFlat.sol
pragma solidity >=0.6.2 >=0.8.25 ^0.8.17 ^0.8.25;
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 name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
interface IEIP712 {
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
abstract contract AbstractContext {
function _msgSender() internal view virtual returns (address);
function _msgData() internal view virtual returns (bytes calldata);
function _isForwarded() internal view virtual returns (bool);
}
abstract contract Context is AbstractContext {
function _msgSender() internal view virtual override returns (address) {
return msg.sender;
}
function _msgData() internal view virtual override returns (bytes calldata) {
return msg.data;
}
function _isForwarded() internal view virtual override returns (bool) {
return false;
}
}
interface IERC721Owner {
function ownerOf(uint256) external view returns (address);
}
interface IAllowanceHolder {
function exec(address operator, address token, uint256 amount, address payable target, bytes calldata data)
external
payable
returns (bytes memory result);
function transferFrom(address token, address owner, address recipient, uint256 amount) external returns (bool);
}
address constant pancakeSwapV3Factory = 0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9;
bytes32 constant pancakeSwapV3InitHash = 0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2;
uint8 constant pancakeSwapV3ForkId = 1;
interface IPancakeSwapV3Callback {
function pancakeV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;
}
address constant solidlyV3Factory = 0x70Fe4a44EA505cFa3A57b95cF2862D4fd5F0f687;
bytes32 constant solidlyV3InitHash = 0xe9b68c5f77858eecac2e651646e208175e9b1359d68d0e14fc69f8c54e5010bf;
uint8 constant solidlyV3ForkId = 3;
interface ISolidlyV3Callback {
function solidlyV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;
}
address constant sushiswapV3MainnetFactory = 0xbACEB8eC6b9355Dfc0269C18bac9d6E2Bdc29C4F;
address constant sushiswapV3Factory = 0xc35DADB65012eC5796536bD9864eD8773aBc74C4;
address constant sushiswapV3ArbitrumFactory = 0x1af415a1EbA07a4986a52B6f2e7dE7003D82231e;
address constant sushiswapV3OptimismFactory = 0x9c6522117e2ed1fE5bdb72bb0eD5E3f2bdE7DBe0;
address constant sushiswapV3PolygonFactory = 0x917933899c6a5F8E37F31E19f92CdBFF7e8FF0e2;
address constant sushiswapV3ScrollFactory = 0x46B3fDF7b5CDe91Ac049936bF0bDb12c5d22202e;
uint8 constant sushiswapV3ForkId = 2;
address constant uniswapV3MainnetFactory = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
address constant uniswapV3SepoliaFactory = 0x0227628f3F023bb0B980b67D528571c95c6DaC1c;
address constant uniswapV3BaseFactory = 0x33128a8fC17869897dcE68Ed026d694621f6FDfD;
address constant uniswapV3BnbFactory = 0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7;
address constant uniswapV3AvalancheFactory = 0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD;
address constant uniswapV3BlastFactory = 0x792edAdE80af5fC680d96a2eD80A44247D2Cf6Fd;
address constant uniswapV3ScrollFactory = 0x70C62C8b8e801124A4Aa81ce07b637A3e83cb919;
bytes32 constant uniswapV3InitHash = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;
uint8 constant uniswapV3ForkId = 0;
interface IUniswapV3Callback {
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;
}
abstract contract FreeMemory {
modifier DANGEROUS_freeMemory() {
uint256 freeMemPtr;
assembly ("memory-safe") {
freeMemPtr := mload(0x40)
}
_;
assembly ("memory-safe") {
mstore(0x40, freeMemPtr)
}
}
}
library Panic {
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
uint8 internal constant GENERIC = 0x00;
uint8 internal constant ASSERT_FAIL = 0x01;
uint8 internal constant ARITHMETIC_OVERFLOW = 0x11;
uint8 internal constant DIVISION_BY_ZERO = 0x12;
uint8 internal constant ENUM_CAST = 0x21;
uint8 internal constant CORRUPT_STORAGE_ARRAY = 0x22;
uint8 internal constant POP_EMPTY_ARRAY = 0x31;
uint8 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
uint8 internal constant OUT_OF_MEMORY = 0x41;
uint8 internal constant ZERO_FUNCTION_POINTER = 0x51;
}
library Revert {
function _revert(bytes memory reason) internal pure {
assembly ("memory-safe") {
revert(add(reason, 0x20), mload(reason))
}
}
function maybeRevert(bool success, bytes memory reason) internal pure {
if (!success) {
_revert(reason);
}
}
}
library UnsafeMath {
function unsafeInc(uint256 x) internal pure returns (uint256) {
unchecked {
return x + 1;
}
}
function unsafeInc(int256 x) internal pure returns (int256) {
unchecked {
return x + 1;
}
}
function unsafeNeg(int256 x) internal pure returns (int256) {
unchecked {
return -x;
}
}
function unsafeDiv(uint256 numerator, uint256 denominator) internal pure returns (uint256 quotient) {
assembly ("memory-safe") {
quotient := div(numerator, denominator)
}
}
function unsafeDiv(int256 numerator, int256 denominator) internal pure returns (int256 quotient) {
assembly ("memory-safe") {
quotient := sdiv(numerator, denominator)
}
}
function unsafeMod(uint256 numerator, uint256 denominator) internal pure returns (uint256 remainder) {
assembly ("memory-safe") {
remainder := mod(numerator, denominator)
}
}
function unsafeMod(int256 numerator, int256 denominator) internal pure returns (int256 remainder) {
assembly ("memory-safe") {
remainder := smod(numerator, denominator)
}
}
function unsafeMulMod(uint256 a, uint256 b, uint256 m) internal pure returns (uint256 r) {
assembly ("memory-safe") {
r := mulmod(a, b, m)
}
}
function unsafeAddMod(uint256 a, uint256 b, uint256 m) internal pure returns (uint256 r) {
assembly ("memory-safe") {
r := addmod(a, b, m)
}
}
}
interface ISignatureTransfer is IEIP712 {
error InvalidAmount(uint256 maxAmount);
error LengthMismatch();
event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);
struct TokenPermissions {
address token;
uint256 amount;
}
struct PermitTransferFrom {
TokenPermissions permitted;
uint256 nonce;
uint256 deadline;
}
struct SignatureTransferDetails {
address to;
uint256 requestedAmount;
}
struct PermitBatchTransferFrom {
TokenPermissions[] permitted;
uint256 nonce;
uint256 deadline;
}
function nonceBitmap(address, uint256) external view returns (uint256);
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
function permitWitnessTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
function permitTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes calldata signature
) external;
function permitWitnessTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;
}
error InvalidOffset();
error ConfusedDeputy();
error InvalidTarget();
error InvalidSender();
error ForwarderNotAllowed();
error InvalidSignatureLen();
error TooMuchSlippage(IERC20 token, uint256 expected, uint256 actual);
error ActionInvalid(uint256 i, bytes4 action, bytes data);
error UnknownForkId(uint8 forkId);
error SignatureExpired(uint256 deadline);
error ReentrantCallback(uint256 callbackInt);
error CallbackNotSpent(uint256 callbackInt);
error ReentrantMetatransaction(bytes32 oldWitness);
error ReentrantPayer(address oldPayer);
error WitnessNotSpent(bytes32 oldWitness);
error PayerSpent();
library SafeTransferLib {
uint32 private constant _TRANSFER_FROM_FAILED_SELECTOR = 0x7939f424;
uint32 private constant _TRANSFER_FAILED_SELECTOR = 0x90b8ec18;
uint32 private constant _APPROVE_FAILED_SELECTOR = 0x3e3f8f73;
function safeTransferETH(address payable to, uint256 amount) internal {
assembly ("memory-safe") {
if iszero(call(gas(), to, amount, 0, 0, 0, 0)) {
let freeMemoryPointer := mload(0x40)
returndatacopy(freeMemoryPointer, 0, returndatasize())
revert(freeMemoryPointer, returndatasize())
}
}
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 amount) internal {
assembly ("memory-safe") {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 68), amount)
if iszero(call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)) {
returndatacopy(freeMemoryPointer, 0, returndatasize())
revert(freeMemoryPointer, returndatasize())
}
if iszero(or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize()))) {
mstore(0, _TRANSFER_FROM_FAILED_SELECTOR)
revert(0x1c, 0x04)
}
}
}
function safeTransfer(IERC20 token, address to, uint256 amount) internal {
assembly ("memory-safe") {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), amount)
if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)) {
returndatacopy(freeMemoryPointer, 0, returndatasize())
revert(freeMemoryPointer, returndatasize())
}
if iszero(or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize()))) {
mstore(0, _TRANSFER_FAILED_SELECTOR)
revert(0x1c, 0x04)
}
}
}
function safeApprove(IERC20 token, address to, uint256 amount) internal {
assembly ("memory-safe") {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), amount)
if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)) {
returndatacopy(freeMemoryPointer, 0, returndatasize())
revert(freeMemoryPointer, returndatasize())
}
if iszero(or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize()))) {
mstore(0, _APPROVE_FAILED_SELECTOR)
revert(0x1c, 0x04)
}
}
}
function safeApproveIfBelow(IERC20 token, address spender, uint256 amount) internal {
uint256 allowance = token.allowance(address(this), spender);
if (allowance < amount) {
if (allowance != 0) {
safeApprove(token, spender, 0);
}
safeApprove(token, spender, type(uint256).max);
}
}
}
interface ISettlerActions {
function TRANSFER_FROM(address recipient, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig)
external;
function METATXN_TRANSFER_FROM(address recipient, ISignatureTransfer.PermitTransferFrom memory permit) external;
function RFQ_VIP(
address recipient,
ISignatureTransfer.PermitTransferFrom memory makerPermit,
address maker,
bytes memory makerSig,
ISignatureTransfer.PermitTransferFrom memory takerPermit,
bytes memory takerSig
) external;
function METATXN_RFQ_VIP(
address recipient,
ISignatureTransfer.PermitTransferFrom memory makerPermit,
address maker,
bytes memory makerSig,
ISignatureTransfer.PermitTransferFrom memory takerPermit
) external;
function RFQ(
address recipient,
ISignatureTransfer.PermitTransferFrom memory permit,
address maker,
bytes memory makerSig,
address takerToken,
uint256 maxTakerAmount
) external;
function UNISWAPV3(address recipient, uint256 bps, bytes memory path, uint256 amountOutMin) external;
function UNISWAPV3_VIP(
address recipient,
bytes memory path,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
uint256 amountOutMin
) external;
function MAKERPSM(address recipient, address gemToken, uint256 bps, address psm, bool buyGem) external;
function CURVE_TRICRYPTO_VIP(
address recipient,
uint80 poolInfo,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
uint256 minBuyAmount
) external;
function METATXN_CURVE_TRICRYPTO_VIP(
address recipient,
uint80 poolInfo,
ISignatureTransfer.PermitTransferFrom memory permit,
uint256 minBuyAmount
) external;
function DODOV1(address sellToken, uint256 bps, address pool, bool quoteForBase, uint256 minBuyAmount) external;
function DODOV2(
address recipient,
address sellToken,
uint256 bps,
address pool,
bool quoteForBase,
uint256 minBuyAmount
) external;
function VELODROME(address recipient, uint256 bps, address pool, uint24 swapInfo, uint256 minBuyAmount) external;
function METATXN_UNISWAPV3_VIP(
address recipient,
bytes memory path,
ISignatureTransfer.PermitTransferFrom memory permit,
uint256 amountOutMin
) external;
function MAVERICKV2(
address recipient,
address sellToken,
uint256 bps,
address pool,
bool tokenAIn,
uint256 minBuyAmount
) external;
function MAVERICKV2_VIP(
address recipient,
bytes32 salt,
bool tokenAIn,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
uint256 minBuyAmount
) external;
function METATXN_MAVERICKV2_VIP(
address recipient,
bytes32 salt,
bool tokenAIn,
ISignatureTransfer.PermitTransferFrom memory permit,
uint256 minBuyAmount
) external;
function UNISWAPV2(
address recipient,
address sellToken,
uint256 bps,
address pool,
uint24 swapInfo,
uint256 amountOutMin
) external;
function POSITIVE_SLIPPAGE(address recipient, address token, uint256 expectedAmount) external;
function BASIC(address sellToken, uint256 bps, address pool, uint256 offset, bytes calldata data) external;
}
abstract contract AllowanceHolderContext is Context {
IAllowanceHolder internal constant _ALLOWANCE_HOLDER = IAllowanceHolder(0x0000000000001fF3684f28c67538d4D072C22734);
function _isForwarded() internal view virtual override returns (bool) {
return super._isForwarded() || super._msgSender() == address(_ALLOWANCE_HOLDER);
}
function _msgSender() internal view virtual override returns (address sender) {
sender = super._msgSender();
if (sender == address(_ALLOWANCE_HOLDER)) {
assembly ("memory-safe") {
sender := shr(0x60, calldataload(sub(calldatasize(), 0x14)))
}
}
}
function balanceOf(address) external pure {
assembly ("memory-safe") {
mstore8(0x00, 0x00)
return(0x00, 0x01)
}
}
}
library AddressDerivation {
using UnsafeMath for uint256;
uint256 internal constant _SECP256K1_P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
uint256 internal constant _SECP256K1_N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
uint256 internal constant SECP256K1_GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
uint256 internal constant SECP256K1_GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;
error InvalidCurve(uint256 x, uint256 y);
function deriveEOA(uint256 x, uint256 y, uint256 k) internal pure returns (address) {
if (k == 0) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
if (k >= _SECP256K1_N || x >= _SECP256K1_P || y >= _SECP256K1_P) {
Panic.panic(Panic.ARITHMETIC_OVERFLOW);
}
if (
x == 0
|| y.unsafeMulMod(y, _SECP256K1_P)
!= x.unsafeMulMod(x, _SECP256K1_P).unsafeMulMod(x, _SECP256K1_P).unsafeAddMod(7, _SECP256K1_P)
) {
revert InvalidCurve(x, y);
}
unchecked {
return ecrecover(
bytes32(0), uint8(27 + (y & 1)), bytes32(x), bytes32(UnsafeMath.unsafeMulMod(x, k, _SECP256K1_N))
);
}
}
function deriveContract(address deployer, uint64 nonce) internal pure returns (address result) {
if (nonce == 0) {
assembly ("memory-safe") {
mstore(
0x00,
or(
0xd694000000000000000000000000000000000000000080,
shl(8, and(0xffffffffffffffffffffffffffffffffffffffff, deployer))
)
)
result := keccak256(0x09, 0x17)
}
} else if (nonce < 0x80) {
assembly ("memory-safe") {
mstore(0x14, deployer)
mstore(0x00, 0xd694)
mstore8(0x34, nonce)
result := keccak256(0x1e, 0x17)
}
} else {
uint256 nonceLength = 8;
unchecked {
if ((uint256(nonce) >> 32) != 0) {
nonceLength += 32;
if (nonce == type(uint64).max) {
Panic.panic(Panic.ARITHMETIC_OVERFLOW);
}
}
if ((uint256(nonce) >> 8) >= (1 << nonceLength)) {
nonceLength += 16;
}
if (uint256(nonce) >= (1 << nonceLength)) {
nonceLength += 8;
}
if ((uint256(nonce) << 8) >= (1 << nonceLength)) {
nonceLength += 8;
}
nonceLength >>= 3;
}
assembly ("memory-safe") {
mstore(nonceLength, nonce)
mstore8(0x20, add(0x7f, nonceLength))
mstore(0x00, deployer)
mstore8(0x0a, add(0xd5, nonceLength))
mstore8(0x0b, 0x94)
result := keccak256(0x0a, add(0x16, nonceLength))
}
}
}
function deriveDeterministicContract(address deployer, bytes32 salt, bytes32 initHash)
internal
pure
returns (address result)
{
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, deployer)
mstore8(add(ptr, 0x0b), 0xff)
mstore(add(ptr, 0x20), salt)
mstore(add(ptr, 0x40), initHash)
result := keccak256(add(ptr, 0x0b), 0x55)
}
}
}
library FullMath {
using UnsafeMath for uint256;
function _mulDivSetup(uint256 a, uint256 b, uint256 denominator)
private
pure
returns (uint256 prod0, uint256 prod1, uint256 remainder)
{
assembly ("memory-safe") {
{
let mm := mulmod(a, b, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
remainder := mulmod(a, b, denominator)
}
}
function _mulDivInvert(uint256 prod0, uint256 prod1, uint256 denominator, uint256 remainder)
private
pure
returns (uint256)
{
uint256 inv;
assembly ("memory-safe") {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
{
let twos := and(sub(0, denominator), denominator)
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
prod0 := or(prod0, mul(prod1, twos))
}
inv := xor(mul(3, denominator), 2)
inv := mul(inv, sub(2, mul(denominator, inv)))
inv := mul(inv, sub(2, mul(denominator, inv)))
inv := mul(inv, sub(2, mul(denominator, inv)))
inv := mul(inv, sub(2, mul(denominator, inv)))
inv := mul(inv, sub(2, mul(denominator, inv)))
inv := mul(inv, sub(2, mul(denominator, inv)))
}
unchecked {
return prod0 * inv;
}
}
function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) {
(uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator);
if (denominator <= prod1) {
Panic.panic(denominator == 0 ? Panic.DIVISION_BY_ZERO : Panic.ARITHMETIC_OVERFLOW);
}
if (prod1 == 0) {
return prod0.unsafeDiv(denominator);
}
return _mulDivInvert(prod0, prod1, denominator, remainder);
}
function unsafeMulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) {
(uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator);
if (prod1 == 0) {
return prod0.unsafeDiv(denominator);
}
return _mulDivInvert(prod0, prod1, denominator, remainder);
}
}
interface IPSM {
function tout() external view returns (uint256);
function gemJoin() external view returns (address);
function sellGem(address usr, uint256 gemAmt) external;
function buyGem(address usr, uint256 gemAmt) external;
}
abstract contract MakerPSM {
using UnsafeMath for uint256;
using SafeTransferLib for IERC20;
uint256 internal constant WAD = 10 ** 18;
IERC20 internal constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
constructor() {
assert(block.chainid == 1 || block.chainid == 31337);
}
function sellToMakerPsm(address recipient, IERC20 gemToken, uint256 bps, IPSM psm, bool buyGem) internal {
if (buyGem) {
uint256 sellAmount = (DAI.balanceOf(address(this)) * bps).unsafeDiv(10_000);
unchecked {
uint256 feeDivisor = psm.tout() + WAD;
uint256 buyAmount = (sellAmount * 10 ** uint256(gemToken.decimals())).unsafeDiv(feeDivisor);
DAI.safeApproveIfBelow(address(psm), sellAmount);
psm.buyGem(recipient, buyAmount);
}
} else {
uint256 sellAmount = (gemToken.balanceOf(address(this)) * bps).unsafeDiv(10_000);
gemToken.safeApproveIfBelow(psm.gemJoin(), sellAmount);
psm.sellGem(recipient, sellAmount);
}
}
}
abstract contract Permit2PaymentAbstract is AbstractContext {
string internal constant TOKEN_PERMISSIONS_TYPE = "TokenPermissions(address token,uint256 amount)";
function _isRestrictedTarget(address) internal view virtual returns (bool);
function _operator() internal view virtual returns (address);
function _permitToTransferDetails(ISignatureTransfer.PermitTransferFrom memory permit, address recipient)
internal
pure
virtual
returns (ISignatureTransfer.SignatureTransferDetails memory transferDetails, address token, uint256 amount);
function _transferFromIKnowWhatImDoing(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails memory transferDetails,
address from,
bytes32 witness,
string memory witnessTypeString,
bytes memory sig,
bool isForwarded
) internal virtual;
function _transferFromIKnowWhatImDoing(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails memory transferDetails,
address from,
bytes32 witness,
string memory witnessTypeString,
bytes memory sig
) internal virtual;
function _transferFrom(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails memory transferDetails,
bytes memory sig,
bool isForwarded
) internal virtual;
function _transferFrom(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails memory transferDetails,
bytes memory sig
) internal virtual;
function _setOperatorAndCall(
address target,
bytes memory data,
uint32 selector,
function (bytes calldata) internal returns (bytes memory) callback
) internal virtual returns (bytes memory);
modifier metaTx(address msgSender, bytes32 witness) virtual;
modifier takerSubmitted() virtual;
function _allowanceHolderTransferFrom(address token, address owner, address recipient, uint256 amount)
internal
virtual;
}
abstract contract SettlerAbstract is Permit2PaymentAbstract {
string internal constant SLIPPAGE_AND_ACTIONS_TYPE =
"SlippageAndActions(address recipient,address buyToken,uint256 minAmountOut,bytes[] actions)";
bytes32 internal constant SLIPPAGE_AND_ACTIONS_TYPEHASH =
0x615e8d716cef7295e75dd3f1f10d679914ad6d7759e8e9459f0109ef75241701;
constructor() {
assert(SLIPPAGE_AND_ACTIONS_TYPEHASH == keccak256(bytes(SLIPPAGE_AND_ACTIONS_TYPE)));
}
function _hasMetaTxn() internal pure virtual returns (bool);
function _dispatch(uint256 i, bytes4 action, bytes calldata data) internal virtual returns (bool);
}
interface IUniV2Pair {
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112, uint112, uint32);
function swap(uint256, uint256, address, bytes calldata) external;
}
abstract contract UniswapV2 {
using UnsafeMath for uint256;
uint32 private constant UNI_PAIR_RESERVES_SELECTOR = 0x0902f1ac;
uint32 private constant UNI_PAIR_SWAP_SELECTOR = 0x022c0d9f;
uint32 private constant ERC20_TRANSFER_SELECTOR = 0xa9059cbb;
uint32 private constant ERC20_BALANCEOF_SELECTOR = 0x70a08231;
function sellToUniswapV2(
address recipient,
address sellToken,
uint256 bps,
address pool,
uint24 swapInfo,
uint256 minBuyAmount
) internal {
bool zeroForOne = (swapInfo & 1) == 1;
bool sellTokenHasFee = (swapInfo & 2) >> 1 == 1;
uint256 feeBps = swapInfo >> 8;
uint256 sellAmount;
uint256 buyAmount;
if (bps != 0) {
unchecked {
sellAmount = (IERC20(sellToken).balanceOf(address(this)) * bps).unsafeDiv(10_000);
}
}
assembly ("memory-safe") {
let ptr := mload(0x40)
if sellAmount {
mstore(ptr, ERC20_TRANSFER_SELECTOR)
mstore(add(ptr, 0x20), pool)
mstore(add(ptr, 0x40), sellAmount)
if iszero(call(gas(), sellToken, 0, add(ptr, 0x1c), 0x44, 0x00, 0x20)) { bubbleRevert(ptr) }
if iszero(or(iszero(returndatasize()), and(iszero(lt(returndatasize(), 0x20)), eq(mload(0x00), 1)))) {
revert(0, 0)
}
}
let sellReserve
let buyReserve
mstore(0x00, UNI_PAIR_RESERVES_SELECTOR)
if iszero(staticcall(gas(), pool, 0x1c, 0x04, 0x00, 0x40)) { bubbleRevert(ptr) }
if lt(returndatasize(), 0x40) { revert(0, 0) }
{
let r := shl(5, zeroForOne)
buyReserve := mload(r)
sellReserve := mload(xor(0x20, r))
}
if or(iszero(sellAmount), sellTokenHasFee) {
mstore(0x00, ERC20_BALANCEOF_SELECTOR)
mstore(0x20, and(0xffffffffffffffffffffffffffffffffffffffff, pool))
if iszero(staticcall(gas(), sellToken, 0x1c, 0x24, 0x00, 0x20)) { bubbleRevert(ptr) }
if lt(returndatasize(), 0x20) { revert(0, 0) }
let bal := mload(0x00)
if lt(bal, sellReserve) {
mstore(0x00, 0x4e487b71)
mstore(0x20, 0x11)
revert(0x1c, 0x24)
}
sellAmount := sub(bal, sellReserve)
}
let sellAmountWithFee := mul(sellAmount, sub(10000, feeBps))
buyAmount := div(mul(sellAmountWithFee, buyReserve), add(sellAmountWithFee, mul(sellReserve, 10000)))
let swapCalldata := add(ptr, 0x1c)
mstore(ptr, UNI_PAIR_SWAP_SELECTOR)
mstore(add(ptr, 0x80), 0x80)
mstore(add(ptr, 0xa0), 0)
{
let offset := add(0x04, shl(5, zeroForOne))
mstore(add(swapCalldata, offset), buyAmount)
mstore(add(swapCalldata, xor(0x20, offset)), 0)
}
mstore(add(swapCalldata, 0x44), and(0xffffffffffffffffffffffffffffffffffffffff, recipient))
if iszero(call(gas(), pool, 0, swapCalldata, 0xa4, 0, 0)) { bubbleRevert(swapCalldata) }
function bubbleRevert(p) {
returndatacopy(p, 0, returndatasize())
revert(p, returndatasize())
}
}
if (buyAmount < minBuyAmount) {
revert TooMuchSlippage(
IERC20(zeroForOne ? IUniV2Pair(pool).token1() : IUniV2Pair(pool).token0()), minBuyAmount, buyAmount
);
}
}
}
interface IVelodromePair {
function metadata()
external
view
returns (
uint256 basis0,
uint256 basis1,
uint256 reserve0,
uint256 reserve1,
bool stable,
IERC20 token0,
IERC20 token1
);
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
}
abstract contract Velodrome {
using UnsafeMath for uint256;
using SafeTransferLib for IERC20;
uint256 private constant _BASIS = 1 ether;
function _k(uint256 x, uint256 y) private pure returns (uint256) {
unchecked {
return _k(x, y, x * x / _BASIS);
}
}
function _k(uint256 x, uint256 y, uint256 x_squared) private pure returns (uint256) {
unchecked {
return _k(x, y, x_squared, y * y / _BASIS);
}
}
function _k(uint256 x, uint256 y, uint256 x_squared, uint256 y_squared) private pure returns (uint256) {
unchecked {
return x * y / _BASIS * (x_squared + y_squared) / _BASIS;
}
}
function _d(uint256 y, uint256 three_x0, uint256 x0_cubed) private pure returns (uint256) {
unchecked {
return _d(y, three_x0, x0_cubed, y * y / _BASIS);
}
}
function _d(uint256 y, uint256 three_x0, uint256 x0_cubed, uint256 y_squared) private pure returns (uint256) {
unchecked {
return y_squared * three_x0 / _BASIS + x0_cubed;
}
}
error NotConverged();
function _get_y(uint256 x0, uint256 xy, uint256 y) private pure returns (uint256) {
unchecked {
uint256 three_x0 = 3 * x0;
uint256 x0_squared = x0 * x0 / _BASIS;
uint256 x0_cubed = x0_squared * x0 / _BASIS;
for (uint256 i; i < 255; i++) {
uint256 y_squared = y * y / _BASIS;
uint256 k = _k(x0, y, x0_squared, y_squared);
if (k < xy) {
uint256 dy = ((xy - k) * _BASIS).unsafeDiv(_d(y, three_x0, x0_cubed, y_squared));
if (dy == 0) {
if (k == xy) {
return y;
}
if (_k(x0, y + 1, x0_squared) > xy) {
return y + 1;
}
dy = 1;
}
y += dy;
} else {
uint256 dy = ((k - xy) * _BASIS).unsafeDiv(_d(y, three_x0, x0_cubed, y_squared));
if (dy == 0) {
if (k == xy || _k(x0, y - 1, x0_squared) < xy) {
return y;
}
dy = 1;
}
y -= dy;
}
}
revert NotConverged();
}
}
function sellToVelodrome(address recipient, uint256 bps, IVelodromePair pair, uint24 swapInfo, uint256 minAmountOut)
internal
{
bool zeroForOne = (swapInfo & 1) == 1;
bool sellTokenHasFee = (swapInfo & 2) >> 1 == 1;
uint256 feeBps = swapInfo >> 8;
(
uint256 sellBasis,
uint256 buyBasis,
uint256 sellReserve,
uint256 buyReserve,
bool stable,
IERC20 sellToken,
IERC20 buyToken
) = pair.metadata();
assert(stable);
if (!zeroForOne) {
(sellBasis, buyBasis, sellReserve, buyReserve, sellToken, buyToken) =
(buyBasis, sellBasis, buyReserve, sellReserve, buyToken, sellToken);
}
uint256 buyAmount;
unchecked {
uint256 sellAmount;
if (bps != 0) {
sellAmount = sellToken.balanceOf(address(this)) * bps / 10_000;
}
if (sellAmount != 0) {
sellToken.safeTransfer(address(pair), sellAmount);
}
if (sellAmount == 0 || sellTokenHasFee) {
sellAmount = sellToken.balanceOf(address(pair)) - sellReserve;
}
sellAmount -= sellAmount * feeBps / 10_000;
sellReserve = (sellReserve * _BASIS).unsafeDiv(sellBasis);
buyReserve = (buyReserve * _BASIS).unsafeDiv(buyBasis);
sellAmount = (sellAmount * _BASIS).unsafeDiv(sellBasis);
buyAmount = buyReserve - _get_y(sellAmount + sellReserve, _k(sellReserve, buyReserve), buyReserve);
buyAmount = buyAmount * buyBasis / _BASIS;
}
if (buyAmount < minAmountOut) {
revert TooMuchSlippage(sellToken, minAmountOut, buyAmount);
}
{
(uint256 buyAmount0, uint256 buyAmount1) = zeroForOne ? (uint256(0), buyAmount) : (buyAmount, uint256(0));
pair.swap(buyAmount0, buyAmount1, recipient, new bytes(0));
}
}
}
abstract contract RfqOrderSettlement is SettlerAbstract {
using SafeTransferLib for IERC20;
using FullMath for uint256;
struct Consideration {
address token;
uint256 amount;
address counterparty;
bool partialFillAllowed;
}
string internal constant CONSIDERATION_TYPE =
"Consideration(address token,uint256 amount,address counterparty,bool partialFillAllowed)";
string internal constant CONSIDERATION_WITNESS =
string(abi.encodePacked("Consideration consideration)", CONSIDERATION_TYPE, TOKEN_PERMISSIONS_TYPE));
bytes32 internal constant CONSIDERATION_TYPEHASH =
0x7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa;
string internal constant RFQ_ORDER_TYPE =
"RfqOrder(Consideration makerConsideration,Consideration takerConsideration)";
string internal constant RFQ_ORDER_TYPE_RECURSIVE = string(abi.encodePacked(RFQ_ORDER_TYPE, CONSIDERATION_TYPE));
bytes32 internal constant RFQ_ORDER_TYPEHASH = 0x49fa719b76f0f6b7e76be94b56c26671a548e1c712d5b13dc2874f70a7598276;
function _hashConsideration(Consideration memory consideration) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let ptr := sub(consideration, 0x20)
let oldValue := mload(ptr)
mstore(ptr, CONSIDERATION_TYPEHASH)
result := keccak256(ptr, 0xa0)
mstore(ptr, oldValue)
}
}
function _logRfqOrder(bytes32 makerConsiderationHash, bytes32 takerConsiderationHash, uint128 makerFilledAmount)
private
{
assembly ("memory-safe") {
mstore(0x00, RFQ_ORDER_TYPEHASH)
mstore(0x20, makerConsiderationHash)
let ptr := mload(0x40)
mstore(0x40, takerConsiderationHash)
let orderHash := keccak256(0x00, 0x60)
mstore(0x40, ptr)
mstore(0x10, makerFilledAmount)
mstore(0x00, orderHash)
log0(0x00, 0x30)
}
}
constructor() {
assert(CONSIDERATION_TYPEHASH == keccak256(bytes(CONSIDERATION_TYPE)));
assert(RFQ_ORDER_TYPEHASH == keccak256(bytes(RFQ_ORDER_TYPE_RECURSIVE)));
}
function fillRfqOrderVIP(
address recipient,
ISignatureTransfer.PermitTransferFrom memory makerPermit,
address maker,
bytes memory makerSig,
ISignatureTransfer.PermitTransferFrom memory takerPermit,
bytes memory takerSig
) internal {
(
ISignatureTransfer.SignatureTransferDetails memory makerTransferDetails,
address makerToken,
uint256 makerAmount
) = _permitToTransferDetails(makerPermit, recipient);
(
ISignatureTransfer.SignatureTransferDetails memory takerTransferDetails,
address takerToken,
uint256 takerAmount
) = _permitToTransferDetails(takerPermit, maker);
bytes32 witness = _hashConsideration(
Consideration({
token: takerToken,
amount: takerAmount,
counterparty: _msgSender(),
partialFillAllowed: false
})
);
_transferFrom(takerPermit, takerTransferDetails, takerSig);
_transferFromIKnowWhatImDoing(
makerPermit, makerTransferDetails, maker, witness, CONSIDERATION_WITNESS, makerSig, false
);
_logRfqOrder(
witness,
_hashConsideration(
Consideration({token: makerToken, amount: makerAmount, counterparty: maker, partialFillAllowed: false})
),
uint128(makerAmount)
);
}
function fillRfqOrderSelfFunded(
address recipient,
ISignatureTransfer.PermitTransferFrom memory permit,
address maker,
bytes memory makerSig,
IERC20 takerToken,
uint256 maxTakerAmount
) internal {
(ISignatureTransfer.SignatureTransferDetails memory transferDetails, address makerToken, uint256 makerAmount) =
_permitToTransferDetails(permit, recipient);
bytes32 takerWitness = _hashConsideration(
Consideration({token: makerToken, amount: makerAmount, counterparty: maker, partialFillAllowed: true})
);
bytes32 makerWitness = _hashConsideration(
Consideration({
token: address(takerToken),
amount: maxTakerAmount,
counterparty: _msgSender(),
partialFillAllowed: true
})
);
uint256 takerAmount = takerToken.balanceOf(address(this));
if (takerAmount > maxTakerAmount) {
takerAmount = maxTakerAmount;
}
transferDetails.requestedAmount = makerAmount = makerAmount.unsafeMulDiv(takerAmount, maxTakerAmount);
takerToken.safeTransfer(maker, takerAmount);
_transferFromIKnowWhatImDoing(
permit, transferDetails, maker, makerWitness, CONSIDERATION_WITNESS, makerSig, false
);
_logRfqOrder(makerWitness, takerWitness, uint128(makerAmount));
}
}
interface ICurveTricrypto {
function exchange_extended(
uint256 sellIndex,
uint256 buyIndex,
uint256 sellAmount,
uint256 minBuyAmount,
bool useEth,
address payer,
address receiver,
bytes32 callbackSelector
) external returns (uint256 buyAmount);
}
interface ICurveTricryptoCallback {
function curveTricryptoSwapCallback(
address payer,
address receiver,
IERC20 sellToken,
uint256 sellAmount,
uint256 buyAmount
) external;
}
abstract contract CurveTricrypto is SettlerAbstract {
using UnsafeMath for uint256;
using SafeTransferLib for IERC20;
using AddressDerivation for address;
function _curveFactory() internal virtual returns (address);
function sellToCurveTricryptoVIP(
address recipient,
uint80 poolInfo,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
uint256 minBuyAmount
) internal {
uint64 factoryNonce = uint64(poolInfo >> 16);
uint8 sellIndex = uint8(poolInfo >> 8);
uint8 buyIndex = uint8(poolInfo);
address pool = _curveFactory().deriveContract(factoryNonce);
bool isForwarded = _isForwarded();
assembly ("memory-safe") {
tstore(0x00, isForwarded)
tstore(0x01, mload(add(0x20, permit)))
tstore(0x02, mload(add(0x40, permit)))
for {
let src := add(0x20, sig)
let end
{
let len := mload(sig)
end := add(len, src)
tstore(0x03, len)
}
let dst := 0x04
} lt(src, end) {
src := add(0x20, src)
dst := add(0x01, dst)
} { tstore(dst, mload(src)) }
}
_setOperatorAndCall(
pool,
abi.encodeCall(
ICurveTricrypto.exchange_extended,
(
sellIndex,
buyIndex,
permit.permitted.amount,
minBuyAmount,
false,
address(0),
recipient,
bytes32(ICurveTricryptoCallback.curveTricryptoSwapCallback.selector)
)
),
uint32(ICurveTricryptoCallback.curveTricryptoSwapCallback.selector),
_curveTricryptoSwapCallback
);
}
function _curveTricryptoSwapCallback(bytes calldata data) private returns (bytes memory) {
require(data.length == 0xa0);
address payer;
IERC20 sellToken;
uint256 sellAmount;
assembly ("memory-safe") {
payer := calldataload(data.offset)
let err := shr(0xa0, payer)
sellToken := calldataload(add(0x40, data.offset))
err := or(shr(0xa0, sellToken), err)
sellAmount := calldataload(add(0x60, data.offset))
if err { revert(0x00, 0x00) }
}
curveTricryptoSwapCallback(payer, address(0), sellToken, sellAmount, 0);
return new bytes(0);
}
function curveTricryptoSwapCallback(address payer, address, IERC20 sellToken, uint256 sellAmount, uint256)
private
{
assert(payer == address(0));
bool isForwarded;
uint256 nonce;
uint256 deadline;
bytes memory sig;
assembly ("memory-safe") {
isForwarded := tload(0x00)
tstore(0x00, 0x00)
nonce := tload(0x01)
tstore(0x01, 0x00)
deadline := tload(0x02)
tstore(0x02, 0x00)
sig := mload(0x40)
for {
let dst := add(0x20, sig)
let end
{
let len := tload(0x03)
end := add(dst, len)
mstore(sig, len)
mstore(0x40, end)
}
let src := 0x04
} lt(dst, end) {
src := add(0x01, src)
dst := add(0x20, dst)
} {
mstore(dst, tload(src))
tstore(src, 0x00)
}
}
ISignatureTransfer.PermitTransferFrom memory permit = ISignatureTransfer.PermitTransferFrom({
permitted: ISignatureTransfer.TokenPermissions({token: address(sellToken), amount: sellAmount}),
nonce: nonce,
deadline: deadline
});
(ISignatureTransfer.SignatureTransferDetails memory transferDetails,,) =
_permitToTransferDetails(permit, msg.sender);
_transferFrom(permit, transferDetails, sig, isForwarded);
}
}
interface IDodoV1 {
function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256);
function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256);
function _R_STATUS_() external view returns (uint8);
function _QUOTE_BALANCE_() external view returns (uint256);
function _BASE_BALANCE_() external view returns (uint256);
function _K_() external view returns (uint256);
function _MT_FEE_RATE_() external view returns (uint256);
function _LP_FEE_RATE_() external view returns (uint256);
function getExpectedTarget() external view returns (uint256 baseTarget, uint256 quoteTarget);
function getOraclePrice() external view returns (uint256);
}
library Math {
function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 quotient = a / b;
unchecked {
uint256 remainder = a - quotient * b;
if (remainder > 0) {
return quotient + 1;
} else {
return quotient;
}
}
}
function sqrt(uint256 x) internal pure returns (uint256 y) {
unchecked {
uint256 z = x / 2 + 1;
y = x;
while (z < y) {
y = z;
z = (x / z + z) / 2;
}
}
}
}
library DecimalMath {
using Math for uint256;
uint256 constant ONE = 10 ** 18;
function mul(uint256 target, uint256 d) internal pure returns (uint256) {
unchecked {
return target * d / ONE;
}
}
function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) {
unchecked {
return (target * d).divCeil(ONE);
}
}
function divFloor(uint256 target, uint256 d) internal pure returns (uint256) {
unchecked {
return target * ONE / d;
}
}
function divCeil(uint256 target, uint256 d) internal pure returns (uint256) {
unchecked {
return (target * ONE).divCeil(d);
}
}
}
library DodoMath {
using Math for uint256;
function _GeneralIntegrate(uint256 V0, uint256 V1, uint256 V2, uint256 i, uint256 k)
internal
pure
returns (uint256)
{
unchecked {
uint256 fairAmount = DecimalMath.mul(i, V1 - V2);
uint256 V0V0V1V2 = DecimalMath.divCeil(V0 * V0 / V1, V2);
uint256 penalty = DecimalMath.mul(k, V0V0V1V2);
return DecimalMath.mul(fairAmount, DecimalMath.ONE - k + penalty);
}
}
function _SolveQuadraticFunctionForTrade(uint256 Q0, uint256 Q1, uint256 ideltaB, bool deltaBSig, uint256 k)
internal
pure
returns (uint256)
{
unchecked {
uint256 kQ02Q1 = DecimalMath.mul(k, Q0) * Q0 / Q1;
uint256 b = DecimalMath.mul(DecimalMath.ONE - k, Q1);
bool minusbSig = true;
if (deltaBSig) {
b += ideltaB;
} else {
kQ02Q1 += ideltaB;
}
if (b >= kQ02Q1) {
b -= kQ02Q1;
minusbSig = true;
} else {
b = kQ02Q1 - b;
minusbSig = false;
}
uint256 squareRoot = DecimalMath.mul((DecimalMath.ONE - k) * 4, DecimalMath.mul(k, Q0) * Q0);
squareRoot = (b * b + squareRoot).sqrt();
uint256 denominator = (DecimalMath.ONE - k) * 2;
uint256 numerator;
if (minusbSig) {
numerator = b + squareRoot;
} else {
numerator = squareRoot - b;
}
if (deltaBSig) {
return DecimalMath.divFloor(numerator, denominator);
} else {
return DecimalMath.divCeil(numerator, denominator);
}
}
}
function _SolveQuadraticFunctionForTarget(uint256 V1, uint256 k, uint256 fairAmount)
internal
pure
returns (uint256 V0)
{
unchecked {
uint256 sqrt = DecimalMath.divCeil(DecimalMath.mul(k, fairAmount) * 4, V1);
sqrt = ((sqrt + DecimalMath.ONE) * DecimalMath.ONE).sqrt();
uint256 premium = DecimalMath.divCeil(sqrt - DecimalMath.ONE, k * 2);
return DecimalMath.mul(V1, DecimalMath.ONE + premium);
}
}
}
abstract contract DodoSellHelper {
using Math for uint256;
enum RStatus {
ONE,
ABOVE_ONE,
BELOW_ONE
}
struct DodoState {
uint256 oraclePrice;
uint256 K;
uint256 B;
uint256 Q;
uint256 baseTarget;
uint256 quoteTarget;
RStatus rStatus;
}
function dodoQuerySellQuoteToken(IDodoV1 dodo, uint256 amount) internal view returns (uint256) {
DodoState memory state;
(state.baseTarget, state.quoteTarget) = dodo.getExpectedTarget();
state.rStatus = RStatus(dodo._R_STATUS_());
state.oraclePrice = dodo.getOraclePrice();
state.Q = dodo._QUOTE_BALANCE_();
state.B = dodo._BASE_BALANCE_();
state.K = dodo._K_();
unchecked {
uint256 boughtAmount;
if (state.rStatus == RStatus.ONE) {
boughtAmount = _ROneSellQuoteToken(amount, state);
} else if (state.rStatus == RStatus.ABOVE_ONE) {
boughtAmount = _RAboveSellQuoteToken(amount, state);
} else {
uint256 backOneBase = state.B - state.baseTarget;
uint256 backOneQuote = state.quoteTarget - state.Q;
if (amount <= backOneQuote) {
boughtAmount = _RBelowSellQuoteToken(amount, state);
} else {
boughtAmount = backOneBase + _ROneSellQuoteToken(amount - backOneQuote, state);
}
}
return DecimalMath.divFloor(boughtAmount, DecimalMath.ONE + dodo._MT_FEE_RATE_() + dodo._LP_FEE_RATE_());
}
}
function _ROneSellQuoteToken(uint256 amount, DodoState memory state)
private
pure
returns (uint256 receiveBaseToken)
{
unchecked {
uint256 i = DecimalMath.divFloor(DecimalMath.ONE, state.oraclePrice);
uint256 B2 = DodoMath._SolveQuadraticFunctionForTrade(
state.baseTarget, state.baseTarget, DecimalMath.mul(i, amount), false, state.K
);
return state.baseTarget - B2;
}
}
function _RAboveSellQuoteToken(uint256 amount, DodoState memory state)
private
pure
returns (uint256 receieBaseToken)
{
unchecked {
uint256 i = DecimalMath.divFloor(DecimalMath.ONE, state.oraclePrice);
uint256 B2 = DodoMath._SolveQuadraticFunctionForTrade(
state.baseTarget, state.B, DecimalMath.mul(i, amount), false, state.K
);
return state.B - B2;
}
}
function _RBelowSellQuoteToken(uint256 amount, DodoState memory state)
private
pure
returns (uint256 receiveBaseToken)
{
unchecked {
uint256 Q1 = state.Q + amount;
uint256 i = DecimalMath.divFloor(DecimalMath.ONE, state.oraclePrice);
return DodoMath._GeneralIntegrate(state.quoteTarget, Q1, state.Q, i, state.K);
}
}
}
abstract contract DodoV1 is SettlerAbstract, DodoSellHelper {
using FullMath for uint256;
using SafeTransferLib for IERC20;
function sellToDodoV1(IERC20 sellToken, uint256 bps, IDodoV1 dodo, bool quoteForBase, uint256 minBuyAmount)
internal
{
uint256 sellAmount = sellToken.balanceOf(address(this)).mulDiv(bps, 10_000);
sellToken.safeApproveIfBelow(address(dodo), sellAmount);
if (quoteForBase) {
uint256 buyAmount = dodoQuerySellQuoteToken(dodo, sellAmount);
if (buyAmount < minBuyAmount) {
revert TooMuchSlippage(sellToken, minBuyAmount, buyAmount);
}
dodo.buyBaseToken(buyAmount, sellAmount, new bytes(0));
} else {
dodo.sellBaseToken(sellAmount, minBuyAmount, new bytes(0));
}
}
}
interface IDodoV2 {
function sellBase(address to) external returns (uint256 receiveQuoteAmount);
function sellQuote(address to) external returns (uint256 receiveBaseAmount);
function _BASE_TOKEN_() external view returns (IERC20);
function _QUOTE_TOKEN_() external view returns (IERC20);
}
abstract contract DodoV2 is SettlerAbstract {
using FullMath for uint256;
using SafeTransferLib for IERC20;
function sellToDodoV2(
address recipient,
IERC20 sellToken,
uint256 bps,
IDodoV2 dodo,
bool quoteForBase,
uint256 minBuyAmount
) internal returns (uint256 buyAmount) {
if (bps != 0) {
uint256 sellAmount = sellToken.balanceOf(address(this)).mulDiv(bps, 10_000);
sellToken.safeTransfer(address(dodo), sellAmount);
}
if (quoteForBase) {
buyAmount = dodo.sellQuote(recipient);
if (buyAmount < minBuyAmount) {
revert TooMuchSlippage(dodo._BASE_TOKEN_(), minBuyAmount, buyAmount);
}
} else {
buyAmount = dodo.sellBase(recipient);
if (buyAmount < minBuyAmount) {
revert TooMuchSlippage(dodo._QUOTE_TOKEN_(), minBuyAmount, buyAmount);
}
}
}
}
bytes32 constant maverickV2InitHash = 0xbb7b783eb4b8ca46925c5384a6b9919df57cb83da8f76e37291f58d0dd5c439a;
address constant maverickV2Factory = 0x0A7e848Aca42d879EF06507Fca0E7b33A0a63c1e;
interface IMaverickV2Pool {
struct SwapParams {
uint256 amount;
bool tokenAIn;
bool exactOutput;
int32 tickLimit;
}
function swap(address recipient, SwapParams calldata params, bytes calldata data)
external
returns (uint256 amountIn, uint256 amountOut);
function tokenA() external view returns (IERC20);
function tokenB() external view returns (IERC20);
struct State {
uint128 reserveA;
uint128 reserveB;
int64 lastTwaD8;
int64 lastLogPriceD8;
uint40 lastTimestamp;
int32 activeTick;
bool isLocked;
uint32 binCounter;
uint8 protocolFeeRatioD3;
}
function getState() external view returns (State memory);
}
interface IMaverickV2SwapCallback {
function maverickV2SwapCallback(IERC20 tokenIn, uint256 amountIn, uint256 amountOut, bytes calldata data)
external;
}
abstract contract MaverickV2 is SettlerAbstract {
using UnsafeMath for uint256;
using SafeTransferLib for IERC20;
function _encodeSwapCallback(ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig)
internal
view
returns (bytes memory result)
{
bool isForwarded = _isForwarded();
assembly ("memory-safe") {
result := mload(0x40)
mcopy(add(0x20, result), mload(permit), 0x40)
mcopy(add(0x60, result), add(0x20, permit), 0x40)
mstore8(add(0xa0, result), isForwarded)
let sigLength := mload(sig)
mcopy(add(0xa1, result), add(0x20, sig), sigLength)
mstore(result, add(0x81, sigLength))
mstore(0x40, add(sigLength, add(0xa1, result)))
}
}
function sellToMaverickV2VIP(
address recipient,
bytes32 salt,
bool tokenAIn,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
uint256 minBuyAmount
) internal returns (uint256 buyAmount) {
bytes memory swapCallbackData = _encodeSwapCallback(permit, sig);
address pool = AddressDerivation.deriveDeterministicContract(maverickV2Factory, salt, maverickV2InitHash);
(, buyAmount) = abi.decode(
_setOperatorAndCall(
pool,
abi.encodeCall(
IMaverickV2Pool.swap,
(
recipient,
IMaverickV2Pool.SwapParams({
amount: permit.permitted.amount,
tokenAIn: tokenAIn,
exactOutput: false,
tickLimit: tokenAIn ? type(int32).max : type(int32).min
}),
swapCallbackData
)
),
uint32(IMaverickV2SwapCallback.maverickV2SwapCallback.selector),
_maverickV2Callback
),
(uint256, uint256)
);
if (buyAmount < minBuyAmount) {
IERC20 buyToken = tokenAIn ? IMaverickV2Pool(pool).tokenB() : IMaverickV2Pool(pool).tokenA();
revert TooMuchSlippage(buyToken, minBuyAmount, buyAmount);
}
}
function sellToMaverickV2(
address recipient,
IERC20 sellToken,
uint256 bps,
IMaverickV2Pool pool,
bool tokenAIn,
uint256 minBuyAmount
) internal returns (uint256 buyAmount) {
uint256 sellAmount;
if (bps != 0) {
unchecked {
sellAmount = (sellToken.balanceOf(address(this)) * bps).unsafeDiv(10_000);
}
}
if (sellAmount == 0) {
sellAmount = sellToken.balanceOf(address(pool));
IMaverickV2Pool.State memory poolState = pool.getState();
unchecked {
sellAmount -= tokenAIn ? poolState.reserveA : poolState.reserveB;
}
} else {
sellToken.safeTransfer(address(pool), sellAmount);
}
(, buyAmount) = pool.swap(
recipient,
IMaverickV2Pool.SwapParams({
amount: sellAmount,
tokenAIn: tokenAIn,
exactOutput: false,
tickLimit: tokenAIn ? type(int32).max : type(int32).min
}),
new bytes(0)
);
if (buyAmount < minBuyAmount) {
revert TooMuchSlippage(tokenAIn ? pool.tokenB() : pool.tokenA(), minBuyAmount, buyAmount);
}
}
function _maverickV2Callback(bytes calldata data) private returns (bytes memory) {
require(data.length >= 0xa0);
IERC20 tokenIn;
uint256 amountIn;
assembly ("memory-safe") {
tokenIn := calldataload(data.offset)
amountIn := calldataload(add(0x20, data.offset))
data.length := calldataload(add(0x80, data.offset))
data.offset := add(0xa0, data.offset)
}
maverickV2SwapCallback(
tokenIn,
amountIn,
0 ,
data
);
return new bytes(0);
}
function maverickV2SwapCallback(IERC20 tokenIn, uint256 amountIn, uint256 , bytes calldata data)
private
{
ISignatureTransfer.PermitTransferFrom calldata permit;
bool isForwarded;
assembly ("memory-safe") {
permit := data.offset
isForwarded := and(0x01, calldataload(add(0x61, data.offset)))
data.offset := add(0x81, data.offset)
data.length := sub(data.length, 0x81)
}
assert(tokenIn == IERC20(permit.permitted.token));
_transferFrom(
permit,
ISignatureTransfer.SignatureTransferDetails({to: msg.sender, requestedAmount: amountIn}),
data,
isForwarded
);
}
}
library TransientStorage {
bytes32 private constant _OPERATOR_SLOT = 0x009355806b743562f351db2e3726091207f49fa1cdccd5c65a7d4860ce3abbe9;
bytes32 private constant _WITNESS_SLOT = 0x1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa;
bytes32 private constant _PAYER_SLOT = 0x46bacb9b87ba1d2910347e4a3e052d06c824a45acd1e9517bb0cb8d0d5cde893;
function setOperatorAndCallback(
address operator,
uint32 selector,
function (bytes calldata) internal returns (bytes memory) callback
) internal {
address currentSigner;
assembly ("memory-safe") {
currentSigner := tload(_PAYER_SLOT)
}
if (operator == currentSigner) {
revert ConfusedDeputy();
}
uint256 callbackInt;
assembly ("memory-safe") {
callbackInt := tload(_OPERATOR_SLOT)
}
if (callbackInt != 0) {
revert ReentrantCallback(callbackInt);
}
assembly ("memory-safe") {
tstore(
_OPERATOR_SLOT,
or(
shl(0xe0, selector),
or(shl(0xa0, and(0xffff, callback)), and(0xffffffffffffffffffffffffffffffffffffffff, operator))
)
)
}
}
function checkSpentOperatorAndCallback() internal view {
uint256 callbackInt;
assembly ("memory-safe") {
callbackInt := tload(_OPERATOR_SLOT)
}
if (callbackInt != 0) {
revert CallbackNotSpent(callbackInt);
}
}
function getAndClearOperatorAndCallback()
internal
returns (bytes4 selector, function (bytes calldata) internal returns (bytes memory) callback, address operator)
{
assembly ("memory-safe") {
selector := tload(_OPERATOR_SLOT)
callback := and(0xffff, shr(0xa0, selector))
operator := selector
tstore(_OPERATOR_SLOT, 0x00)
}
}
function setWitness(bytes32 newWitness) internal {
bytes32 currentWitness;
assembly ("memory-safe") {
currentWitness := tload(_WITNESS_SLOT)
}
if (currentWitness != bytes32(0)) {
revert ReentrantMetatransaction(currentWitness);
}
assembly ("memory-safe") {
tstore(_WITNESS_SLOT, newWitness)
}
}
function checkSpentWitness() internal view {
bytes32 currentWitness;
assembly ("memory-safe") {
currentWitness := tload(_WITNESS_SLOT)
}
if (currentWitness != bytes32(0)) {
revert WitnessNotSpent(currentWitness);
}
}
function getAndClearWitness() internal returns (bytes32 witness) {
assembly ("memory-safe") {
witness := tload(_WITNESS_SLOT)
tstore(_WITNESS_SLOT, 0x00)
}
}
function setPayer(address payer) internal {
if (payer == address(0)) {
revert ConfusedDeputy();
}
address oldPayer;
assembly ("memory-safe") {
oldPayer := tload(_PAYER_SLOT)
}
if (oldPayer != address(0)) {
revert ReentrantPayer(oldPayer);
}
assembly ("memory-safe") {
tstore(_PAYER_SLOT, and(0xffffffffffffffffffffffffffffffffffffffff, payer))
}
}
function getPayer() internal view returns (address payer) {
assembly ("memory-safe") {
payer := tload(_PAYER_SLOT)
}
}
function clearPayer(address expectedOldPayer) internal {
address oldPayer;
assembly ("memory-safe") {
oldPayer := tload(_PAYER_SLOT)
}
if (oldPayer != expectedOldPayer) {
revert PayerSpent();
}
assembly ("memory-safe") {
tstore(_PAYER_SLOT, 0x00)
}
}
}
abstract contract Permit2PaymentBase is SettlerAbstract {
using Revert for bool;
ISignatureTransfer internal constant _PERMIT2 = ISignatureTransfer(0x000000000022D473030F116dDEE9F6B43aC78BA3);
function _isRestrictedTarget(address target) internal pure virtual override returns (bool) {
return target == address(_PERMIT2);
}
function _msgSender() internal view virtual override returns (address) {
return TransientStorage.getPayer();
}
function _setOperatorAndCall(
address payable target,
uint256 value,
bytes memory data,
uint32 selector,
function (bytes calldata) internal returns (bytes memory) callback
) internal returns (bytes memory) {
TransientStorage.setOperatorAndCallback(target, selector, callback);
(bool success, bytes memory returndata) = target.call{value: value}(data);
success.maybeRevert(returndata);
TransientStorage.checkSpentOperatorAndCallback();
return returndata;
}
function _setOperatorAndCall(
address target,
bytes memory data,
uint32 selector,
function (bytes calldata) internal returns (bytes memory) callback
) internal override returns (bytes memory) {
return _setOperatorAndCall(payable(target), 0, data, selector, callback);
}
function _invokeCallback(bytes calldata data) internal returns (bytes memory) {
(bytes4 selector, function (bytes calldata) internal returns (bytes memory) callback, address operator) =
TransientStorage.getAndClearOperatorAndCallback();
require(bytes4(data) == selector);
require(msg.sender == operator);
return callback(data[4:]);
}
}
abstract contract Permit2Payment is Permit2PaymentBase {
fallback(bytes calldata data) external virtual returns (bytes memory) {
return _invokeCallback(data);
}
function _permitToTransferDetails(ISignatureTransfer.PermitTransferFrom memory permit, address recipient)
internal
pure
override
returns (ISignatureTransfer.SignatureTransferDetails memory transferDetails, address token, uint256 amount)
{
transferDetails.to = recipient;
transferDetails.requestedAmount = amount = permit.permitted.amount;
token = permit.permitted.token;
}
function _transferFromIKnowWhatImDoing(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails memory transferDetails,
address from,
bytes32 witness,
string memory witnessTypeString,
bytes memory sig,
bool isForwarded
) internal override {
if (isForwarded) revert ForwarderNotAllowed();
_PERMIT2.permitWitnessTransferFrom(permit, transferDetails, from, witness, witnessTypeString, sig);
}
function _transferFromIKnowWhatImDoing(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails memory transferDetails,
address from,
bytes32 witness,
string memory witnessTypeString,
bytes memory sig
) internal override {
_transferFromIKnowWhatImDoing(permit, transferDetails, from, witness, witnessTypeString, sig, _isForwarded());
}
function _transferFrom(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails memory transferDetails,
bytes memory sig
) internal override {
_transferFrom(permit, transferDetails, sig, _isForwarded());
}
}
abstract contract Permit2PaymentTakerSubmitted is AllowanceHolderContext, Permit2Payment {
constructor() {
assert(!_hasMetaTxn());
}
function _isRestrictedTarget(address target) internal pure virtual override returns (bool) {
return target == address(_ALLOWANCE_HOLDER) || super._isRestrictedTarget(target);
}
function _operator() internal view override returns (address) {
return AllowanceHolderContext._msgSender();
}
function _msgSender()
internal
view
virtual
override(Permit2PaymentBase, AllowanceHolderContext)
returns (address)
{
return Permit2PaymentBase._msgSender();
}
function _transferFrom(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails memory transferDetails,
bytes memory sig,
bool isForwarded
) internal override {
if (isForwarded) {
if (sig.length != 0) revert InvalidSignatureLen();
if (permit.nonce != 0) Panic.panic(Panic.ARITHMETIC_OVERFLOW);
if (block.timestamp > permit.deadline) revert SignatureExpired(permit.deadline);
_allowanceHolderTransferFrom(
permit.permitted.token, _msgSender(), transferDetails.to, transferDetails.requestedAmount
);
} else {
_PERMIT2.permitTransferFrom(permit, transferDetails, _msgSender(), sig);
}
}
function _allowanceHolderTransferFrom(address token, address owner, address recipient, uint256 amount)
internal
override
{
_ALLOWANCE_HOLDER.transferFrom(token, owner, recipient, amount);
}
modifier takerSubmitted() override {
address msgSender = _operator();
TransientStorage.setPayer(msgSender);
_;
TransientStorage.clearPayer(msgSender);
}
modifier metaTx(address, bytes32) override {
revert();
_;
}
}
abstract contract Permit2PaymentMetaTxn is Context, Permit2Payment {
constructor() {
assert(_hasMetaTxn());
}
function _operator() internal view override returns (address) {
return Context._msgSender();
}
function _msgSender() internal view virtual override(Permit2PaymentBase, Context) returns (address) {
return Permit2PaymentBase._msgSender();
}
string private constant _SLIPPAGE_AND_ACTIONS_WITNESS = string(
abi.encodePacked("SlippageAndActions slippageAndActions)", SLIPPAGE_AND_ACTIONS_TYPE, TOKEN_PERMISSIONS_TYPE)
);
function _transferFrom(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails memory transferDetails,
bytes memory sig,
bool isForwarded
) internal override {
bytes32 witness = TransientStorage.getAndClearWitness();
if (witness == bytes32(0)) {
revert ConfusedDeputy();
}
_transferFromIKnowWhatImDoing(
permit, transferDetails, _msgSender(), witness, _SLIPPAGE_AND_ACTIONS_WITNESS, sig, isForwarded
);
}
function _allowanceHolderTransferFrom(address, address, address, uint256) internal pure override {
revert ConfusedDeputy();
}
modifier takerSubmitted() override {
revert();
_;
}
modifier metaTx(address msgSender, bytes32 witness) override {
if (_isForwarded()) {
revert ForwarderNotAllowed();
}
TransientStorage.setWitness(witness);
TransientStorage.setPayer(msgSender);
_;
TransientStorage.clearPayer(msgSender);
TransientStorage.checkSpentWitness();
}
}
interface IUniswapV3Pool {
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
}
abstract contract UniswapV3Fork is SettlerAbstract {
using UnsafeMath for uint256;
using SafeTransferLib for IERC20;
uint256 private constant SINGLE_HOP_PATH_SIZE = 0x2c;
uint256 private constant PATH_SKIP_HOP_SIZE = 0x18;
uint256 private constant SWAP_CALLBACK_PREFIX_DATA_SIZE = 0x28;
uint256 private constant SWAP_CALLBACK_PERMIT2DATA_OFFSET = 0x48;
uint256 private constant PERMIT_DATA_SIZE = 0x60;
uint256 private constant ISFORWARDED_DATA_SIZE = 0x01;
uint160 private constant MIN_PRICE_SQRT_RATIO = 4295128739;
uint160 private constant MAX_PRICE_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
uint256 private constant ADDRESS_MASK = 0x00ffffffffffffffffffffffffffffffffffffffff;
uint256 private constant UINT24_MASK = 0xffffff;
function sellToUniswapV3(address recipient, uint256 bps, bytes memory encodedPath, uint256 minBuyAmount)
internal
returns (uint256 buyAmount)
{
buyAmount = _uniV3ForkSwap(
recipient,
encodedPath,
(IERC20(address(bytes20(encodedPath))).balanceOf(address(this)) * bps).unsafeDiv(10_000),
minBuyAmount,
address(this),
new bytes(SWAP_CALLBACK_PREFIX_DATA_SIZE)
);
}
function sellToUniswapV3VIP(
address recipient,
bytes memory encodedPath,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
uint256 minBuyAmount
) internal returns (uint256 buyAmount) {
bytes memory swapCallbackData =
new bytes(SWAP_CALLBACK_PREFIX_DATA_SIZE + PERMIT_DATA_SIZE + ISFORWARDED_DATA_SIZE + sig.length);
_encodePermit2Data(swapCallbackData, permit, sig, _isForwarded());
buyAmount = _uniV3ForkSwap(
recipient,
encodedPath,
permit.permitted.amount,
minBuyAmount,
address(0),
swapCallbackData
);
}
function _uniV3ForkSwap(
address recipient,
bytes memory encodedPath,
uint256 sellAmount,
uint256 minBuyAmount,
address payer,
bytes memory swapCallbackData
) internal returns (uint256 buyAmount) {
if (sellAmount > uint256(type(int256).max)) {
Panic.panic(Panic.ARITHMETIC_OVERFLOW);
}
IERC20 outputToken;
while (true) {
bool isPathMultiHop = _isPathMultiHop(encodedPath);
bool zeroForOne;
IUniswapV3Pool pool;
uint32 callbackSelector;
{
(IERC20 token0, uint8 forkId, uint24 poolId, IERC20 token1) = _decodeFirstPoolInfoFromPath(encodedPath);
IERC20 sellToken = token0;
outputToken = token1;
if (!(zeroForOne = token0 < token1)) {
(token0, token1) = (token1, token0);
}
address factory;
bytes32 initHash;
(factory, initHash, callbackSelector) = _uniV3ForkInfo(forkId);
pool = _toPool(factory, initHash, token0, token1, poolId);
_updateSwapCallbackData(swapCallbackData, sellToken, payer);
}
int256 amount0;
int256 amount1;
if (isPathMultiHop) {
uint256 freeMemPtr;
assembly ("memory-safe") {
freeMemPtr := mload(0x40)
}
(amount0, amount1) = abi.decode(
_setOperatorAndCall(
address(pool),
abi.encodeCall(
pool.swap,
(
address(this),
zeroForOne,
int256(sellAmount),
zeroForOne ? MIN_PRICE_SQRT_RATIO + 1 : MAX_PRICE_SQRT_RATIO - 1,
swapCallbackData
)
),
callbackSelector,
_uniV3ForkCallback
),
(int256, int256)
);
assembly ("memory-safe") {
mstore(0x40, freeMemPtr)
}
} else {
(amount0, amount1) = abi.decode(
_setOperatorAndCall(
address(pool),
abi.encodeCall(
pool.swap,
(
recipient,
zeroForOne,
int256(sellAmount),
zeroForOne ? MIN_PRICE_SQRT_RATIO + 1 : MAX_PRICE_SQRT_RATIO - 1,
swapCallbackData
)
),
callbackSelector,
_uniV3ForkCallback
),
(int256, int256)
);
}
{
int256 _buyAmount = -(zeroForOne ? amount1 : amount0);
if (_buyAmount < 0) {
Panic.panic(Panic.ARITHMETIC_OVERFLOW);
}
buyAmount = uint256(_buyAmount);
}
if (!isPathMultiHop) {
break;
}
payer = address(this);
sellAmount = buyAmount;
encodedPath = _shiftHopFromPathInPlace(encodedPath);
assembly ("memory-safe") {
mstore(swapCallbackData, SWAP_CALLBACK_PREFIX_DATA_SIZE)
}
}
if (buyAmount < minBuyAmount) {
revert TooMuchSlippage(outputToken, minBuyAmount, buyAmount);
}
}
function _isPathMultiHop(bytes memory encodedPath) private pure returns (bool) {
return encodedPath.length > SINGLE_HOP_PATH_SIZE;
}
function _decodeFirstPoolInfoFromPath(bytes memory encodedPath)
private
pure
returns (IERC20 inputToken, uint8 forkId, uint24 poolId, IERC20 outputToken)
{
if (encodedPath.length < SINGLE_HOP_PATH_SIZE) {
Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
}
assembly ("memory-safe") {
inputToken := mload(add(encodedPath, 0x14))
forkId := mload(add(encodedPath, 0x15))
poolId := mload(add(encodedPath, 0x18))
outputToken := mload(add(encodedPath, SINGLE_HOP_PATH_SIZE))
}
}
function _shiftHopFromPathInPlace(bytes memory encodedPath) private pure returns (bytes memory) {
if (encodedPath.length < PATH_SKIP_HOP_SIZE) {
Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
}
assembly ("memory-safe") {
let length := sub(mload(encodedPath), PATH_SKIP_HOP_SIZE)
encodedPath := add(encodedPath, PATH_SKIP_HOP_SIZE)
mstore(encodedPath, length)
}
return encodedPath;
}
function _encodePermit2Data(
bytes memory swapCallbackData,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
bool isForwarded
) private pure {
assembly ("memory-safe") {
mstore(add(SWAP_CALLBACK_PERMIT2DATA_OFFSET, swapCallbackData), mload(add(0x20, mload(permit))))
mcopy(add(add(SWAP_CALLBACK_PERMIT2DATA_OFFSET, 0x20), swapCallbackData), add(0x20, permit), 0x40)
mstore8(add(add(SWAP_CALLBACK_PERMIT2DATA_OFFSET, PERMIT_DATA_SIZE), swapCallbackData), isForwarded)
mcopy(
add(
add(add(SWAP_CALLBACK_PERMIT2DATA_OFFSET, PERMIT_DATA_SIZE), ISFORWARDED_DATA_SIZE),
swapCallbackData
),
add(0x20, sig),
mload(sig)
)
}
}
function _updateSwapCallbackData(bytes memory swapCallbackData, IERC20 sellToken, address payer) private pure {
assembly ("memory-safe") {
let length := mload(swapCallbackData)
mstore(add(0x28, swapCallbackData), sellToken)
mstore(add(0x14, swapCallbackData), payer)
mstore(swapCallbackData, length)
}
}
function _toPool(address factory, bytes32 initHash, IERC20 token0, IERC20 token1, uint24 poolId)
private
pure
returns (IUniswapV3Pool)
{
bytes32 salt;
assembly ("memory-safe") {
token0 := and(ADDRESS_MASK, token0)
token1 := and(ADDRESS_MASK, token1)
poolId := and(UINT24_MASK, poolId)
let ptr := mload(0x40)
mstore(0x00, token0)
mstore(0x20, token1)
mstore(0x40, poolId)
salt := keccak256(0x00, sub(0x60, shl(0x05, iszero(poolId))))
mstore(0x40, ptr)
}
return IUniswapV3Pool(AddressDerivation.deriveDeterministicContract(factory, salt, initHash));
}
function _uniV3ForkInfo(uint8 forkId) internal view virtual returns (address, bytes32, uint32);
function _uniV3ForkCallback(bytes calldata data) private returns (bytes memory) {
require(data.length >= 0x80);
int256 amount0Delta;
int256 amount1Delta;
assembly ("memory-safe") {
amount0Delta := calldataload(data.offset)
amount1Delta := calldataload(add(0x20, data.offset))
data.offset := add(data.offset, calldataload(add(0x40, data.offset)))
data.length := calldataload(data.offset)
data.offset := add(0x20, data.offset)
}
uniswapV3SwapCallback(amount0Delta, amount1Delta, data);
return new bytes(0);
}
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) private {
address payer = address(uint160(bytes20(data)));
data = data[0x14:];
uint256 sellAmount = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
_pay(payer, sellAmount, data);
}
function _pay(address payer, uint256 amount, bytes calldata permit2Data) private {
if (payer == address(this)) {
IERC20(address(uint160(bytes20(permit2Data)))).safeTransfer(msg.sender, amount);
} else {
assert(payer == address(0));
ISignatureTransfer.PermitTransferFrom calldata permit;
bool isForwarded;
bytes calldata sig;
assembly ("memory-safe") {
permit := sub(permit2Data.offset, 0x0c)
isForwarded := and(0x01, calldataload(add(0x55, permit2Data.offset)))
sig.offset := add(0x75, permit2Data.offset)
sig.length := sub(permit2Data.length, 0x75)
}
_transferFrom(
permit,
ISignatureTransfer.SignatureTransferDetails({to: msg.sender, requestedAmount: amount}),
sig,
isForwarded
);
}
}
}
abstract contract Basic is SettlerAbstract {
using SafeTransferLib for IERC20;
using FullMath for uint256;
using Revert for bool;
IERC20 internal constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
function basicSellToPool(IERC20 sellToken, uint256 bps, address pool, uint256 offset, bytes memory data) internal {
if (_isRestrictedTarget(pool)) {
revert ConfusedDeputy();
}
bool success;
bytes memory returnData;
uint256 value;
if (sellToken == IERC20(ETH_ADDRESS)) {
value = address(this).balance.mulDiv(bps, 10_000);
if (data.length == 0) {
if (offset != 0) revert InvalidOffset();
(success, returnData) = payable(pool).call{value: value}("");
success.maybeRevert(returnData);
return;
} else {
if ((offset += 32) > data.length) {
Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
}
assembly ("memory-safe") {
mstore(add(data, offset), value)
}
}
} else if (address(sellToken) == address(0)) {
if (offset != 0) revert InvalidOffset();
} else {
uint256 amount = sellToken.balanceOf(address(this)).mulDiv(bps, 10_000);
if ((offset += 32) > data.length) {
Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
}
assembly ("memory-safe") {
mstore(add(data, offset), amount)
}
if (address(sellToken) != pool) {
sellToken.safeApproveIfBelow(pool, amount);
}
}
(success, returnData) = payable(pool).call{value: value}(data);
success.maybeRevert(returnData);
if (returnData.length == 0 && pool.code.length == 0) revert InvalidTarget();
}
}
library CalldataDecoder {
function decodeCall(bytes[] calldata data, uint256 i)
internal
pure
returns (bytes4 selector, bytes calldata args)
{
assembly ("memory-safe") {
args.offset :=
add(
data.offset,
calldataload(
add(shl(5, i), data.offset)
)
)
args.length := calldataload(args.offset)
args.offset := add(args.offset, 0x20)
selector := calldataload(args.offset)
args.length := sub(args.length, 0x04)
args.offset := add(args.offset, 0x04)
}
}
}
abstract contract SettlerBase is Basic, RfqOrderSettlement, UniswapV3Fork, UniswapV2, Velodrome {
using SafeTransferLib for IERC20;
using SafeTransferLib for address payable;
receive() external payable {}
event GitCommit(bytes20 indexed);
constructor(bytes20 gitCommit, uint256 tokenId) {
if (block.chainid != 31337) {
emit GitCommit(gitCommit);
assert(IERC721Owner(0x00000000000004533Fe15556B1E086BB1A72cEae).ownerOf(tokenId) == address(this));
} else {
assert(gitCommit == bytes20(0));
}
}
struct AllowedSlippage {
address recipient;
IERC20 buyToken;
uint256 minAmountOut;
}
function _checkSlippageAndTransfer(AllowedSlippage calldata slippage) internal {
(address recipient, IERC20 buyToken, uint256 minAmountOut) =
(slippage.recipient, slippage.buyToken, slippage.minAmountOut);
if (minAmountOut != 0 || address(buyToken) != address(0)) {
if (buyToken == ETH_ADDRESS) {
uint256 amountOut = address(this).balance;
if (amountOut < minAmountOut) {
revert TooMuchSlippage(buyToken, minAmountOut, amountOut);
}
payable(recipient).safeTransferETH(amountOut);
} else {
uint256 amountOut = buyToken.balanceOf(address(this));
if (amountOut < minAmountOut) {
revert TooMuchSlippage(buyToken, minAmountOut, amountOut);
}
buyToken.safeTransfer(recipient, amountOut);
}
}
}
function _dispatch(uint256, bytes4 action, bytes calldata data) internal virtual override returns (bool) {
if (action == ISettlerActions.TRANSFER_FROM.selector) {
(address recipient, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig) =
abi.decode(data, (address, ISignatureTransfer.PermitTransferFrom, bytes));
(ISignatureTransfer.SignatureTransferDetails memory transferDetails,,) =
_permitToTransferDetails(permit, recipient);
_transferFrom(permit, transferDetails, sig);
} else if (action == ISettlerActions.RFQ.selector) {
(
address recipient,
ISignatureTransfer.PermitTransferFrom memory permit,
address maker,
bytes memory makerSig,
IERC20 takerToken,
uint256 maxTakerAmount
) = abi.decode(data, (address, ISignatureTransfer.PermitTransferFrom, address, bytes, IERC20, uint256));
fillRfqOrderSelfFunded(recipient, permit, maker, makerSig, takerToken, maxTakerAmount);
} else if (action == ISettlerActions.UNISWAPV3.selector) {
(address recipient, uint256 bps, bytes memory path, uint256 amountOutMin) =
abi.decode(data, (address, uint256, bytes, uint256));
sellToUniswapV3(recipient, bps, path, amountOutMin);
} else if (action == ISettlerActions.UNISWAPV2.selector) {
(address recipient, address sellToken, uint256 bps, address pool, uint24 swapInfo, uint256 amountOutMin) =
abi.decode(data, (address, address, uint256, address, uint24, uint256));
sellToUniswapV2(recipient, sellToken, bps, pool, swapInfo, amountOutMin);
} else if (action == ISettlerActions.BASIC.selector) {
(IERC20 sellToken, uint256 bps, address pool, uint256 offset, bytes memory _data) =
abi.decode(data, (IERC20, uint256, address, uint256, bytes));
basicSellToPool(sellToken, bps, pool, offset, _data);
} else if (action == ISettlerActions.VELODROME.selector) {
(address recipient, uint256 bps, IVelodromePair pool, uint24 swapInfo, uint256 minAmountOut) =
abi.decode(data, (address, uint256, IVelodromePair, uint24, uint256));
sellToVelodrome(recipient, bps, pool, swapInfo, minAmountOut);
} else if (action == ISettlerActions.POSITIVE_SLIPPAGE.selector) {
(address recipient, IERC20 token, uint256 expectedAmount) = abi.decode(data, (address, IERC20, uint256));
if (token == IERC20(ETH_ADDRESS)) {
uint256 balance = address(this).balance;
if (balance > expectedAmount) {
unchecked {
payable(recipient).safeTransferETH(balance - expectedAmount);
}
}
} else {
uint256 balance = token.balanceOf(address(this));
if (balance > expectedAmount) {
unchecked {
token.safeTransfer(recipient, balance - expectedAmount);
}
}
}
} else {
return false;
}
return true;
}
}
abstract contract Settler is Permit2PaymentTakerSubmitted, SettlerBase {
using UnsafeMath for uint256;
using CalldataDecoder for bytes[];
constructor(bytes20 gitCommit) SettlerBase(gitCommit, 2) {}
function _hasMetaTxn() internal pure override returns (bool) {
return false;
}
function _msgSender()
internal
view
virtual
override(Permit2PaymentTakerSubmitted, AbstractContext)
returns (address)
{
return super._msgSender();
}
function _isRestrictedTarget(address target)
internal
pure
virtual
override(Permit2PaymentTakerSubmitted, Permit2PaymentAbstract)
returns (bool)
{
return super._isRestrictedTarget(target);
}
function _dispatchVIP(bytes4 action, bytes calldata data) internal virtual returns (bool) {
if (action == ISettlerActions.RFQ_VIP.selector) {
(
address recipient,
ISignatureTransfer.PermitTransferFrom memory makerPermit,
address maker,
bytes memory makerSig,
ISignatureTransfer.PermitTransferFrom memory takerPermit,
bytes memory takerSig
) = abi.decode(
data,
(
address,
ISignatureTransfer.PermitTransferFrom,
address,
bytes,
ISignatureTransfer.PermitTransferFrom,
bytes
)
);
fillRfqOrderVIP(recipient, makerPermit, maker, makerSig, takerPermit, takerSig);
} else if (action == ISettlerActions.UNISWAPV3_VIP.selector) {
(
address recipient,
bytes memory path,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
uint256 amountOutMin
) = abi.decode(data, (address, bytes, ISignatureTransfer.PermitTransferFrom, bytes, uint256));
sellToUniswapV3VIP(recipient, path, permit, sig, amountOutMin);
} else {
return false;
}
return true;
}
function execute(AllowedSlippage calldata slippage, bytes[] calldata actions, bytes32 )
public
payable
takerSubmitted
returns (bool)
{
for (uint256 i; i < actions.length; i = i.unsafeInc()) {
(bytes4 action, bytes calldata data) = actions.decodeCall(i);
if (!((i == 0 && _dispatchVIP(action, data)) || _dispatch(i, action, data))) {
revert ActionInvalid(i, action, data);
}
}
_checkSlippageAndTransfer(slippage);
return true;
}
}
abstract contract SettlerMetaTxn is Permit2PaymentMetaTxn, SettlerBase {
using UnsafeMath for uint256;
using CalldataDecoder for bytes[];
constructor(bytes20 gitCommit) SettlerBase(gitCommit, 3) {}
function _hasMetaTxn() internal pure override returns (bool) {
return true;
}
function _msgSender()
internal
view
virtual
override(Permit2PaymentMetaTxn, AbstractContext)
returns (address)
{
return super._msgSender();
}
function _hashArrayOfBytes(bytes[] calldata actions) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let ptr := mload(0x40)
let hashesLength := shl(5, actions.length)
for {
let i := actions.offset
let dst := ptr
let end := add(i, hashesLength)
} lt(i, end) {
i := add(i, 0x20)
dst := add(dst, 0x20)
} {
let src := add(actions.offset, calldataload(i))
let length := calldataload(src)
calldatacopy(dst, add(src, 0x20), length)
mstore(dst, keccak256(dst, length))
}
result := keccak256(ptr, hashesLength)
}
}
function _hashActionsAndSlippage(bytes[] calldata actions, AllowedSlippage calldata slippage)
internal
pure
returns (bytes32 result)
{
bytes32 arrayOfBytesHash = _hashArrayOfBytes(actions);
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, SLIPPAGE_AND_ACTIONS_TYPEHASH)
calldatacopy(add(ptr, 0x20), slippage, 0x60)
mstore(add(ptr, 0x80), arrayOfBytesHash)
result := keccak256(ptr, 0xa0)
}
}
function _dispatchVIP(bytes4 action, bytes calldata data, bytes calldata sig) internal virtual returns (bool) {
if (action == ISettlerActions.METATXN_RFQ_VIP.selector) {
(
address recipient,
ISignatureTransfer.PermitTransferFrom memory makerPermit,
address maker,
bytes memory makerSig,
ISignatureTransfer.PermitTransferFrom memory takerPermit
) = abi.decode(
data,
(address, ISignatureTransfer.PermitTransferFrom, address, bytes, ISignatureTransfer.PermitTransferFrom)
);
fillRfqOrderVIP(recipient, makerPermit, maker, makerSig, takerPermit, sig);
} else if (action == ISettlerActions.METATXN_TRANSFER_FROM.selector) {
(address recipient, ISignatureTransfer.PermitTransferFrom memory permit) =
abi.decode(data, (address, ISignatureTransfer.PermitTransferFrom));
(ISignatureTransfer.SignatureTransferDetails memory transferDetails,,) =
_permitToTransferDetails(permit, recipient);
_transferFrom(permit, transferDetails, sig);
} else if (action == ISettlerActions.METATXN_UNISWAPV3_VIP.selector) {
(
address recipient,
bytes memory path,
ISignatureTransfer.PermitTransferFrom memory permit,
uint256 amountOutMin
) = abi.decode(data, (address, bytes, ISignatureTransfer.PermitTransferFrom, uint256));
sellToUniswapV3VIP(recipient, path, permit, sig, amountOutMin);
} else {
return false;
}
return true;
}
function executeMetaTxn(
AllowedSlippage calldata slippage,
bytes[] calldata actions,
bytes32,
address msgSender,
bytes calldata sig
) public metaTx(msgSender, _hashActionsAndSlippage(actions, slippage)) returns (bool) {
require(actions.length != 0);
{
(bytes4 action, bytes calldata data) = actions.decodeCall(0);
if (!_dispatchVIP(action, data, sig)) {
revert ActionInvalid(0, action, data);
}
}
for (uint256 i = 1; i < actions.length; i = i.unsafeInc()) {
(bytes4 action, bytes calldata data) = actions.decodeCall(i);
if (!_dispatch(i, action, data)) {
revert ActionInvalid(i, action, data);
}
}
_checkSlippageAndTransfer(slippage);
return true;
}
}
abstract contract MainnetMixin is FreeMemory, SettlerBase, MakerPSM, MaverickV2, CurveTricrypto, DodoV1, DodoV2 {
constructor() {
assert(block.chainid == 1 || block.chainid == 31337);
}
function _dispatch(uint256 i, bytes4 action, bytes calldata data)
internal
virtual
override(SettlerAbstract, SettlerBase)
DANGEROUS_freeMemory
returns (bool)
{
if (super._dispatch(i, action, data)) {
return true;
} else if (action == ISettlerActions.MAKERPSM.selector) {
(address recipient, IERC20 gemToken, uint256 bps, IPSM psm, bool buyGem) =
abi.decode(data, (address, IERC20, uint256, IPSM, bool));
sellToMakerPsm(recipient, gemToken, bps, psm, buyGem);
} else if (action == ISettlerActions.MAVERICKV2.selector) {
(
address recipient,
IERC20 sellToken,
uint256 bps,
IMaverickV2Pool pool,
bool tokenAIn,
uint256 minBuyAmount
) = abi.decode(data, (address, IERC20, uint256, IMaverickV2Pool, bool, uint256));
sellToMaverickV2(recipient, sellToken, bps, pool, tokenAIn, minBuyAmount);
} else if (action == ISettlerActions.DODOV2.selector) {
(address recipient, IERC20 sellToken, uint256 bps, IDodoV2 dodo, bool quoteForBase, uint256 minBuyAmount) =
abi.decode(data, (address, IERC20, uint256, IDodoV2, bool, uint256));
sellToDodoV2(recipient, sellToken, bps, dodo, quoteForBase, minBuyAmount);
} else if (action == ISettlerActions.DODOV1.selector) {
(IERC20 sellToken, uint256 bps, IDodoV1 dodo, bool quoteForBase, uint256 minBuyAmount) =
abi.decode(data, (IERC20, uint256, IDodoV1, bool, uint256));
sellToDodoV1(sellToken, bps, dodo, quoteForBase, minBuyAmount);
} else {
return false;
}
return true;
}
function _uniV3ForkInfo(uint8 forkId)
internal
pure
override
returns (address factory, bytes32 initHash, uint32 callbackSelector)
{
if (forkId == uniswapV3ForkId) {
factory = uniswapV3MainnetFactory;
initHash = uniswapV3InitHash;
callbackSelector = uint32(IUniswapV3Callback.uniswapV3SwapCallback.selector);
} else if (forkId == pancakeSwapV3ForkId) {
factory = pancakeSwapV3Factory;
initHash = pancakeSwapV3InitHash;
callbackSelector = uint32(IPancakeSwapV3Callback.pancakeV3SwapCallback.selector);
} else if (forkId == sushiswapV3ForkId) {
factory = sushiswapV3MainnetFactory;
initHash = uniswapV3InitHash;
callbackSelector = uint32(IUniswapV3Callback.uniswapV3SwapCallback.selector);
} else if (forkId == solidlyV3ForkId) {
factory = solidlyV3Factory;
initHash = solidlyV3InitHash;
callbackSelector = uint32(ISolidlyV3Callback.solidlyV3SwapCallback.selector);
} else {
revert UnknownForkId(forkId);
}
}
function _curveFactory() internal pure override returns (address) {
return 0x0c0e5f2fF0ff18a3be9b835635039256dC4B4963;
}
}
contract MainnetSettler is Settler, MainnetMixin {
constructor(bytes20 gitCommit) Settler(gitCommit) {}
function _dispatchVIP(bytes4 action, bytes calldata data) internal override DANGEROUS_freeMemory returns (bool) {
if (super._dispatchVIP(action, data)) {
return true;
} else if (action == ISettlerActions.MAVERICKV2_VIP.selector) {
(
address recipient,
bytes32 salt,
bool tokenAIn,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
uint256 minBuyAmount
) = abi.decode(data, (address, bytes32, bool, ISignatureTransfer.PermitTransferFrom, bytes, uint256));
sellToMaverickV2VIP(recipient, salt, tokenAIn, permit, sig, minBuyAmount);
} else if (action == ISettlerActions.CURVE_TRICRYPTO_VIP.selector) {
(
address recipient,
uint80 poolInfo,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes memory sig,
uint256 minBuyAmount
) = abi.decode(data, (address, uint80, ISignatureTransfer.PermitTransferFrom, bytes, uint256));
sellToCurveTricryptoVIP(recipient, poolInfo, permit, sig, minBuyAmount);
} else {
return false;
}
return true;
}
function _isRestrictedTarget(address target)
internal
pure
override(Settler, Permit2PaymentAbstract)
returns (bool)
{
return super._isRestrictedTarget(target);
}
function _dispatch(uint256 i, bytes4 action, bytes calldata data)
internal
override(SettlerAbstract, SettlerBase, MainnetMixin)
returns (bool)
{
return super._dispatch(i, action, data);
}
function _msgSender() internal view override(Settler, AbstractContext) returns (address) {
return super._msgSender();
}
}
contract MainnetSettlerMetaTxn is SettlerMetaTxn, MainnetMixin {
constructor(bytes20 gitCommit) SettlerMetaTxn(gitCommit) {}
function _dispatchVIP(bytes4 action, bytes calldata data, bytes calldata sig)
internal
override
DANGEROUS_freeMemory
returns (bool)
{
if (super._dispatchVIP(action, data, sig)) {
return true;
} else if (action == ISettlerActions.METATXN_MAVERICKV2_VIP.selector) {
(
address recipient,
bytes32 salt,
bool tokenAIn,
ISignatureTransfer.PermitTransferFrom memory permit,
uint256 minBuyAmount
) = abi.decode(data, (address, bytes32, bool, ISignatureTransfer.PermitTransferFrom, uint256));
sellToMaverickV2VIP(recipient, salt, tokenAIn, permit, sig, minBuyAmount);
} else if (action == ISettlerActions.METATXN_CURVE_TRICRYPTO_VIP.selector) {
(
address recipient,
uint80 poolInfo,
ISignatureTransfer.PermitTransferFrom memory permit,
uint256 minBuyAmount
) = abi.decode(data, (address, uint80, ISignatureTransfer.PermitTransferFrom, uint256));
sellToCurveTricryptoVIP(recipient, poolInfo, permit, sig, minBuyAmount);
} else {
return false;
}
return true;
}
function _dispatch(uint256 i, bytes4 action, bytes calldata data)
internal
override(SettlerAbstract, SettlerBase, MainnetMixin)
returns (bool)
{
return super._dispatch(i, action, data);
}
function _msgSender() internal view override(SettlerMetaTxn, AbstractContext) returns (address) {
return super._msgSender();
}
}