Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Multichain Info
N/A
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
10122225 | 31 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
KatanaSettlerIntent
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 2000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity =0.8.25 >=0.6.2 >=0.8.25 ^0.8.0 ^0.8.25; // src/Context.sol 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; } } // src/deployer/DeployerAddress.sol address constant DEPLOYER = 0x00000000000004533Fe15556B1E086BB1A72cEae; // src/utils/FastLogic.sol library FastLogic { function or(bool a, bool b) internal pure returns (bool r) { assembly ("memory-safe") { r := or(a, b) } } function and(bool a, bool b) internal pure returns (bool r) { assembly ("memory-safe") { r := and(a, b) } } function andNot(bool a, bool b) internal pure returns (bool r) { assembly ("memory-safe") { r := gt(a, b) } } } // src/utils/FreeMemory.sol abstract contract FreeMemory { modifier DANGEROUS_freeMemory() { uint256 freeMemPtr; assembly ("memory-safe") { freeMemPtr := mload(0x40) } _; assembly ("memory-safe") { mstore(0x40, freeMemPtr) } } } // src/allowanceholder/IAllowanceHolder.sol IAllowanceHolder constant ALLOWANCE_HOLDER = IAllowanceHolder(0x0000000000001fF3684f28c67538d4D072C22734); interface IAllowanceHolder { /// @notice Executes against `target` with the `data` payload. Prior to execution, token permits /// are temporarily stored for the duration of the transaction. These permits can be /// consumed by the `operator` during the execution /// @notice `operator` consumes the funds during its operations by calling back into /// `AllowanceHolder` with `transferFrom`, consuming a token permit. /// @dev Neither `exec` nor `transferFrom` check that `token` contains code. /// @dev msg.sender is forwarded to target appended to the msg data (similar to ERC-2771) /// @param operator An address which is allowed to consume the token permits /// @param token The ERC20 token the caller has authorised to be consumed /// @param amount The quantity of `token` the caller has authorised to be consumed /// @param target A contract to execute operations with `data` /// @param data The data to forward to `target` /// @return result The returndata from calling `target` with `data` /// @notice If calling `target` with `data` reverts, the revert is propagated function exec(address operator, address token, uint256 amount, address payable target, bytes calldata data) external payable returns (bytes memory result); /// @notice The counterpart to `exec` which allows for the consumption of token permits later /// during execution /// @dev *DOES NOT* check that `token` contains code. This function vacuously succeeds if /// `token` is empty. /// @dev can only be called by the `operator` previously registered in `exec` /// @param token The ERC20 token to transfer /// @param owner The owner of tokens to transfer /// @param recipient The destination/beneficiary of the ERC20 `transferFrom` /// @param amount The quantity of `token` to transfer` /// @return true function transferFrom(address token, address owner, address recipient, uint256 amount) external returns (bool); } // lib/permit2/src/interfaces/IEIP712.sol interface IEIP712 { function DOMAIN_SEPARATOR() external view returns (bytes32); } // lib/forge-std/src/interfaces/IERC165.sol interface IERC165 { /// @notice Query if a contract implements an interface /// @param interfaceID The interface identifier, as specified in ERC-165 /// @dev Interface identification is specified in ERC-165. This function /// uses less than 30,000 gas. /// @return `true` if the contract implements `interfaceID` and /// `interfaceID` is not 0xffffffff, `false` otherwise function supportsInterface(bytes4 interfaceID) external view returns (bool); } // src/interfaces/IERC1967Proxy.sol interface IERC1967Proxy { event Upgraded(address indexed implementation); function implementation() external view returns (address); function version() external view returns (string memory); function upgrade(address newImplementation) external payable returns (bool); function upgradeAndCall(address newImplementation, bytes calldata data) external payable returns (bool); } // lib/forge-std/src/interfaces/IERC20.sol /// @dev Interface of the ERC20 standard as defined in the EIP. /// @dev This includes the optional name, symbol, and decimals metadata. interface IERC20 { /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). event Transfer(address indexed from, address indexed to, uint256 value); /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` /// is the new allowance. event Approval(address indexed owner, address indexed spender, uint256 value); /// @notice Returns the amount of tokens in existence. function totalSupply() external view returns (uint256); /// @notice Returns the amount of tokens owned by `account`. function balanceOf(address account) external view returns (uint256); /// @notice Moves `amount` tokens from the caller's account to `to`. function transfer(address to, uint256 amount) external returns (bool); /// @notice Returns the remaining number of tokens that `spender` is allowed /// to spend on behalf of `owner` function allowance(address owner, address spender) external view returns (uint256); /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 function approve(address spender, uint256 amount) external returns (bool); /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. /// `amount` is then deducted from the caller's allowance. function transferFrom(address from, address to, uint256 amount) external returns (bool); /// @notice Returns the name of the token. function name() external view returns (string memory); /// @notice Returns the symbol of the token. function symbol() external view returns (string memory); /// @notice Returns the decimals places of the token. function decimals() external view returns (uint8); } // src/IERC721Owner.sol interface IERC721Owner { function ownerOf(uint256) external view returns (address); } // src/interfaces/IMultiCall.sol interface IMultiCall_0 { function multicall(bytes[] calldata datas) external; } // src/deployer/Nonce.sol /// @dev if you update this, you also have to update the length of the array `NonceList.List.links` in Deployer.sol type Nonce is uint32; function incr(Nonce a) pure returns (Nonce) { return Nonce.wrap(Nonce.unwrap(a) + 1); } function Nonce_gt(Nonce a, Nonce b) pure returns (bool) { return Nonce.unwrap(a) > Nonce.unwrap(b); } function Nonce_eq(Nonce a, Nonce b) pure returns (bool) { return Nonce.unwrap(a) == Nonce.unwrap(b); } function isNull_0(Nonce a) pure returns (bool) { return Nonce.unwrap(a) == 0; } using {incr, Nonce_gt as >, Nonce_eq as ==, isNull_0} for Nonce global; Nonce constant zero = Nonce.wrap(0); // src/utils/Panic.sol library Panic { function panic(uint256 code) internal pure { assembly ("memory-safe") { mstore(0x00, 0x4e487b71) // selector for `Panic(uint256)` mstore(0x20, code) revert(0x1c, 0x24) } } // https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require 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; } // src/utils/Revert.sol 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); } } } // src/deployer/Feature.sol type Feature is uint128; function Feature_eq(Feature a, Feature b) pure returns (bool) { return Feature.unwrap(a) == Feature.unwrap(b); } function isNull_1(Feature a) pure returns (bool) { return Feature.unwrap(a) == 0; } using {Feature_eq as ==, isNull_1} for Feature global; function wrap(uint256 x) pure returns (Feature) { if (x > type(uint128).max) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } if (x == 0) { Panic.panic(Panic.ENUM_CAST); } return Feature.wrap(uint128(x)); } // src/interfaces/IOwnable.sol interface IOwnable is IERC165 { event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); function owner() external view returns (address); function transferOwnership(address) external returns (bool); error PermissionDenied(); error ZeroAddress(); } // src/interfaces/ISettlerBase.sol interface ISettlerBase { struct AllowedSlippage { address payable recipient; IERC20 buyToken; uint256 minAmountOut; } } // lib/permit2/src/interfaces/ISignatureTransfer.sol /// @title SignatureTransfer /// @notice Handles ERC20 token transfers through signature based actions /// @dev Requires user's token approval on the Permit2 contract interface ISignatureTransfer is IEIP712 { /// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount /// @param maxAmount The maximum amount a spender can request to transfer error InvalidAmount(uint256 maxAmount); /// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred /// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred error LengthMismatch(); /// @notice Emits an event when the owner successfully invalidates an unordered nonce. event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask); /// @notice The token and amount details for a transfer signed in the permit transfer signature struct TokenPermissions { // ERC20 token address address token; // the maximum amount that can be spent uint256 amount; } /// @notice The signed permit message for a single token transfer struct PermitTransferFrom { TokenPermissions permitted; // a unique value for every token owner's signature to prevent signature replays uint256 nonce; // deadline on the permit signature uint256 deadline; } /// @notice Specifies the recipient address and amount for batched transfers. /// @dev Recipients and amounts correspond to the index of the signed token permissions array. /// @dev Reverts if the requested amount is greater than the permitted signed amount. struct SignatureTransferDetails { // recipient address address to; // spender requested amount uint256 requestedAmount; } /// @notice Used to reconstruct the signed permit message for multiple token transfers /// @dev Do not need to pass in spender address as it is required that it is msg.sender /// @dev Note that a user still signs over a spender address struct PermitBatchTransferFrom { // the tokens and corresponding amounts permitted for a transfer TokenPermissions[] permitted; // a unique value for every token owner's signature to prevent signature replays uint256 nonce; // deadline on the permit signature uint256 deadline; } /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce /// @dev It returns a uint256 bitmap /// @dev The index, or wordPosition is capped at type(uint248).max function nonceBitmap(address, uint256) external view returns (uint256); /// @notice Transfers a token using a signed permit message /// @dev Reverts if the requested amount is greater than the permitted signed amount /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails The spender's requested transfer details for the permitted token /// @param signature The signature to verify function permitTransferFrom( PermitTransferFrom memory permit, SignatureTransferDetails calldata transferDetails, address owner, bytes calldata signature ) external; /// @notice Transfers a token using a signed permit message /// @notice Includes extra data provided by the caller to verify signature over /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition /// @dev Reverts if the requested amount is greater than the permitted signed amount /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails The spender's requested transfer details for the permitted token /// @param witness Extra data to include when checking the user signature /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash /// @param signature The signature to verify function permitWitnessTransferFrom( PermitTransferFrom memory permit, SignatureTransferDetails calldata transferDetails, address owner, bytes32 witness, string calldata witnessTypeString, bytes calldata signature ) external; /// @notice Transfers multiple tokens using a signed permit message /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails Specifies the recipient and requested amount for the token transfer /// @param signature The signature to verify function permitTransferFrom( PermitBatchTransferFrom memory permit, SignatureTransferDetails[] calldata transferDetails, address owner, bytes calldata signature ) external; /// @notice Transfers multiple tokens using a signed permit message /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition /// @notice Includes extra data provided by the caller to verify signature over /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails Specifies the recipient and requested amount for the token transfer /// @param witness Extra data to include when checking the user signature /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash /// @param signature The signature to verify function permitWitnessTransferFrom( PermitBatchTransferFrom memory permit, SignatureTransferDetails[] calldata transferDetails, address owner, bytes32 witness, string calldata witnessTypeString, bytes calldata signature ) external; /// @notice Invalidates the bits specified in mask for the bitmap at the word position /// @dev The wordPos is maxed at type(uint248).max /// @param wordPos A number to index the nonceBitmap at /// @param mask A bitmap masked against msg.sender's current bitmap at the word position function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external; } // src/vendor/SafeTransferLib.sol /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address payable to, uint256 amount) internal { assembly ("memory-safe") { // Transfer the ETH and revert if it fails. if iszero(call(gas(), to, amount, 0x00, 0x00, 0x00, 0x00)) { let ptr := mload(0x40) returndatacopy(ptr, 0x00, returndatasize()) revert(ptr, returndatasize()) } } } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function fastBalanceOf(IERC20 token, address acct) internal view returns (uint256 r) { assembly ("memory-safe") { mstore(0x14, acct) // Store the `acct` argument. mstore(0x00, 0x70a08231000000000000000000000000) // Selector for `balanceOf(address)`, with `acct`'s padding. // Call and check for revert. Storing the selector with padding in // memory at 0 results in a start of calldata at offset 16. Calldata // is 36 bytes long (4 bytes selector, 32 bytes argument) if iszero(staticcall(gas(), token, 0x10, 0x24, 0x00, 0x20)) { let ptr := mload(0x40) returndatacopy(ptr, 0x00, returndatasize()) revert(ptr, returndatasize()) } // Check for short returndata and missing code if iszero(lt(0x1f, returndatasize())) { revert(0x00, 0x00) } r := mload(0x00) } } function safeTransferFrom(IERC20 token, address from, address to, uint256 amount) internal { assembly ("memory-safe") { let ptr := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(0x60, from)) // Store the `from` argument. (Clears `to`'s padding.) mstore(0x0c, 0x23b872dd000000000000000000000000) // Selector for `transferFrom(address,address,uint256)`, with `from`'s padding. // Calldata starts at offset 28 and is 100 bytes long (3 * 32 + 4). // If there is returndata (optional) we copy the first 32 bytes into the first slot of memory. if iszero(call(gas(), token, 0x00, 0x1c, 0x64, 0x00, 0x20)) { returndatacopy(ptr, 0x00, returndatasize()) revert(ptr, returndatasize()) } // We check that the call either returned exactly 1 [true] (can't just be non-zero // data), or had no return data. if iszero(or(and(eq(mload(0x00), 0x01), lt(0x1f, returndatasize())), iszero(returndatasize()))) { mstore(0x00, 0x7939f424) // Selector for `TransferFromFailed()` revert(0x1c, 0x04) } mstore(0x60, 0x00) // Restore the zero slot to zero. mstore(0x40, ptr) // Restore the free memory pointer. } } function safeTransfer(IERC20 token, address to, uint256 amount) internal { assembly ("memory-safe") { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. // Storing `amount` clobbers the upper bits of the free memory pointer, but those bits // can never be set without running into an OOG, so it's safe. We'll restore them to // zero at the end. mstore(0x00, 0xa9059cbb000000000000000000000000) // Selector for `transfer(address,uint256)`, with `to`'s padding. // Calldata starts at offset 16 and is 68 bytes long (2 * 32 + 4). // If there is returndata (optional) we copy the first 32 bytes into the first slot of memory. if iszero(call(gas(), token, 0x00, 0x10, 0x44, 0x00, 0x20)) { let ptr := and(0xffffff, mload(0x40)) returndatacopy(ptr, 0x00, returndatasize()) revert(ptr, returndatasize()) } // We check that the call either returned exactly 1 [true] (can't just be non-zero // data), or had no return data. if iszero(or(and(eq(mload(0x00), 0x01), lt(0x1f, returndatasize())), iszero(returndatasize()))) { mstore(0x00, 0x90b8ec18) // Selector for `TransferFailed()` revert(0x1c, 0x04) } mstore(0x34, 0x00) // Restore the part of the free memory pointer that was overwritten. } } function safeApprove(IERC20 token, address to, uint256 amount) internal { assembly ("memory-safe") { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. // Storing `amount` clobbers the upper bits of the free memory pointer, but those bits // can never be set without running into an OOG, so it's safe. We'll restore them to // zero at the end. mstore(0x00, 0x095ea7b3000000000000000000000000) // Selector for `approve(address,uint256)`, with `to`'s padding. // Calldata starts at offset 16 and is 68 bytes long (2 * 32 + 4). // If there is returndata (optional) we copy the first 32 bytes into the first slot of memory. if iszero(call(gas(), token, 0x00, 0x10, 0x44, 0x00, 0x20)) { let ptr := and(0xffffff, mload(0x40)) returndatacopy(ptr, 0x00, returndatasize()) revert(ptr, returndatasize()) } // We check that the call either returned exactly 1 [true] (can't just be non-zero // data), or had no return data. if iszero(or(and(eq(mload(0x00), 0x01), lt(0x1f, returndatasize())), iszero(returndatasize()))) { mstore(0x00, 0x3e3f8f73) // Selector for `ApproveFailed()` revert(0x1c, 0x04) } mstore(0x34, 0x00) // Restore the part of the free memory pointer that was overwritten. } } 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); } } } // src/core/SettlerErrors.sol /// @notice Thrown when an offset is not the expected value error InvalidOffset(); /// @notice Thrown when a validating a target contract to avoid certain types of targets error ConfusedDeputy(); function revertConfusedDeputy() pure { assembly ("memory-safe") { mstore(0x00, 0xe758b8d5) // selector for `ConfusedDeputy()` revert(0x1c, 0x04) } } /// @notice Thrown when a target contract is invalid given the context error InvalidTarget(); /// @notice Thrown when validating the caller against the expected caller error InvalidSender(); /// @notice Thrown in cases when using a Trusted Forwarder / AllowanceHolder is not allowed error ForwarderNotAllowed(); /// @notice Thrown when a signature length is not the expected length error InvalidSignatureLen(); /// @notice Thrown when a slippage limit is exceeded error TooMuchSlippage(IERC20 token, uint256 expected, uint256 actual); function revertTooMuchSlippage(IERC20 buyToken, uint256 expectedBuyAmount, uint256 actualBuyAmount) pure { assembly ("memory-safe") { mstore(0x54, actualBuyAmount) mstore(0x34, expectedBuyAmount) mstore(0x14, buyToken) mstore(0x00, 0x97a6f3b9000000000000000000000000) // selector for `TooMuchSlippage(address,uint256,uint256)` with `buyToken`'s padding revert(0x10, 0x64) } } /// @notice Thrown when a byte array that is supposed to encode a function from ISettlerActions is /// not recognized in context. error ActionInvalid(uint256 i, bytes4 action, bytes data); function revertActionInvalid(uint256 i, uint256 action, bytes calldata data) pure { assembly ("memory-safe") { let ptr := mload(0x40) mstore(ptr, 0x3c74eed6) // selector for `ActionInvalid(uint256,bytes4,bytes)` mstore(add(0x20, ptr), i) mstore(add(0x40, ptr), shl(0xe0, action)) // align as `bytes4` mstore(add(0x60, ptr), 0x60) // offset to the length slot of the dynamic value `data` mstore(add(0x80, ptr), data.length) calldatacopy(add(0xa0, ptr), data.offset, data.length) revert(add(0x1c, ptr), add(0x84, data.length)) } } /// @notice Thrown when the encoded fork ID as part of UniswapV3 fork path is not on the list of /// recognized forks for this chain. error UnknownForkId(uint8 forkId); function revertUnknownForkId(uint8 forkId) pure { assembly ("memory-safe") { mstore(0x00, 0xd3b1276d) // selector for `UnknownForkId(uint8)` mstore(0x20, and(0xff, forkId)) revert(0x1c, 0x24) } } /// @notice Thrown when an AllowanceHolder transfer's permit is past its deadline error SignatureExpired(uint256 deadline); /// @notice Thrown when selling the native asset, but `msg.value` exceeds the value from the generated quote error MsgValueMismatch(uint256 expected, uint256 actual); /// @notice An internal error that should never be thrown. Thrown when a callback reenters the /// entrypoint and attempts to clobber the existing callback. error ReentrantCallback(uint256 callbackInt); /// @notice An internal error that should never be thrown. This error can only be thrown by /// non-metatx-supporting Settler instances. Thrown when a callback-requiring liquidity /// source is called, but Settler never receives the callback. error CallbackNotSpent(uint256 callbackInt); /// @notice Thrown when a metatransaction has reentrancy. error ReentrantMetatransaction(bytes32 oldWitness); /// @notice Thrown when any transaction has reentrancy, not just taker-submitted or metatransaction. error ReentrantPayer(address oldPayer); /// @notice An internal error that should never be thrown. Thrown when a metatransaction fails to /// spend a coupon. error WitnessNotSpent(bytes32 oldWitness); /// @notice An internal error that should never be thrown. Thrown when the payer is unset /// unexpectedly. error PayerSpent(); error DeltaNotPositive(IERC20 token); error DeltaNotNegative(IERC20 token); error ZeroSellAmount(IERC20 token); error ZeroBuyAmount(IERC20 buyToken); error BoughtSellToken(IERC20 sellToken); error TokenHashCollision(IERC20 token0, IERC20 token1); error ZeroToken(); /// @notice Thrown for liquidities that require a Newton-Raphson approximation to solve their /// constant function when Newton-Raphson fails to converge on the solution in a /// "reasonable" number of iterations. error NotConverged(); /// @notice Thrown when the encoded pool manager ID as part of PancakeSwap Infinity fill is not on /// the list of recognized pool managers. error UnknownPoolManagerId(uint8 poolManagerId); // src/utils/Ternary.sol library Ternary { //// All the code duplication in this file is because solc isn't smart enough to figure out that //// it doesn't need to do a ton of masking when types are cast to each other without //// modification. function ternary(bool c, uint256 x, uint256 y) internal pure returns (uint256 r) { assembly ("memory-safe") { r := xor(y, mul(xor(x, y), c)) } } function ternary(bool c, int256 x, int256 y) internal pure returns (int256 r) { assembly ("memory-safe") { r := xor(y, mul(xor(x, y), c)) } } function ternary(bool c, bytes4 x, bytes4 y) internal pure returns (bytes4 r) { assembly ("memory-safe") { r := xor(y, mul(xor(x, y), c)) } } function ternary(bool c, address x, address y) internal pure returns (address r) { assembly ("memory-safe") { r := xor(y, mul(xor(x, y), c)) } } function orZero(bool c, uint256 x) internal pure returns (uint256 r) { assembly ("memory-safe") { r := mul(x, c) } } function maybeSwap(bool c, uint256 x, uint256 y) internal pure returns (uint256 a, uint256 b) { assembly ("memory-safe") { let t := mul(xor(x, y), c) a := xor(x, t) b := xor(y, t) } } function maybeSwap(bool c, int256 x, int256 y) internal pure returns (int256 a, int256 b) { assembly ("memory-safe") { let t := mul(xor(x, y), c) a := xor(x, t) b := xor(y, t) } } function maybeSwap(bool c, IERC20 x, IERC20 y) internal pure returns (IERC20 a, IERC20 b) { assembly ("memory-safe") { let t := mul(xor(x, y), c) a := xor(x, t) b := xor(y, t) } } function maybeSwap(bool c, address x, address y) internal pure returns (address a, address b) { assembly ("memory-safe") { let t := mul(xor(x, y), c) a := xor(x, t) b := xor(y, t) } } } // src/utils/UnsafeMath.sol library UnsafeMath { function unsafeInc(uint256 x) internal pure returns (uint256) { unchecked { return x + 1; } } function unsafeInc(uint256 x, bool b) internal pure returns (uint256 r) { assembly ("memory-safe") { r := add(x, b) } } function unsafeInc(int256 x) internal pure returns (int256) { unchecked { return x + 1; } } function unsafeDec(uint256 x) internal pure returns (uint256) { unchecked { return x - 1; } } function unsafeDec(uint256 x, bool b) internal pure returns (uint256 r) { assembly ("memory-safe") { r := sub(x, b) } } function unsafeDec(int256 x) internal pure returns (int256) { unchecked { return x - 1; } } function unsafeNeg(int256 x) internal pure returns (int256) { unchecked { return -x; } } function unsafeAbs(int256 x) internal pure returns (uint256 r) { assembly ("memory-safe") { r := mul(or(0x01, sar(0xff, x)), 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) } } function unsafeDivUp(uint256 n, uint256 d) internal pure returns (uint256 r) { assembly ("memory-safe") { r := add(gt(mod(n, d), 0x00), div(n, d)) } } /// rounds away from zero function unsafeDivUp(int256 n, int256 d) internal pure returns (int256 r) { assembly ("memory-safe") { r := add(mul(lt(0x00, smod(n, d)), or(0x01, sar(0xff, xor(n, d)))), sdiv(n, d)) } } function unsafeAdd(uint256 a, uint256 b) internal pure returns (uint256 r) { assembly ("memory-safe") { r := add(a, b) } } } library Math { function inc(uint256 x, bool c) internal pure returns (uint256 r) { assembly ("memory-safe") { r := add(x, c) } if (r < x) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } } function dec(uint256 x, bool c) internal pure returns (uint256 r) { assembly ("memory-safe") { r := sub(x, c) } if (r > x) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } } function toInt(bool c) internal pure returns (uint256 r) { assembly ("memory-safe") { r := c } } function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 r) { assembly ("memory-safe") { r := add(x, y) r := or(r, sub(0x00, lt(r, y))) } } function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 r) { assembly ("memory-safe") { r := mul(gt(x, y), sub(x, y)) } } function absDiff(uint256 x, uint256 y) internal pure returns (uint256 r, bool sign) { assembly ("memory-safe") { sign := lt(x, y) let m := sub(0x00, sign) r := sub(xor(sub(x, y), m), m) } } } // src/utils/512Math.sol /* WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** *** WARNING This code is unaudited WARNING *** *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING */ /// The type uint512 behaves as if it were declared as /// struct uint512 { /// uint256 hi; /// uint256 lo; /// } /// However, returning `memory` references from internal functions is impossible /// to do efficiently, especially when the functions are small and are called /// frequently. Therefore, we assume direct control over memory allocation using /// the functions `tmp()` and `alloc()` defined below. If you need to pass /// 512-bit integers between contracts (generally a bad idea), the struct /// `uint512_external` defined at the end of this file is provided for this /// purpose and has exactly the definition you'd expect (as well as convenient /// conversion functions). /// /// MAKING A DECLARATION OF THE FOLLOWING FORM WILL CAUSE UNEXPECTED BEHAVIOR: /// uint512 x; /// INSTEAD OF DOING THAT, YOU MUST USE `alloc()`, LIKE THIS: /// uint512 x = alloc(); /// IF YOU REALLY WANTED TO DO THAT (ADVANCED USAGE) THEN FOR CLARITY, WRITE THE /// FOLLOWING: /// uint512 x = tmp(); /// /// While user-defined arithmetic operations (i.e. +, -, *, %, /) are provided /// for `uint512`, they are not gas-optimal, full-featured, or composable. You /// will get a revert upon incorrect usage. Their primary usage is when a simple /// arithmetic operation needs to be performed followed by a comparison (e.g. <, /// >, ==, etc.) or conversion to a pair of `uint256`s (i.e. `.into()`). The use /// of the user-defined arithmetic operations is not composable with the usage /// of `tmp()`. /// /// In general, correct usage of `uint512` requires always specifying the output /// location of each operation. For each `o*` operation (mnemonic: /// out-of-place), the first argument is the output location and the remaining /// arguments are the input. For each `i*` operation (mnemonic: in-place), the /// first argument is both input and output and the remaining arguments are /// purely input. For each `ir*` operation (mnemonic: in-place reverse; only for /// non-commutative operations), the semantics of the input arguments are /// flipped (i.e. `irsub(foo, bar)` is semantically equivalent to `foo = bar - /// foo`); the first argument is still the output location. Only `irsub`, /// `irmod`, `irdiv`, `irmodAlt`, and `irdivAlt` exist. Unless otherwise noted, /// the return value of each function is the output location. This supports /// chaining/pipeline/tacit-style programming. /// /// All provided arithmetic operations behave as if they were inside an /// `unchecked` block. We assume that because you're reaching for 512-bit math, /// you have domain knowledge about the range of values that you will /// encounter. Overflow causes truncation, not a revert. Division or modulo by /// zero still causes a panic revert with code 18 (identical behavior to /// "normal" unchecked arithmetic). /// /// Three additional arithmetic operations are provided, bare `sub`, `mod`, and /// `div`. These are provided for use when it is known that the result of the /// operation will fit into 256 bits. This fact is not checked, but more /// efficient algorithms are employed assuming this. The result is a `uint256`. /// /// The operations `*mod` and `*div` with 512-bit denominator are `view` instead /// of `pure` because they make use of the MODEXP (5) precompile. Some EVM L2s /// and sidechains do not support MODEXP with 512-bit arguments. On those /// chains, the `*modAlt` and `*divAlt` functions are provided. These functions /// are truly `pure` and do not rely on MODEXP at all. The downside is that they /// consume slightly (really only *slightly*) more gas. /// /// ## Full list of provided functions /// /// Unless otherwise noted, all functions return `(uint512)` /// /// ### Utility /// /// * from(uint256) /// * from(uint256,uint256) -- The EVM is big-endian. The most-significant word is first. /// * from(uint512) -- performs a copy /// * into() returns (uint256,uint256) -- Again, the most-significant word is first. /// * toExternal(uint512) returns (uint512_external memory) /// /// ### Comparison (all functions return `(bool)`) /// /// * isZero(uint512) /// * isMax(uint512) /// * eq(uint512,uint256) /// * eq(uint512,uint512) /// * ne(uint512,uint256) /// * ne(uint512,uint512) /// * gt(uint512,uint256) /// * gt(uint512,uint512) /// * ge(uint512,uint256) /// * ge(uint512,uint512) /// * lt(uint512,uint256) /// * lt(uint512,uint512) /// * le(uint512,uint256) /// * le(uint512,uint512) /// /// ### Addition /// /// * oadd(uint512,uint256,uint256) -- iadd(uint256,uint256) is not provided for somewhat obvious reasons /// * oadd(uint512,uint512,uint256) /// * iadd(uint512,uint256) /// * oadd(uint512,uint512,uint512) /// * iadd(uint512,uint512) /// /// ### Subtraction /// /// * sub(uint512,uint256) returns (uint256) /// * sub(uint512,uint512) returns (uint256) /// * osub(uint512,uint512,uint256) /// * isub(uint512,uint256) /// * osub(uint512,uint512,uint512) /// * isub(uint512,uint512) /// * irsub(uint512,uint512) /// /// ### Multiplication /// /// * omul(uint512,uint256,uint256) /// * omul(uint512,uint512,uint256) /// * imul(uint512,uint256) /// * omul(uint512,uint512,uint512) /// * imul(uint512,uint512) /// /// ### Modulo /// /// * mod(uint512,uint256) returns (uint256) -- mod(uint512,uint512) is not provided for less obvious reasons /// * omod(uint512,uint512,uint512) /// * imod(uint512,uint512) /// * irmod(uint512,uint512) /// * omodAlt(uint512,uint512,uint512) /// * imodAlt(uint512,uint512) /// * irmodAlt(uint512,uint512) /// /// ### Division /// /// * div(uint512,uint256) returns (uint256) /// * div(uint512,uint512) returns (uint256) /// * odiv(uint512,uint512,uint256) /// * idiv(uint512,uint256) /// * odiv(uint512,uint512,uint512) /// * idiv(uint512,uint512) /// * irdiv(uint512,uint512) /// * divAlt(uint512,uint512) returns (uint256) -- divAlt(uint512,uint256) is not provided because div(uint512,uint256) is suitable for chains without MODEXP /// * odivAlt(uint512,uint512,uint512) /// * idivAlt(uint512,uint512) /// * irdivAlt(uint512,uint512) type uint512 is bytes32; function alloc() pure returns (uint512 r) { assembly ("memory-safe") { r := mload(0x40) mstore(0x40, add(0x40, r)) } } function tmp() pure returns (uint512 r) {} library Lib512MathAccessors { function from(uint512 r, uint256 x) internal pure returns (uint512 r_out) { assembly ("memory-safe") { mstore(r, 0x00) mstore(add(0x20, r), x) r_out := r } } function from(uint512 r, uint256 x_hi, uint256 x_lo) internal pure returns (uint512 r_out) { assembly ("memory-safe") { mstore(r, x_hi) mstore(add(0x20, r), x_lo) r_out := r } } function from(uint512 r, uint512 x) internal pure returns (uint512 r_out) { assembly ("memory-safe") { // Paradoxically, using `mload` and `mstore` here (instead of // `mcopy`) produces more optimal code because it gives solc the // opportunity to optimize-out the use of memory entirely, in // typical usage. As a happy side effect, it also means that we // don't have to deal with Cancun hardfork compatibility issues. mstore(r, mload(x)) mstore(add(0x20, r), mload(add(0x20, x))) r_out := r } } function into(uint512 x) internal pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { r_hi := mload(x) r_lo := mload(add(0x20, x)) } } } using Lib512MathAccessors for uint512 global; library Lib512MathComparisons { function isZero(uint512 x) internal pure returns (bool r) { (uint256 x_hi, uint256 x_lo) = x.into(); assembly ("memory-safe") { r := iszero(or(x_hi, x_lo)) } } function isMax(uint512 x) internal pure returns (bool r) { (uint256 x_hi, uint256 x_lo) = x.into(); assembly ("memory-safe") { r := iszero(not(and(x_hi, x_lo))) } } function eq(uint512 x, uint256 y) internal pure returns (bool r) { (uint256 x_hi, uint256 x_lo) = x.into(); assembly ("memory-safe") { r := and(iszero(x_hi), eq(x_lo, y)) } } function gt(uint512 x, uint256 y) internal pure returns (bool r) { (uint256 x_hi, uint256 x_lo) = x.into(); assembly ("memory-safe") { r := or(gt(x_hi, 0x00), gt(x_lo, y)) } } function lt(uint512 x, uint256 y) internal pure returns (bool r) { (uint256 x_hi, uint256 x_lo) = x.into(); assembly ("memory-safe") { r := and(iszero(x_hi), lt(x_lo, y)) } } function ne(uint512 x, uint256 y) internal pure returns (bool) { return !eq(x, y); } function ge(uint512 x, uint256 y) internal pure returns (bool) { return !lt(x, y); } function le(uint512 x, uint256 y) internal pure returns (bool) { return !gt(x, y); } function eq(uint512 x, uint512 y) internal pure returns (bool r) { (uint256 x_hi, uint256 x_lo) = x.into(); (uint256 y_hi, uint256 y_lo) = y.into(); assembly ("memory-safe") { r := and(eq(x_hi, y_hi), eq(x_lo, y_lo)) } } function gt(uint512 x, uint512 y) internal pure returns (bool r) { (uint256 x_hi, uint256 x_lo) = x.into(); (uint256 y_hi, uint256 y_lo) = y.into(); assembly ("memory-safe") { r := or(gt(x_hi, y_hi), and(eq(x_hi, y_hi), gt(x_lo, y_lo))) } } function lt(uint512 x, uint512 y) internal pure returns (bool r) { (uint256 x_hi, uint256 x_lo) = x.into(); (uint256 y_hi, uint256 y_lo) = y.into(); assembly ("memory-safe") { r := or(lt(x_hi, y_hi), and(eq(x_hi, y_hi), lt(x_lo, y_lo))) } } function ne(uint512 x, uint512 y) internal pure returns (bool) { return !eq(x, y); } function ge(uint512 x, uint512 y) internal pure returns (bool) { return !lt(x, y); } function le(uint512 x, uint512 y) internal pure returns (bool) { return !gt(x, y); } } using Lib512MathComparisons for uint512 global; function __eq(uint512 x, uint512 y) pure returns (bool) { return x.eq(y); } function __gt(uint512 x, uint512 y) pure returns (bool) { return x.gt(y); } function __lt(uint512 x, uint512 y) pure returns (bool r) { return x.lt(y); } function __ne(uint512 x, uint512 y) pure returns (bool) { return x.ne(y); } function __ge(uint512 x, uint512 y) pure returns (bool) { return x.ge(y); } function __le(uint512 x, uint512 y) pure returns (bool) { return x.le(y); } using {__eq as ==, __gt as >, __lt as <, __ne as !=, __ge as >=, __le as <=} for uint512 global; library Lib512MathArithmetic { using UnsafeMath for uint256; function oadd(uint512 r, uint256 x, uint256 y) internal pure returns (uint512) { uint256 r_hi; uint256 r_lo; assembly ("memory-safe") { r_lo := add(x, y) // `lt(r_lo, x)` indicates overflow in the lower addition. We can // add the bool directly to the integer to perform carry r_hi := lt(r_lo, x) } return r.from(r_hi, r_lo); } function oadd(uint512 r, uint512 x, uint256 y) internal pure returns (uint512) { (uint256 x_hi, uint256 x_lo) = x.into(); uint256 r_hi; uint256 r_lo; assembly ("memory-safe") { r_lo := add(x_lo, y) // `lt(r_lo, x_lo)` indicates overflow in the lower // addition. Overflow in the high limb is simply ignored r_hi := add(x_hi, lt(r_lo, x_lo)) } return r.from(r_hi, r_lo); } function iadd(uint512 r, uint256 y) internal pure returns (uint512) { return oadd(r, r, y); } function _add(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { r_lo := add(x_lo, y_lo) // `lt(r_lo, x_lo)` indicates overflow in the lower // addition. Overflow in the high limb is simply ignored. r_hi := add(add(x_hi, y_hi), lt(r_lo, x_lo)) } } function oadd(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) { (uint256 x_hi, uint256 x_lo) = x.into(); (uint256 y_hi, uint256 y_lo) = y.into(); (uint256 r_hi, uint256 r_lo) = _add(x_hi, x_lo, y_hi, y_lo); return r.from(r_hi, r_lo); } function iadd(uint512 r, uint512 y) internal pure returns (uint512) { return oadd(r, r, y); } function _sub(uint256 x_hi, uint256 x_lo, uint256 y) private pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { r_lo := sub(x_lo, y) // `gt(r_lo, x_lo)` indicates underflow in the lower subtraction. We // can subtract the bool directly from the integer to perform carry. r_hi := sub(x_hi, gt(r_lo, x_lo)) } } function osub(uint512 r, uint512 x, uint256 y) internal pure returns (uint512) { (uint256 x_hi, uint256 x_lo) = x.into(); (uint256 r_hi, uint256 r_lo) = _sub(x_hi, x_lo, y); return r.from(r_hi, r_lo); } function isub(uint512 r, uint256 y) internal pure returns (uint512) { return osub(r, r, y); } function _sub(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { r_lo := sub(x_lo, y_lo) // `gt(r_lo, x_lo)` indicates underflow in the lower subtraction. // Underflow in the high limb is simply ignored. r_hi := sub(sub(x_hi, y_hi), gt(r_lo, x_lo)) } } function osub(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) { (uint256 x_hi, uint256 x_lo) = x.into(); (uint256 y_hi, uint256 y_lo) = y.into(); (uint256 r_hi, uint256 r_lo) = _sub(x_hi, x_lo, y_hi, y_lo); return r.from(r_hi, r_lo); } function isub(uint512 r, uint512 y) internal pure returns (uint512) { return osub(r, r, y); } function irsub(uint512 r, uint512 y) internal pure returns (uint512) { return osub(r, y, r); } function sub(uint512 x, uint256 y) internal pure returns (uint256 r) { assembly ("memory-safe") { r := sub(mload(add(0x20, x)), y) } } function sub(uint512 x, uint512 y) internal pure returns (uint256 r) { assembly ("memory-safe") { r := sub(mload(add(0x20, x)), mload(add(0x20, y))) } } //// The technique implemented in the following functions for multiplication is //// adapted from Remco Bloemen's work https://2π.com/17/full-mul/ . //// The original code was released under the MIT license. function _mul(uint256 x, uint256 y) private pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { let mm := mulmod(x, y, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) r_lo := mul(x, y) r_hi := sub(sub(mm, r_lo), lt(mm, r_lo)) } } function omul(uint512 r, uint256 x, uint256 y) internal pure returns (uint512) { (uint256 r_hi, uint256 r_lo) = _mul(x, y); return r.from(r_hi, r_lo); } function _mul(uint256 x_hi, uint256 x_lo, uint256 y) private pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { let mm := mulmod(x_lo, y, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) r_lo := mul(x_lo, y) r_hi := add(mul(x_hi, y), sub(sub(mm, r_lo), lt(mm, r_lo))) } } function omul(uint512 r, uint512 x, uint256 y) internal pure returns (uint512) { (uint256 x_hi, uint256 x_lo) = x.into(); (uint256 r_hi, uint256 r_lo) = _mul(x_hi, x_lo, y); return r.from(r_hi, r_lo); } function imul(uint512 r, uint256 y) internal pure returns (uint512) { return omul(r, r, y); } function _mul(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { let mm := mulmod(x_lo, y_lo, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) r_lo := mul(x_lo, y_lo) r_hi := add(add(mul(x_hi, y_lo), mul(x_lo, y_hi)), sub(sub(mm, r_lo), lt(mm, r_lo))) } } function omul(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) { (uint256 x_hi, uint256 x_lo) = x.into(); (uint256 y_hi, uint256 y_lo) = y.into(); (uint256 r_hi, uint256 r_lo) = _mul(x_hi, x_lo, y_hi, y_lo); return r.from(r_hi, r_lo); } function imul(uint512 r, uint512 y) internal pure returns (uint512) { return omul(r, r, y); } function mod(uint512 n, uint256 d) internal pure returns (uint256 r) { if (d == 0) { Panic.panic(Panic.DIVISION_BY_ZERO); } (uint256 n_hi, uint256 n_lo) = n.into(); assembly ("memory-safe") { r := mulmod(n_hi, sub(0x00, d), d) r := addmod(n_lo, r, d) } } function omod(uint512 r, uint512 x, uint512 y) internal view returns (uint512) { (uint256 x_hi, uint256 x_lo) = x.into(); (uint256 y_hi, uint256 y_lo) = y.into(); assembly ("memory-safe") { // We use the MODEXP (5) precompile with an exponent of 1. We encode // the arguments to the precompile at the beginning of free memory // without allocating. Arguments are encoded as: // [64 32 64 x_hi x_lo 1 y_hi y_lo] let ptr := mload(0x40) mstore(ptr, 0x40) mstore(add(0x20, ptr), 0x20) mstore(add(0x40, ptr), 0x40) // See comment in `from` about why `mstore` is more efficient than `mcopy` mstore(add(0x60, ptr), x_hi) mstore(add(0x80, ptr), x_lo) mstore(add(0xa0, ptr), 0x01) mstore(add(0xc0, ptr), y_hi) mstore(add(0xe0, ptr), y_lo) // We write the result of MODEXP directly into the output space r. pop(staticcall(gas(), 0x05, ptr, 0x100, r, 0x40)) // The MODEXP precompile can only fail due to out-of-gas. This call // consumes only 200 gas, so if it failed, there is only 4 gas // remaining in this context. Therefore, we will out-of-gas // immediately when we attempt to read the result. We don't bother // to check for failure. } return r; } function imod(uint512 r, uint512 y) internal view returns (uint512) { return omod(r, r, y); } function irmod(uint512 r, uint512 y) internal view returns (uint512) { return omod(r, y, r); } /// Multiply 512-bit [x_hi x_lo] by 256-bit [y] giving 768-bit [r_ex r_hi r_lo] function _mul768(uint256 x_hi, uint256 x_lo, uint256 y) private pure returns (uint256 r_ex, uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { let mm0 := mulmod(x_lo, y, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) r_lo := mul(x_lo, y) let mm1 := mulmod(x_hi, y, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) let r_partial := mul(x_hi, y) r_ex := sub(sub(mm1, r_partial), lt(mm1, r_partial)) r_hi := add(r_partial, sub(sub(mm0, r_lo), lt(mm0, r_lo))) // `lt(r_hi, r_partial)` indicates overflow in the addition to form // `r_hi`. We can add the bool directly to the integer to perform // carry. r_ex := add(r_ex, lt(r_hi, r_partial)) } } //// The technique implemented in the following functions for division is //// adapted from Remco Bloemen's work https://2π.com/21/muldiv/ . //// The original code was released under the MIT license. function _roundDown(uint256 x_hi, uint256 x_lo, uint256 d) private pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { // Get the remainder [n_hi n_lo] % d (< 2²⁵⁶ - 1) // 2**256 % d = -d % 2**256 % d -- https://2π.com/17/512-bit-division/ let rem := mulmod(x_hi, sub(0x00, d), d) rem := addmod(x_lo, rem, d) r_hi := sub(x_hi, gt(rem, x_lo)) r_lo := sub(x_lo, rem) } } function _roundDown(uint256 x_hi, uint256 x_lo, uint256 d_hi, uint256 d_lo) private view returns (uint256 r_hi, uint256 r_lo) { uint512 r; assembly ("memory-safe") { // We point `r` to the beginning of free memory WITHOUT allocating. // This is not technically "memory-safe" because solc might use that // memory for something in between the end of this assembly block // and the beginning of the call to `into()`, but empirically and // practically speaking that won't and doesn't happen. We save some // gas by not bumping the free pointer. r := mload(0x40) // Get the remainder [x_hi x_lo] % [d_hi d_lo] (< 2⁵¹² - 1) We use // the MODEXP (5) precompile with an exponent of 1. We encode the // arguments to the precompile at the beginning of free memory // without allocating. Conveniently, `r` already points to this // region. Arguments are encoded as: // [64 32 64 x_hi x_lo 1 d_hi d_lo] mstore(r, 0x40) mstore(add(0x20, r), 0x20) mstore(add(0x40, r), 0x40) mstore(add(0x60, r), x_hi) mstore(add(0x80, r), x_lo) mstore(add(0xa0, r), 0x01) mstore(add(0xc0, r), d_hi) mstore(add(0xe0, r), d_lo) // The MODEXP precompile can only fail due to out-of-gas. This call // consumes only 200 gas, so if it failed, there is only 4 gas // remaining in this context. Therefore, we will out-of-gas // immediately when we attempt to read the result. We don't bother // to check for failure. pop(staticcall(gas(), 0x05, r, 0x100, r, 0x40)) } (uint256 rem_hi, uint256 rem_lo) = r.into(); // Round down by subtracting the remainder from the numerator (r_hi, r_lo) = _sub(x_hi, x_lo, rem_hi, rem_lo); } function _twos(uint256 x) private pure returns (uint256 twos, uint256 twosInv) { assembly ("memory-safe") { // Compute largest power of two divisor of `x`. `x` is nonzero, so // this is always ≥ 1. twos := and(sub(0x00, x), x) // To shift up (bits from the high limb into the low limb) we need // the inverse of `twos`. That is, 2²⁵⁶ / twos. // 2**256 / twos = -twos % 2**256 / twos + 1 -- https://2π.com/17/512-bit-division/ // If `twos` is zero, then `twosInv` becomes one (not possible) twosInv := add(div(sub(0x00, twos), twos), 0x01) } } function _toOdd256(uint256 x_hi, uint256 x_lo, uint256 y) private pure returns (uint256 x_lo_out, uint256 y_out) { // Factor powers of two out of `y` and apply the same shift to [x_hi // x_lo] (uint256 twos, uint256 twosInv) = _twos(y); assembly ("memory-safe") { // Divide `y` by the power of two y_out := div(y, twos) // Divide [x_hi x_lo] by the power of two x_lo_out := or(div(x_lo, twos), mul(x_hi, twosInv)) } } function _toOdd256(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (uint256 x_lo_out, uint256 y_lo_out) { // Factor powers of two out of `y_lo` and apply the same shift to `x_lo` (uint256 twos, uint256 twosInv) = _twos(y_lo); assembly ("memory-safe") { // Divide [y_hi y_lo] by the power of two, returning only the low limb y_lo_out := or(div(y_lo, twos), mul(y_hi, twosInv)) // Divide [x_hi x_lo] by the power of two, returning only the low limb x_lo_out := or(div(x_lo, twos), mul(x_hi, twosInv)) } } function _toOdd512(uint256 x_hi, uint256 x_lo, uint256 y) private pure returns (uint256 x_hi_out, uint256 x_lo_out, uint256 y_out) { // Factor powers of two out of `y` and apply the same shift to [x_hi // x_lo] (uint256 twos, uint256 twosInv) = _twos(y); assembly ("memory-safe") { // Divide `y` by the power of two y_out := div(y, twos) // Divide [x_hi x_lo] by the power of two x_hi_out := div(x_hi, twos) x_lo_out := or(div(x_lo, twos), mul(x_hi, twosInv)) } } function _toOdd512(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (uint256 x_hi_out, uint256 x_lo_out, uint256 y_hi_out, uint256 y_lo_out) { // Factor powers of two out of [y_hi y_lo] and apply the same shift to // [x_hi x_lo] and [y_hi y_lo] (uint256 twos, uint256 twosInv) = _twos(y_lo); assembly ("memory-safe") { // Divide [y_hi y_lo] by the power of two y_hi_out := div(y_hi, twos) y_lo_out := or(div(y_lo, twos), mul(y_hi, twosInv)) // Divide [x_hi x_lo] by the power of two x_hi_out := div(x_hi, twos) x_lo_out := or(div(x_lo, twos), mul(x_hi, twosInv)) } } function _invert256(uint256 d) private pure returns (uint256 inv) { assembly ("memory-safe") { // Invert `d` mod 2²⁵⁶ -- https://2π.com/18/multiplitcative-inverses/ // `d` is an odd number (from _toOdd*). It has an inverse modulo // 2²⁵⁶ such that d * inv ≡ 1 mod 2²⁵⁶. // We use Newton-Raphson iterations compute inv. Thanks to Hensel's // lifting lemma, this also works in modular arithmetic, doubling // the correct bits in each step. The Newton-Raphson-Hensel step is: // inv_{n+1} = inv_n * (2 - d*inv_n) % 2**512 // To kick off Newton-Raphson-Hensel iterations, we start with a // seed of the inverse that is correct correct for four bits. // d * inv ≡ 1 mod 2⁴ inv := xor(mul(0x03, d), 0x02) // Each Newton-Raphson-Hensel step doubles the number of correct // bits in `inv`. After 6 iterations, full convergence is // guaranteed. inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2⁸ inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2¹⁶ inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2³² inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2⁶⁴ inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2¹²⁸ inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2²⁵⁶ } } function _invert512(uint256 d) private pure returns (uint256 inv_hi, uint256 inv_lo) { // First, we get the inverse of `d` mod 2²⁵⁶ inv_lo = _invert256(d); // To extend this to the inverse mod 2⁵¹², we perform a more elaborate // 7th Newton-Raphson-Hensel iteration with 512 bits of precision. // tmp = d * inv_lo % 2**512 (uint256 tmp_hi, uint256 tmp_lo) = _mul(d, inv_lo); // tmp = 2 - tmp % 2**512 (tmp_hi, tmp_lo) = _sub(0, 2, tmp_hi, tmp_lo); assembly ("memory-safe") { // inv_hi = inv_lo * tmp / 2**256 % 2**256 let mm := mulmod(inv_lo, tmp_lo, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) inv_hi := add(mul(inv_lo, tmp_hi), sub(sub(mm, inv_lo), lt(mm, inv_lo))) } } function _invert512(uint256 d_hi, uint256 d_lo) private pure returns (uint256 inv_hi, uint256 inv_lo) { // First, we get the inverse of `d` mod 2²⁵⁶ inv_lo = _invert256(d_lo); // To extend this to the inverse mod 2⁵¹², we perform a more elaborate // 7th Newton-Raphson-Hensel iteration with 512 bits of precision. // tmp = d * inv_lo % 2**512 (uint256 tmp_hi, uint256 tmp_lo) = _mul(d_hi, d_lo, inv_lo); // tmp = 2 - tmp % 2**512 (tmp_hi, tmp_lo) = _sub(0, 2, tmp_hi, tmp_lo); assembly ("memory-safe") { // inv_hi = inv_lo * tmp / 2**256 % 2**256 let mm := mulmod(inv_lo, tmp_lo, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) inv_hi := add(mul(inv_lo, tmp_hi), sub(sub(mm, inv_lo), lt(mm, inv_lo))) } } function div(uint512 n, uint256 d) internal pure returns (uint256) { if (d == 0) { Panic.panic(Panic.DIVISION_BY_ZERO); } (uint256 n_hi, uint256 n_lo) = n.into(); if (n_hi == 0) { return n_lo.unsafeDiv(d); } // Round the numerator down to a multiple of the denominator. This makes // the division exact without affecting the result. (n_hi, n_lo) = _roundDown(n_hi, n_lo, d); // Make `d` odd so that it has a multiplicative inverse mod 2²⁵⁶ // After this we can discard `n_hi` because our result is only 256 bits (n_lo, d) = _toOdd256(n_hi, n_lo, d); // We perform division by multiplying by the multiplicative inverse of // the denominator mod 2²⁵⁶. Since `d` is odd, this inverse // exists. Compute that inverse d = _invert256(d); unchecked { // Because the division is now exact (we rounded `n` down to a // multiple of `d`), we perform it by multiplying with the modular // inverse of the denominator. This is the correct result mod 2²⁵⁶. return n_lo * d; } } function _gt(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (bool r) { assembly ("memory-safe") { r := or(gt(x_hi, y_hi), and(eq(x_hi, y_hi), gt(x_lo, y_lo))) } } function div(uint512 n, uint512 d) internal view returns (uint256) { (uint256 d_hi, uint256 d_lo) = d.into(); if (d_hi == 0) { return div(n, d_lo); } (uint256 n_hi, uint256 n_lo) = n.into(); if (d_lo == 0) { return n_hi.unsafeDiv(d_hi); } if (_gt(d_hi, d_lo, n_hi, n_lo)) { // TODO: this optimization may not be overall optimizing return 0; } // Round the numerator down to a multiple of the denominator. This makes // the division exact without affecting the result. (n_hi, n_lo) = _roundDown(n_hi, n_lo, d_hi, d_lo); // Make `d_lo` odd so that it has a multiplicative inverse mod 2²⁵⁶ // After this we can discard `n_hi` and `d_hi` because our result is // only 256 bits (n_lo, d_lo) = _toOdd256(n_hi, n_lo, d_hi, d_lo); // We perform division by multiplying by the multiplicative inverse of // the denominator mod 2²⁵⁶. Since `d_lo` is odd, this inverse // exists. Compute that inverse d_lo = _invert256(d_lo); unchecked { // Because the division is now exact (we rounded `n` down to a // multiple of `d`), we perform it by multiplying with the modular // inverse of the denominator. This is the correct result mod 2²⁵⁶. return n_lo * d_lo; } } function odiv(uint512 r, uint512 x, uint256 y) internal pure returns (uint512) { if (y == 0) { Panic.panic(Panic.DIVISION_BY_ZERO); } (uint256 x_hi, uint256 x_lo) = x.into(); if (x_hi == 0) { return r.from(0, x_lo.unsafeDiv(y)); } // Round the numerator down to a multiple of the denominator. This makes // the division exact without affecting the result. (x_hi, x_lo) = _roundDown(x_hi, x_lo, y); // Make `y` odd so that it has a multiplicative inverse mod 2⁵¹² (x_hi, x_lo, y) = _toOdd512(x_hi, x_lo, y); // We perform division by multiplying by the multiplicative inverse of // the denominator mod 2⁵¹². Since `y` is odd, this inverse // exists. Compute that inverse (uint256 inv_hi, uint256 inv_lo) = _invert512(y); // Because the division is now exact (we rounded `x` down to a multiple // of `y`), we perform it by multiplying with the modular inverse of the // denominator. (uint256 r_hi, uint256 r_lo) = _mul(x_hi, x_lo, inv_hi, inv_lo); return r.from(r_hi, r_lo); } function idiv(uint512 r, uint256 y) internal pure returns (uint512) { return odiv(r, r, y); } function odiv(uint512 r, uint512 x, uint512 y) internal view returns (uint512) { (uint256 y_hi, uint256 y_lo) = y.into(); if (y_hi == 0) { return odiv(r, x, y_lo); } (uint256 x_hi, uint256 x_lo) = x.into(); if (y_lo == 0) { return r.from(0, x_hi.unsafeDiv(y_hi)); } if (_gt(y_hi, y_lo, x_hi, x_lo)) { // TODO: this optimization may not be overall optimizing return r.from(0, 0); } // Round the numerator down to a multiple of the denominator. This makes // the division exact without affecting the result. (x_hi, x_lo) = _roundDown(x_hi, x_lo, y_hi, y_lo); // Make `y` odd so that it has a multiplicative inverse mod 2⁵¹² (x_hi, x_lo, y_hi, y_lo) = _toOdd512(x_hi, x_lo, y_hi, y_lo); // We perform division by multiplying by the multiplicative inverse of // the denominator mod 2⁵¹². Since `y` is odd, this inverse // exists. Compute that inverse (y_hi, y_lo) = _invert512(y_hi, y_lo); // Because the division is now exact (we rounded `x` down to a multiple // of `y`), we perform it by multiplying with the modular inverse of the // denominator. (uint256 r_hi, uint256 r_lo) = _mul(x_hi, x_lo, y_hi, y_lo); return r.from(r_hi, r_lo); } function idiv(uint512 r, uint512 y) internal view returns (uint512) { return odiv(r, r, y); } function irdiv(uint512 r, uint512 y) internal view returns (uint512) { return odiv(r, y, r); } function _gt(uint256 x_ex, uint256 x_hi, uint256 x_lo, uint256 y_ex, uint256 y_hi, uint256 y_lo) private pure returns (bool r) { assembly ("memory-safe") { r := or( or(gt(x_ex, y_ex), and(eq(x_ex, y_ex), gt(x_hi, y_hi))), and(and(eq(x_ex, y_ex), eq(x_hi, y_hi)), gt(x_lo, y_lo)) ) } } /// The technique implemented in the following helper function for Knuth /// Algorithm D (a modification of the citation further below) is adapted /// from ridiculous fish's (aka corydoras) work /// https://ridiculousfish.com/blog/posts/labor-of-division-episode-iv.html /// and /// https://ridiculousfish.com/blog/posts/labor-of-division-episode-v.html . function _correctQ(uint256 q, uint256 r, uint256 x_next, uint256 y_next, uint256 y_whole) private pure returns (uint256 q_out) { assembly ("memory-safe") { let c1 := mul(q, y_next) let c2 := or(shl(0x80, r), x_next) q_out := sub(q, shl(gt(sub(c1, c2), y_whole), gt(c1, c2))) } } /// The technique implemented in the following function for division is /// adapted from Donald Knuth, The Art of Computer Programming (TAOCP) /// Volume 2, Section 4.3.1, Algorithm D. function _algorithmD(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (uint256 q) { // We treat `x` and `y` each as ≤4-limb bigints where each limb is half // a machine word (128 bits). This lets us perform 2-limb ÷ 1-limb // divisions as a single operation (`div`) as required by Algorithm // D. It also simplifies/optimizes some of the multiplications. if (y_hi >> 128 != 0) { // y is 4 limbs, x is 4 limbs, q is 1 limb // Normalize. Ensure the uppermost limb of y ≥ 2¹²⁷ (equivalently // y_hi >= 2**255). This is step D1 of Algorithm D // The author's copy of TAOCP (3rd edition) states to set `d = (2 ** // 128 - 1) // y_hi`, however this is incorrect. Setting `d` in this // fashion may result in overflow in the subsequent `_mul`. Setting // `d` as implemented below still satisfies the postcondition (`y_hi // >> 128 >= 1 << 127`) but never results in overflow. uint256 d = uint256(1 << 128).unsafeDiv((y_hi >> 128).unsafeInc()); uint256 x_ex; (x_ex, x_hi, x_lo) = _mul768(x_hi, x_lo, d); (y_hi, y_lo) = _mul(y_hi, y_lo, d); // `n_approx` is the 2 most-significant limbs of x, after // normalization uint256 n_approx = (x_ex << 128) | (x_hi >> 128); // `d_approx` is the most significant limb of y, after normalization uint256 d_approx = y_hi >> 128; // Normalization ensures that result of this division is an // approximation of the most significant (and only) limb of the // quotient and is too high by at most 3. This is the "Calculate // q-hat" (D3) step of Algorithm D. (did you know that U+0302, // COMBINING CIRCUMFLEX ACCENT cannot be combined with q? shameful) q = n_approx.unsafeDiv(d_approx); uint256 r_hat = n_approx.unsafeMod(d_approx); // The process of `_correctQ` subtracts up to 2 from `q`, to make it // more accurate. This is still part of the "Calculate q-hat" (D3) // step of Algorithm D. q = _correctQ(q, r_hat, x_hi & type(uint128).max, y_hi & type(uint128).max, y_hi); // This final, low-probability, computationally-expensive correction // conditionally subtracts 1 from `q` to make it exactly the // most-significant limb of the quotient. This is the "Multiply and // subtract" (D4), "Test remainder" (D5), and "Add back" (D6) steps // of Algorithm D, with substantial shortcutting { (uint256 tmp_ex, uint256 tmp_hi, uint256 tmp_lo) = _mul768(y_hi, y_lo, q); bool neg = _gt(tmp_ex, tmp_hi, tmp_lo, x_ex, x_hi, x_lo); assembly ("memory-safe") { q := sub(q, neg) } } } else { // y is 3 limbs // Normalize. Ensure the most significant limb of y ≥ 2¹²⁷ (step D1) // See above comment about the error in TAOCP. uint256 d = uint256(1 << 128).unsafeDiv(y_hi.unsafeInc()); (y_hi, y_lo) = _mul(y_hi, y_lo, d); // `y_next` is the second-most-significant, nonzero, normalized limb // of y uint256 y_next = y_lo >> 128; // `y_whole` is the 2 most-significant, nonzero, normalized limbs of // y uint256 y_whole = (y_hi << 128) | y_next; if (x_hi >> 128 != 0) { // x is 4 limbs, q is 2 limbs // Finish normalizing (step D1) uint256 x_ex; (x_ex, x_hi, x_lo) = _mul768(x_hi, x_lo, d); uint256 n_approx = (x_ex << 128) | (x_hi >> 128); // As before, `q_hat` is the most significant limb of the // quotient and too high by at most 3 (step D3) uint256 q_hat = n_approx.unsafeDiv(y_hi); uint256 r_hat = n_approx.unsafeMod(y_hi); // Subtract up to 2 from `q_hat`, improving our estimate (step // D3) q_hat = _correctQ(q_hat, r_hat, x_hi & type(uint128).max, y_next, y_whole); q = q_hat << 128; { // "Multiply and subtract" (D4) step of Algorithm D (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat); uint256 tmp_ex = tmp_hi >> 128; tmp_hi = (tmp_hi << 128) | (tmp_lo >> 128); tmp_lo <<= 128; // "Test remainder" (D5) step of Algorithm D bool neg = _gt(tmp_ex, tmp_hi, tmp_lo, x_ex, x_hi, x_lo); // Finish step D4 (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo); // "Add back" (D6) step of Algorithm D if (neg) { // This branch is quite rare, so it's gas-advantageous // to actually branch and usually skip the costly `_add` unchecked { q -= 1 << 128; } (x_hi, x_lo) = _add(x_hi, x_lo, y_whole, y_lo << 128); } } // `x_ex` is now zero (implicitly) // Run another loop (steps D3 through D6) of Algorithm D to get // the lower limb of the quotient q_hat = x_hi.unsafeDiv(y_hi); r_hat = x_hi.unsafeMod(y_hi); q_hat = _correctQ(q_hat, r_hat, x_lo >> 128, y_next, y_whole); { (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat); bool neg = _gt(tmp_hi, tmp_lo, x_hi, x_lo); assembly ("memory-safe") { q_hat := sub(q_hat, neg) } } q |= q_hat; } else { // x is 3 limbs, q is 1 limb // Finish normalizing (step D1) (x_hi, x_lo) = _mul(x_hi, x_lo, d); // `q` is the most significant (and only) limb of the quotient // and too high by at most 3 (step D3) q = x_hi.unsafeDiv(y_hi); uint256 r_hat = x_hi.unsafeMod(y_hi); // Subtract up to 2 from `q`, improving our estimate (step D3) q = _correctQ(q, r_hat, x_lo >> 128, y_next, y_whole); // Subtract up to 1 from `q` to make it exact (steps D4 through // D6) { (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q); bool neg = _gt(tmp_hi, tmp_lo, x_hi, x_lo); assembly ("memory-safe") { q := sub(q, neg) } } } } // All other cases are handled by the checks that y ≥ 2²⁵⁶ (equivalently // y_hi != 0) and that x ≥ y } /// Modified from Solady (https://github.com/Vectorized/solady/blob/a3d6a974f9c9f00dcd95b235619a209a63c61d94/src/utils/LibBit.sol#L33-L45) /// The original code was released under the MIT license. function _clzLower(uint256 x) private pure returns (uint256 r) { assembly ("memory-safe") { r := shl(0x06, lt(0xffffffffffffffff, x)) r := or(r, shl(0x05, lt(0xffffffff, shr(r, x)))) r := or(r, shl(0x04, lt(0xffff, shr(r, x)))) r := or(r, shl(0x03, lt(0xff, shr(r, x)))) // We use a 5-bit deBruijn Sequence to convert `x`'s 8 // most-significant bits into an index. We then index the lookup // table (bytewise) by the deBruijn symbol to obtain the bitwise // inverse of its logarithm. r := xor( r, byte( and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x7879797a797d7a7b797d7c7d7a7b7c7e797a7d7a7c7c7b7e7a7a7c7b7f7f7f7f ) ) } } function _clzUpper(uint256 x) private pure returns (uint256) { return _clzLower(x >> 128); } function _shl(uint256 x_hi, uint256 x_lo, uint256 s) private pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { r_hi := or(shl(s, x_hi), shr(sub(0x100, s), x_lo)) r_lo := shl(s, x_lo) } } function _shl768(uint256 x_hi, uint256 x_lo, uint256 s) private pure returns (uint256 r_ex, uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { let neg_s := sub(0x100, s) r_ex := shr(neg_s, x_hi) r_hi := or(shl(s, x_hi), shr(neg_s, x_lo)) r_lo := shl(s, x_lo) } } function _shr(uint256 x_hi, uint256 x_lo, uint256 s) private pure returns (uint256 r_hi, uint256 r_lo) { assembly ("memory-safe") { r_hi := shr(s, x_hi) r_lo := or(shl(sub(0x100, s), x_hi), shr(s, x_lo)) } } // This function is a different modification of Knuth's Algorithm D. In this // case, we're only interested in the (normalized) remainder instead of the // quotient. We also substitute the normalization by division for // normalization by shifting because it makes un-normalization more // gas-efficient. function _algorithmDRemainder(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (uint256, uint256) { // We treat `x` and `y` each as ≤4-limb bigints where each limb is half // a machine word (128 bits). This lets us perform 2-limb ÷ 1-limb // divisions as a single operation (`div`) as required by Algorithm D. uint256 s; if (y_hi >> 128 != 0) { // y is 4 limbs, x is 4 limbs // Normalize. Ensure the uppermost limb of y ≥ 2¹²⁷ (equivalently // y_hi >= 2**255). This is step D1 of Algorithm D Unlike the // preceeding implementation of Algorithm D, we use a binary shift // instead of a multiply to normalize. This performs a costly "count // leading zeroes" operation, but it lets us transform an // even-more-costly division-by-inversion operation later into a // simple shift. This still ultimately satisfies the postcondition // (y_hi >> 128 >= 1 << 127) without overflowing. s = _clzUpper(y_hi); uint256 x_ex; (x_ex, x_hi, x_lo) = _shl768(x_hi, x_lo, s); (y_hi, y_lo) = _shl(y_hi, y_lo, s); // `n_approx` is the 2 most-significant limbs of x, after // normalization uint256 n_approx = (x_ex << 128) | (x_hi >> 128); // TODO: this can probably be optimized (combined with `_shl`) // `d_approx` is the most significant limb of y, after normalization uint256 d_approx = y_hi >> 128; // TODO: this can probably be optimized (combined with `_shl`) // Normalization ensures that result of this division is an // approximation of the most significant (and only) limb of the // quotient and is too high by at most 3. This is the "Calculate // q-hat" (D3) step of Algorithm D. (did you know that U+0302, // COMBINING CIRCUMFLEX ACCENT cannot be combined with q? shameful) uint256 q_hat = n_approx.unsafeDiv(d_approx); uint256 r_hat = n_approx.unsafeMod(d_approx); // The process of `_correctQ` subtracts up to 2 from `q_hat`, to // make it more accurate. This is still part of the "Calculate // q-hat" (D3) step of Algorithm D. q_hat = _correctQ(q_hat, r_hat, x_hi & type(uint128).max, y_hi & type(uint128).max, y_hi); { // This penultimate correction subtracts q-hat × y from x to // obtain the normalized remainder. This is the "Multiply and // subtract" (D4) and "Test remainder" (D5) steps of Algorithm // D, with some shortcutting (uint256 tmp_ex, uint256 tmp_hi, uint256 tmp_lo) = _mul768(y_hi, y_lo, q_hat); bool neg = _gt(tmp_ex, tmp_hi, tmp_lo, x_ex, x_hi, x_lo); (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo); // `x_ex` is now implicitly zero (or signals a carry that we // will clear in the next step) // Because `q_hat` may be too high by 1, we have to detect // underflow from the previous step and correct it. This is the // "Add back" (D6) step of Algorithm D if (neg) { (x_hi, x_lo) = _add(x_hi, x_lo, y_hi, y_lo); } } } else { // y is 3 limbs // Normalize. Ensure the most significant limb of y ≥ 2¹²⁷ (step D1) // See above comment about the use of a shift instead of division. s = _clzLower(y_hi); (y_hi, y_lo) = _shl(y_hi, y_lo, s); // `y_next` is the second-most-significant, nonzero, normalized limb // of y uint256 y_next = y_lo >> 128; // TODO: this can probably be optimized (combined with `_shl`) // `y_whole` is the 2 most-significant, nonzero, normalized limbs of // y uint256 y_whole = (y_hi << 128) | y_next; // TODO: this can probably be optimized (combined with `_shl`) if (x_hi >> 128 != 0) { // x is 4 limbs; we have to run 2 iterations of Algorithm D to // fully divide out by y // Finish normalizing (step D1) uint256 x_ex; (x_ex, x_hi, x_lo) = _shl768(x_hi, x_lo, s); uint256 n_approx = (x_ex << 128) | (x_hi >> 128); // TODO: this can probably be optimized (combined with `_shl768`) // As before, `q_hat` is the most significant limb of the // quotient and too high by at most 3 (step D3) uint256 q_hat = n_approx.unsafeDiv(y_hi); uint256 r_hat = n_approx.unsafeMod(y_hi); // Subtract up to 2 from `q_hat`, improving our estimate (step // D3) q_hat = _correctQ(q_hat, r_hat, x_hi & type(uint128).max, y_next, y_whole); // Subtract up to 1 from q-hat to make it exactly the // most-significant limb of the quotient and subtract q-hat × y // from x to clear the most-significant limb of x. { // "Multiply and subtract" (D4) step of Algorithm D (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat); uint256 tmp_ex = tmp_hi >> 128; tmp_hi = (tmp_hi << 128) | (tmp_lo >> 128); tmp_lo <<= 128; // "Test remainder" (D5) step of Algorithm D bool neg = _gt(tmp_ex, tmp_hi, tmp_lo, x_ex, x_hi, x_lo); // Finish step D4 (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo); // "Add back" (D6) step of Algorithm D. We implicitly // subtract 1 from `q_hat`, but elide explicitly // representing that because `q_hat` is no longer needed. if (neg) { // This branch is quite rare, so it's gas-advantageous // to actually branch and usually skip the costly `_add` (x_hi, x_lo) = _add(x_hi, x_lo, y_whole, y_lo << 128); } } // `x_ex` is now zero (implicitly) // [x_hi x_lo] now represents the partial, normalized remainder. // Run another loop (steps D3 through D6) of Algorithm D to get // the lower limb of the quotient // Step D3 q_hat = x_hi.unsafeDiv(y_hi); r_hat = x_hi.unsafeMod(y_hi); // Step D3 q_hat = _correctQ(q_hat, r_hat, x_lo >> 128, y_next, y_whole); // Again, implicitly correct q-hat to make it exactly the // least-significant limb of the quotient. Subtract q-hat × y // from x to obtain the normalized remainder. { // Steps D4 and D5 (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat); bool neg = _gt(tmp_hi, tmp_lo, x_hi, x_lo); (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo); // Step D6 if (neg) { (x_hi, x_lo) = _add(x_hi, x_lo, y_hi, y_lo); } } } else { // x is 3 limbs // Finish normalizing (step D1) (x_hi, x_lo) = _shl(x_hi, x_lo, s); // `q_hat` is the most significant (and only) limb of the // quotient and too high by at most 3 (step D3) uint256 q_hat = x_hi.unsafeDiv(y_hi); uint256 r_hat = x_hi.unsafeMod(y_hi); // Subtract up to 2 from `q_hat`, improving our estimate (step // D3) q_hat = _correctQ(q_hat, r_hat, x_lo >> 128, y_next, y_whole); // Make `q_hat` exact (implicitly) and subtract q-hat × y from x // to obtain the normalized remainder. (steps D4 through D6) { (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat); bool neg = _gt(tmp_hi, tmp_lo, x_hi, x_lo); (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo); if (neg) { (x_hi, x_lo) = _add(x_hi, x_lo, y_hi, y_lo); } } } } // All other cases are handled by the checks that y ≥ 2²⁵⁶ (equivalently // y_hi != 0) and that x ≥ y // The second-most-significant limb of normalized x is now zero // (equivalently x_hi < 2**128), but because the entire machine is not // guaranteed to be cleared, we can't optimize any further. // [x_hi x_lo] now represents remainder × 2ˢ (the normalized remainder); // we shift right by `s` (un-normalize) to obtain the result. return _shr(x_hi, x_lo, s); } function odivAlt(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) { (uint256 y_hi, uint256 y_lo) = y.into(); if (y_hi == 0) { // This is the only case where we can have a 2-word quotient return odiv(r, x, y_lo); } (uint256 x_hi, uint256 x_lo) = x.into(); if (y_lo == 0) { uint256 r_lo = x_hi.unsafeDiv(y_hi); return r.from(0, r_lo); } if (_gt(y_hi, y_lo, x_hi, x_lo)) { return r.from(0, 0); } // At this point, we know that both `x` and `y` are fully represented by // 2 words. There is no simpler representation for the problem. We must // use Knuth's Algorithm D. { uint256 r_lo = _algorithmD(x_hi, x_lo, y_hi, y_lo); return r.from(0, r_lo); } } function idivAlt(uint512 r, uint512 y) internal pure returns (uint512) { return odivAlt(r, r, y); } function irdivAlt(uint512 r, uint512 y) internal pure returns (uint512) { return odivAlt(r, y, r); } function divAlt(uint512 x, uint512 y) internal pure returns (uint256) { (uint256 y_hi, uint256 y_lo) = y.into(); if (y_hi == 0) { return div(x, y_lo); } (uint256 x_hi, uint256 x_lo) = x.into(); if (y_lo == 0) { return x_hi.unsafeDiv(y_hi); } if (_gt(y_hi, y_lo, x_hi, x_lo)) { return 0; } // At this point, we know that both `x` and `y` are fully represented by // 2 words. There is no simpler representation for the problem. We must // use Knuth's Algorithm D. return _algorithmD(x_hi, x_lo, y_hi, y_lo); } function omodAlt(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) { (uint256 y_hi, uint256 y_lo) = y.into(); if (y_hi == 0) { uint256 r_lo = mod(x, y_lo); return r.from(0, r_lo); } (uint256 x_hi, uint256 x_lo) = x.into(); if (y_lo == 0) { uint256 r_hi = x_hi.unsafeMod(y_hi); return r.from(r_hi, x_lo); } if (_gt(y_hi, y_lo, x_hi, x_lo)) { return r.from(x_hi, x_lo); } // At this point, we know that both `x` and `y` are fully represented by // 2 words. There is no simpler representation for the problem. We must // use Knuth's Algorithm D. { (uint256 r_hi, uint256 r_lo) = _algorithmDRemainder(x_hi, x_lo, y_hi, y_lo); return r.from(r_hi, r_lo); } } function imodAlt(uint512 r, uint512 y) internal pure returns (uint512) { return omodAlt(r, r, y); } function irmodAlt(uint512 r, uint512 y) internal pure returns (uint512) { return omodAlt(r, y, r); } } using Lib512MathArithmetic for uint512 global; library Lib512MathUserDefinedHelpers { function checkNull(uint512 x, uint512 y) internal pure { assembly ("memory-safe") { if iszero(mul(x, y)) { mstore(0x00, 0x4e487b71) // selector for `Panic(uint256)` mstore(0x20, 0x01) // code for "assertion failure" } } } function smuggleToPure(function (uint512, uint512, uint512) internal view returns (uint512) f) internal pure returns (function (uint512, uint512, uint512) internal pure returns (uint512) r) { assembly ("memory-safe") { r := f } } function omod(uint512 r, uint512 x, uint512 y) internal view returns (uint512) { return r.omod(x, y); } function odiv(uint512 r, uint512 x, uint512 y) internal view returns (uint512) { return r.odiv(x, y); } } function __add(uint512 x, uint512 y) pure returns (uint512 r) { Lib512MathUserDefinedHelpers.checkNull(x, y); r.oadd(x, y); } function __sub(uint512 x, uint512 y) pure returns (uint512 r) { Lib512MathUserDefinedHelpers.checkNull(x, y); r.osub(x, y); } function __mul(uint512 x, uint512 y) pure returns (uint512 r) { Lib512MathUserDefinedHelpers.checkNull(x, y); r.omul(x, y); } function __mod(uint512 x, uint512 y) pure returns (uint512 r) { Lib512MathUserDefinedHelpers.checkNull(x, y); Lib512MathUserDefinedHelpers.smuggleToPure(Lib512MathUserDefinedHelpers.omod)(r, x, y); } function __div(uint512 x, uint512 y) pure returns (uint512 r) { Lib512MathUserDefinedHelpers.checkNull(x, y); Lib512MathUserDefinedHelpers.smuggleToPure(Lib512MathUserDefinedHelpers.odiv)(r, x, y); } using {__add as +, __sub as -, __mul as *, __mod as %, __div as / } for uint512 global; struct uint512_external { uint256 hi; uint256 lo; } library Lib512MathExternal { function from(uint512 r, uint512_external memory x) internal pure returns (uint512) { assembly ("memory-safe") { mstore(r, mload(x)) mstore(add(0x20, r), mload(add(0x20, x))) } return r; } function into(uint512_external memory x) internal pure returns (uint512 r) { assembly ("memory-safe") { r := x } } function toExternal(uint512 x) internal pure returns (uint512_external memory r) { assembly ("memory-safe") { if iszero(eq(mload(0x40), add(0x40, r))) { revert(0x00, 0x00) } mstore(0x40, r) r := x } } } using Lib512MathExternal for uint512 global; using Lib512MathExternal for uint512_external global; // src/utils/AddressDerivation.sol 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); // keccak256(abi.encodePacked(ECMUL([x, y], k)))[12:] 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); } // +/-7 are neither square nor cube mod p, so we only have to check one // coordinate against 0. if it is 0, then the other is too (the point at // infinity) or the point is invalid 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 { // https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384 return ecrecover( bytes32(0), uint8(27 + (y & 1)), bytes32(x), bytes32(UnsafeMath.unsafeMulMod(x, k, _SECP256K1_N)) ); } } // keccak256(RLP([deployer, nonce]))[12:] 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") { // we don't care about dirty bits in `deployer`; they'll be overwritten later mstore(0x14, deployer) mstore(0x00, 0xd694) mstore8(0x34, nonce) result := keccak256(0x1e, 0x17) } } else { // compute ceil(log_256(nonce)) + 1 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; } // ceil if ((uint256(nonce) << 8) >= (1 << nonceLength)) { nonceLength += 8; } // bytes, not bits nonceLength >>= 3; } assembly ("memory-safe") { // we don't care about dirty bits in `deployer` or `nonce`. they'll be overwritten later 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)) } } } // keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initHash))[12:] function deriveDeterministicContract(address deployer, bytes32 salt, bytes32 initHash) internal pure returns (address result) { assembly ("memory-safe") { let ptr := mload(0x40) // we don't care about dirty bits in `deployer`; they'll be overwritten later mstore(0x00, deployer) mstore(0x20, salt) mstore(0x40, initHash) mstore8(0x0b, 0xff) result := keccak256(0x0b, 0x55) mstore(0x40, ptr) } } } // src/allowanceholder/AllowanceHolderContext.sol abstract contract AllowanceHolderContext is Context { function _isForwarded() internal view virtual override returns (bool) { return super._isForwarded() || super._msgSender() == address(ALLOWANCE_HOLDER); } function _msgData() internal view virtual override returns (bytes calldata) { if (super._msgSender() == address(ALLOWANCE_HOLDER)) { return msg.data[:msg.data.length - 20]; } else { return msg.data; } } function _msgSender() internal view virtual override returns (address sender) { sender = super._msgSender(); if (sender == address(ALLOWANCE_HOLDER)) { // ERC-2771 like usage where the _trusted_ `AllowanceHolder` has appended the appropriate // msg.sender to the msg data bytes calldata data = super._msgData(); assembly ("memory-safe") { sender := shr(0x60, calldataload(add(data.offset, sub(data.length, 0x14)))) } } } // this is here to avoid foot-guns and make it very explicit that we intend // to pass the confused deputy check in AllowanceHolder function balanceOf(address) external pure { assembly ("memory-safe") { mstore8(0x00, 0x00) return(0x00, 0x01) } } } // src/vendor/FullMath.sol /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv library FullMath { using UnsafeMath for uint256; using UnsafeMath for uint8; using Math for uint256; using Math for bool; /// @notice 512-bit multiply [prod1 prod0] = a * b /// @param a The multiplicand /// @param b The multiplier /// @return lo Least significant 256 bits of the product /// @return hi Most significant 256 bits of the product function fullMul(uint256 a, uint256 b) internal pure returns (uint256 lo, uint256 hi) { // Compute the product mod 2**256 and mod 2**256 - 1 then use the Chinese // Remainder Theorem to reconstruct the 512 bit result. The result is stored // in two 256 variables such that product = prod1 * 2**256 + prod0 assembly ("memory-safe") { let mm := mulmod(a, b, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) lo := mul(a, b) hi := sub(sub(mm, lo), lt(mm, lo)) } } function fullLt(uint256 a_lo, uint256 a_hi, uint256 b_lo, uint256 b_hi) internal pure returns (bool r) { assembly ("memory-safe") { r := or(lt(a_hi, b_hi), and(eq(a_hi, b_hi), lt(a_lo, b_lo))) } } /// @notice 512-bit multiply [prod1 prod0] = a * b /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return prod0 Least significant 256 bits of the product /// @return prod1 Most significant 256 bits of the product /// @return remainder Remainder of full-precision division function _mulDivSetup(uint256 a, uint256 b, uint256 denominator) private pure returns (uint256 prod0, uint256 prod1, uint256 remainder) { (prod0, prod1) = fullMul(a, b); remainder = a.unsafeMulMod(b, denominator); } /// @notice 512-bit by 256-bit division. /// @param prod0 Least significant 256 bits of the product /// @param prod1 Most significant 256 bits of the product /// @param denominator The divisor /// @param remainder Remainder of full-precision division /// @return The 256-bit result /// @dev Overflow and division by zero aren't checked and are GIGO errors function _mulDivInvert(uint256 prod0, uint256 prod1, uint256 denominator, uint256 remainder) private pure returns (uint256) { uint256 inv; assembly ("memory-safe") { // Make division exact by rounding [prod1 prod0] down to a multiple of // denominator // Subtract 256 bit number from 512 bit number prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) // Factor powers of two out of denominator { // Compute largest power of two divisor of denominator. // Always >= 1. let twos := and(sub(0, denominator), denominator) // Divide denominator by power of two denominator := div(denominator, twos) // Divide [prod1 prod0] by the factors of two prod0 := div(prod0, twos) // Shift in bits from prod1 into prod0. For this we need to flip `twos` // such that it is 2**256 / twos. // If twos is zero, then it becomes one twos := add(div(sub(0, twos), twos), 1) prod0 := or(prod0, mul(prod1, twos)) } // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse modulo 2**256 // such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct correct for // four bits. That is, denominator * inv = 1 mod 2**4 inv := xor(mul(3, denominator), 2) // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**128 inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**256 } // Because the division is now exact we can divide by multiplying with the // modular inverse of denominator. This will give us the correct result // modulo 2**256. Since the precoditions guarantee that the outcome is less // than 2**256, this is the final result. We don't need to compute the high // bits of the result and prod1 is no longer required. unchecked { return prod0 * inv; } } /// @notice Calculates a×b÷denominator with full precision then rounds towards 0. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return The 256-bit result function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) { (uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator); // Make sure the result is less than 2**256. // Also prevents denominator == 0 if (denominator <= prod1) { unchecked { Panic.panic(Panic.ARITHMETIC_OVERFLOW.unsafeInc(denominator == 0)); } } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { return prod0.unsafeDiv(denominator); } return _mulDivInvert(prod0, prod1, denominator, remainder); } /// @notice Calculates a×b÷denominator with full precision then rounds towards positive infinity. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return The 256-bit result function mulDivUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) { (uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator); // Make sure the result is less than 2**256. // Also prevents denominator == 0 if (denominator <= prod1) { unchecked { Panic.panic(Panic.ARITHMETIC_OVERFLOW.unsafeInc(denominator == 0)); } } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { return prod0.unsafeDivUp(denominator); } return _mulDivInvert(prod0, prod1, denominator, remainder).inc(0 < remainder); } /// @notice Calculates a×b÷denominator with full precision then rounds towards positive infinity. Returns `type(uint256).max` if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return The 256-bit result function saturatingMulDivUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) { (uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator); uint256 overflow; unchecked { overflow = (denominator > prod1).toInt() - 1; } if (prod1 == 0) { return prod0.unsafeDivUp(denominator).saturatingAdd(overflow); } return _mulDivInvert(prod0, prod1, denominator, remainder).inc(0 < remainder).saturatingAdd(overflow); } /// @notice Calculates a×b÷denominator with full precision then rounds towards 0. Overflowing a uint256 or denominator == 0 are GIGO errors /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return The 256-bit result function unsafeMulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) { (uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator); // Overflow and zero-division checks are skipped // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { return prod0.unsafeDiv(denominator); } return _mulDivInvert(prod0, prod1, denominator, remainder); } /// @notice Calculates a×b÷denominator with full precision then rounds towards 0. Overflowing a uint256 or denominator == 0 are GIGO errors /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @dev This is the branchless, straight line version of `unsafeMulDiv`. If we know that `prod1 != 0` this may be faster. Also this gives Solc a better chance to optimize. /// @return The 256-bit result function unsafeMulDivAlt(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) { (uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator); return _mulDivInvert(prod0, prod1, denominator, remainder); } /// @notice Calculates a×b÷denominator with full precision then rounds towards positive infinity. Overflowing a uint256 or denominator == 0 are GIGO errors /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return The 256-bit result function unsafeMulDivUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) { (uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator); // Overflow and zero-division checks are skipped // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { return prod0.unsafeDivUp(denominator); } return _mulDivInvert(prod0, prod1, denominator, remainder).unsafeInc(0 < remainder); } /// @notice Calculates a×b÷denominator with full precision then rounds towards positive infinity. Overflowing a uint256 or denominator == 0 are GIGO errors /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @dev This is the branchless, straight line version of `unsafeMulDivUp`. If we know that `prod1 != 0` this may be faster. Also this gives Solc a better chance to optimize. /// @return The 256-bit result function unsafeMulDivUpAlt(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) { (uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator); return _mulDivInvert(prod0, prod1, denominator, remainder).unsafeInc(0 < remainder); } function unsafeMulShift(uint256 a, uint256 b, uint256 s) internal pure returns (uint256 result) { assembly ("memory-safe") { let mm := mulmod(a, b, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) let prod0 := mul(a, b) let prod1 := sub(sub(mm, prod0), lt(mm, prod0)) result := or(shr(s, prod0), shl(sub(0x100, s), prod1)) } } function unsafeMulShiftUp(uint256 a, uint256 b, uint256 s) internal pure returns (uint256 result) { assembly ("memory-safe") { let mm := mulmod(a, b, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) let prod0 := mul(a, b) let prod1 := sub(sub(mm, prod0), lt(mm, prod0)) let s_ := sub(0x100, s) result := or(shr(s, prod0), shl(s_, prod1)) result := add(lt(0x00, shl(s_, prod0)), result) } } } // src/ISettlerActions.sol interface ISettlerActions { /// @dev Transfer funds from msg.sender Permit2. function TRANSFER_FROM(address recipient, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig) external; // @dev msgValue is interpreted as an upper bound on the expected msg.value, not as an exact specification function NATIVE_CHECK(uint256 deadline, uint256 msgValue) external; /// @dev Transfer funds from metatransaction requestor into the Settler contract using Permit2. Only for use in `Settler.executeMetaTxn` where the signature is provided as calldata function METATXN_TRANSFER_FROM(address recipient, ISignatureTransfer.PermitTransferFrom memory permit) external; /// @dev Settle an RfqOrder between maker and taker transfering funds directly between the parties // Post-req: Payout if recipient != taker function RFQ_VIP( address recipient, ISignatureTransfer.PermitTransferFrom memory makerPermit, address maker, bytes memory makerSig, ISignatureTransfer.PermitTransferFrom memory takerPermit, bytes memory takerSig ) external; /// @dev Settle an RfqOrder between maker and taker transfering funds directly between the parties for the entire amount function METATXN_RFQ_VIP( address recipient, ISignatureTransfer.PermitTransferFrom memory makerPermit, address maker, bytes memory makerSig, ISignatureTransfer.PermitTransferFrom memory takerPermit ) external; /// @dev Settle an RfqOrder between Maker and Settler. Transfering funds from the Settler contract to maker. /// Retaining funds in the settler contract. // Pre-req: Funded // Post-req: Payout function RFQ( address recipient, ISignatureTransfer.PermitTransferFrom memory permit, address maker, bytes memory makerSig, address takerToken, uint256 maxTakerAmount ) external; function UNISWAPV4( address recipient, address sellToken, uint256 bps, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, uint256 amountOutMin ) external; function UNISWAPV4_VIP( address recipient, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig, uint256 amountOutMin ) external; function METATXN_UNISWAPV4_VIP( address recipient, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, ISignatureTransfer.PermitTransferFrom memory permit, uint256 amountOutMin ) external; function BALANCERV3( address recipient, address sellToken, uint256 bps, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, uint256 amountOutMin ) external; function BALANCERV3_VIP( address recipient, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig, uint256 amountOutMin ) external; function METATXN_BALANCERV3_VIP( address recipient, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, ISignatureTransfer.PermitTransferFrom memory permit, uint256 amountOutMin ) external; function PANCAKE_INFINITY( address recipient, address sellToken, uint256 bps, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, uint256 amountOutMin ) external; function PANCAKE_INFINITY_VIP( address recipient, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig, uint256 amountOutMin ) external; function METATXN_PANCAKE_INFINITY_VIP( address recipient, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, ISignatureTransfer.PermitTransferFrom memory permit, uint256 amountOutMin ) external; /// @dev Trades against UniswapV3 using the contracts balance for funding // Pre-req: Funded // Post-req: Payout function UNISWAPV3(address recipient, uint256 bps, bytes memory path, uint256 amountOutMin) external; /// @dev Trades against UniswapV3 using user funds via Permit2 for funding function UNISWAPV3_VIP( address recipient, bytes memory path, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig, uint256 amountOutMin ) external; /// @dev Trades against UniswapV3 using user funds via Permit2 for funding. Metatransaction variant. Signature is over all actions. function METATXN_UNISWAPV3_VIP( address recipient, bytes memory path, ISignatureTransfer.PermitTransferFrom memory permit, uint256 amountOutMin ) external; function MAKERPSM(address recipient, uint256 bps, bool buyGem, uint256 amountOutMin) 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; /// @dev Trades against MaverickV2 using the contracts balance for funding /// This action does not use the MaverickV2 callback, so it takes an arbitrary pool address to make calls against. /// Passing `tokenAIn` as a parameter actually saves gas relative to introspecting the pool's `tokenA()` accessor. function MAVERICKV2( address recipient, address sellToken, uint256 bps, address pool, bool tokenAIn, uint256 minBuyAmount ) external; /// @dev Trades against MaverickV2, spending the taker's coupon inside the callback /// This action requires the use of the MaverickV2 callback, so we take the MaverickV2 CREATE2 salt as an argument to derive the pool address from the trusted factory and inithash. /// @param salt is formed as `keccak256(abi.encode(feeAIn, feeBIn, tickSpacing, lookback, tokenA, tokenB, kinds, address(0)))` function MAVERICKV2_VIP( address recipient, bytes32 salt, bool tokenAIn, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig, uint256 minBuyAmount ) external; /// @dev Trades against MaverickV2, spending the taker's coupon inside the callback; metatransaction variant function METATXN_MAVERICKV2_VIP( address recipient, bytes32 salt, bool tokenAIn, ISignatureTransfer.PermitTransferFrom memory permit, uint256 minBuyAmount ) external; /// @dev Trades against UniswapV2 using the contracts balance for funding /// @param swapInfo is encoded as the upper 16 bits as the fee of the pool in bps, the second /// lowest bit as "sell token has transfer fee", and the lowest bit as the /// "token0 for token1" flag. function UNISWAPV2( address recipient, address sellToken, uint256 bps, address pool, uint24 swapInfo, uint256 amountOutMin ) external; function POSITIVE_SLIPPAGE(address payable recipient, address token, uint256 expectedAmount) external; /// @dev Trades against a basic AMM which follows the approval, transferFrom(msg.sender) interaction // Pre-req: Funded // Post-req: Payout function BASIC(address sellToken, uint256 bps, address pool, uint256 offset, bytes calldata data) external; function EKUBO( address recipient, address sellToken, uint256 bps, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, uint256 amountOutMin ) external; function EKUBO_VIP( address recipient, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig, uint256 amountOutMin ) external; function METATXN_EKUBO_VIP( address recipient, bool feeOnTransfer, uint256 hashMul, uint256 hashMod, bytes memory fills, ISignatureTransfer.PermitTransferFrom memory permit, uint256 amountOutMin ) external; function EULERSWAP( address recipient, address sellToken, uint256 bps, address pool, bool zeroForOne, uint256 amountOutMin ) external; } // src/interfaces/ISettlerMetaTxn.sol interface ISettlerMetaTxn is ISettlerBase { function executeMetaTxn( AllowedSlippage calldata slippage, bytes[] calldata actions, bytes32 /* zid & affiliate */, address msgSender, bytes calldata sig ) external returns (bool); } // src/multicall/MultiCallContext.sol interface IMultiCall_1 { enum RevertPolicy { REVERT, HALT, CONTINUE } struct Call { address target; RevertPolicy revertPolicy; uint256 value; bytes data; } struct Result { bool success; bytes data; } function multicall(Call[] calldata calls, uint256 contextdepth) external payable returns (Result[] memory); receive() external payable; } address constant MULTICALL_ADDRESS = 0x00000000000000CF9E3c5A26621af382fA17f24f; abstract contract MultiCallContext is Context { using FastLogic for bool; IMultiCall_1 internal constant _MULTICALL = IMultiCall_1(payable(MULTICALL_ADDRESS)); function _isForwarded() internal view virtual override returns (bool) { return super._isForwarded().or(super._msgSender() == address(_MULTICALL)); } function _msgData() internal view virtual override returns (bytes calldata r) { address sender = super._msgSender(); r = super._msgData(); assembly ("memory-safe") { r.length := sub(r.length, mul(0x14, eq(MULTICALL_ADDRESS, and(0xffffffffffffffffffffffffffffffffffffffff, sender)))) } } function _msgSender() internal view virtual override returns (address sender) { sender = super._msgSender(); bytes calldata data = super._msgData(); assembly ("memory-safe") { // ERC-2771. The trusted forwarder (`_MULTICALL`) has appended the appropriate // msg.sender to the msg data sender := xor( sender, mul( xor(shr(0x60, calldataload(add(data.offset, sub(data.length, 0x14)))), sender), and(lt(0x03, data.length), iszero(shl(0x60, xor(MULTICALL_ADDRESS, sender)))) ) ) } } } // src/core/Permit2PaymentAbstract.sol 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 _permitToSellAmountCalldata(ISignatureTransfer.PermitTransferFrom calldata permit) internal view virtual returns (uint256 sellAmount); function _permitToSellAmount(ISignatureTransfer.PermitTransferFrom memory permit) internal view virtual returns (uint256 sellAmount); function _permitToTransferDetails(ISignatureTransfer.PermitTransferFrom memory permit, address recipient) internal view virtual returns (ISignatureTransfer.SignatureTransferDetails memory transferDetails, uint256 sellAmount); 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; } // src/deployer/IDeployer.sol interface IERC721View is IERC165 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event PermanentURI(string, uint256 indexed); // not technically part of the standard function balanceOf(address) external view returns (uint256); function ownerOf(uint256 tokenId) external view returns (address); function getApproved(uint256 tokenId) external view returns (address); function isApprovedForAll(address owner, address operator) external view returns (bool); } interface IERC721ViewMetadata is IERC721View { function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256) external view returns (string memory); } interface IDeployerRemove { function remove(Feature, Nonce) external returns (bool); function remove(address) external returns (bool); function removeAll(Feature) external returns (bool); } interface IDeployer is IOwnable, IERC721ViewMetadata, IMultiCall_0, IDeployerRemove { function authorized(Feature) external view returns (address, uint40); function descriptionHash(Feature) external view returns (bytes32); function prev(Feature) external view returns (address); function next(Feature) external view returns (address); function deployInfo(address) external view returns (Feature, Nonce); function authorize(Feature, address, uint40) external returns (bool); function setDescription(Feature, string calldata) external returns (string memory); function deploy(Feature, bytes calldata) external payable returns (address, Nonce); // ERC-6093 errors error ERC721InvalidOwner(address owner); error ERC721NonexistentToken(uint256 tokenId); error FeatureNotInitialized(Feature); error FeatureInitialized(Feature); error DeployFailed(Feature, Nonce, address); error FutureNonce(Nonce); error NoInstance(); event Authorized(Feature indexed, address indexed, uint40); event Deployed(Feature indexed, Nonce indexed, address indexed); event Removed(Feature indexed, Nonce indexed, address indexed); event RemovedAll(Feature indexed); } // src/SettlerAbstract.sol abstract contract SettlerAbstract is Permit2PaymentAbstract { // Permit2 Witness for meta transactions string internal constant SLIPPAGE_AND_ACTIONS_TYPE = "SlippageAndActions(address recipient,address buyToken,uint256 minAmountOut,bytes[] actions)"; bytes32 internal constant SLIPPAGE_AND_ACTIONS_TYPEHASH = 0x615e8d716cef7295e75dd3f1f10d679914ad6d7759e8e9459f0109ef75241701; // Permit2 Witness for intents string internal constant SLIPPAGE_TYPE = "Slippage(address recipient,address buyToken,uint256 minAmountOut)"; bytes32 internal constant SLIPPAGE_TYPEHASH = 0xdc83993a2ffc65b01b71ed08790b6e39c5c55d76937b62a3b5085b02071f1259; uint256 internal constant BASIS = 10_000; IERC20 internal constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); constructor() { assert(SLIPPAGE_AND_ACTIONS_TYPEHASH == keccak256(bytes(SLIPPAGE_AND_ACTIONS_TYPE))); assert(SLIPPAGE_TYPEHASH == keccak256(bytes(SLIPPAGE_TYPE))); } function _hasMetaTxn() internal pure virtual returns (bool); function _tokenId() internal pure virtual returns (uint256); function _dispatch(uint256 i, uint256 action, bytes calldata data) internal virtual returns (bool); function _div512to256(uint512 n, uint512 d) internal view virtual returns (uint256); } // src/core/UniswapV2.sol 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 is SettlerAbstract { using SafeTransferLib for IERC20; // bytes4(keccak256("getReserves()")) uint32 private constant UNI_PAIR_RESERVES_SELECTOR = 0x0902f1ac; // bytes4(keccak256("swap(uint256,uint256,address,bytes)")) uint32 private constant UNI_PAIR_SWAP_SELECTOR = 0x022c0d9f; // bytes4(keccak256("transfer(address,uint256)")) uint32 private constant ERC20_TRANSFER_SELECTOR = 0xa9059cbb; // bytes4(keccak256("balanceOf(address)")) uint32 private constant ERC20_BALANCEOF_SELECTOR = 0x70a08231; /// @dev Sell a token for another token using UniswapV2. function sellToUniswapV2( address recipient, address sellToken, uint256 bps, address pool, uint24 swapInfo, uint256 minBuyAmount ) internal { // Preventing calls to Permit2 or AH is not explicitly required as neither of these contracts implement the `swap` nor `transfer` selector // |7|6|5|4|3|2|1|0| - bit positions in swapInfo (uint8) // |0|0|0|0|0|0|F|Z| - Z: zeroForOne flag, F: sellTokenHasFee flag bool zeroForOne = (swapInfo & 1) == 1; // Extract the least significant bit (bit 0) bool sellTokenHasFee = (swapInfo & 2) >> 1 == 1; // Extract the second least significant bit (bit 1) and shift it right uint256 feeBps = swapInfo >> 8; uint256 sellAmount; uint256 buyAmount; // If bps is zero we assume there are no funds within this contract, skip the updating sellAmount. // This case occurs if the pool is being chained, in which the funds have been sent directly to the pool if (bps != 0) { // We don't care about phantom overflow here because reserves are // limited to 112 bits. Any token balance that would overflow here would // also break UniV2. // It is *possible* to set `bps` above the basis and therefore // cause an overflow on this multiplication. However, `bps` is // passed as authenticated calldata, so this is a GIGO error that we // do not attempt to fix. unchecked { sellAmount = IERC20(sellToken).fastBalanceOf(address(this)) * bps / BASIS; } } assembly ("memory-safe") { let ptr := mload(0x40) // transfer sellAmount (a non zero amount) of sellToken to the pool if sellAmount { mstore(ptr, ERC20_TRANSFER_SELECTOR) mstore(add(ptr, 0x20), pool) mstore(add(ptr, 0x40), sellAmount) // ...||ERC20_TRANSFER_SELECTOR|pool|sellAmount| if iszero(call(gas(), sellToken, 0, add(ptr, 0x1c), 0x44, 0x00, 0x20)) { bubbleRevert() } if iszero(or(iszero(returndatasize()), and(iszero(lt(returndatasize(), 0x20)), eq(mload(0x00), 1)))) { revert(0, 0) } } // get pool reserves let sellReserve let buyReserve mstore(0x00, UNI_PAIR_RESERVES_SELECTOR) // ||UNI_PAIR_RESERVES_SELECTOR| if iszero(staticcall(gas(), pool, 0x1c, 0x04, 0x00, 0x40)) { bubbleRevert() } if lt(returndatasize(), 0x40) { revert(0, 0) } { let r := shl(5, zeroForOne) buyReserve := mload(r) sellReserve := mload(xor(0x20, r)) } // Update the sell amount in the following cases: // the funds are in the pool already (flagged by sellAmount being 0) // the sell token has a fee (flagged by sellTokenHasFee) if or(iszero(sellAmount), sellTokenHasFee) { // retrieve the sellToken balance of the pool mstore(0x00, ERC20_BALANCEOF_SELECTOR) mstore(0x20, and(0xffffffffffffffffffffffffffffffffffffffff, pool)) // ||ERC20_BALANCEOF_SELECTOR|pool| if iszero(staticcall(gas(), sellToken, 0x1c, 0x24, 0x00, 0x20)) { bubbleRevert() } if lt(returndatasize(), 0x20) { revert(0, 0) } let bal := mload(0x00) // determine real sellAmount by comparing pool's sellToken balance to reserve amount if lt(bal, sellReserve) { mstore(0x00, 0x4e487b71) // selector for `Panic(uint256)` mstore(0x20, 0x11) // panic code for arithmetic underflow revert(0x1c, 0x24) } sellAmount := sub(bal, sellReserve) } // compute buyAmount based on sellAmount and reserves let sellAmountWithFee := mul(sellAmount, sub(10000, feeBps)) buyAmount := div(mul(sellAmountWithFee, buyReserve), add(sellAmountWithFee, mul(sellReserve, 10000))) let swapCalldata := add(ptr, 0x1c) // set up swap call selector and empty callback data mstore(ptr, UNI_PAIR_SWAP_SELECTOR) mstore(add(ptr, 0x80), 0x80) // offset to length of data mstore(add(ptr, 0xa0), 0) // length of data // set amount0Out and amount1Out { // If `zeroForOne`, offset is 0x24, else 0x04 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)) // ...||UNI_PAIR_SWAP_SELECTOR|amount0Out|amount1Out|recipient|data| // perform swap at the pool sending bought tokens to the recipient if iszero(call(gas(), pool, 0, swapCalldata, 0xa4, 0, 0)) { bubbleRevert() } // revert with the return data from the most recent call function bubbleRevert() { let p := mload(0x40) returndatacopy(p, 0, returndatasize()) revert(p, returndatasize()) } } if (buyAmount < minBuyAmount) { revertTooMuchSlippage( IERC20(zeroForOne ? IUniV2Pair(pool).token1() : IUniV2Pair(pool).token0()), minBuyAmount, buyAmount ); } } } // src/core/RfqOrderSettlement.sol abstract contract RfqOrderSettlement is SettlerAbstract { using Ternary for bool; using SafeTransferLib for IERC20; using FullMath for uint256; struct Consideration { IERC20 token; uint256 amount; address counterparty; bool partialFillAllowed; } string internal constant CONSIDERATION_TYPE = "Consideration(address token,uint256 amount,address counterparty,bool partialFillAllowed)"; // `string.concat` isn't recognized by solc as compile-time constant, but `abi.encodePacked` is 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))); } /// @dev Settle an RfqOrder between maker and taker transferring funds directly between the counterparties. Either /// two Permit2 signatures are consumed, with the maker Permit2 containing a witness of the RfqOrder, or /// AllowanceHolder is supported for the taker payment. The Maker has signed the same order as the /// Taker. Submission may be directly by the taker or via a third party with the Taker signing a witness. /// @dev if used, the taker's witness is not calculated nor verified here as calling function is trusted function fillRfqOrderVIP( address recipient, ISignatureTransfer.PermitTransferFrom memory makerPermit, address maker, bytes memory makerSig, ISignatureTransfer.PermitTransferFrom memory takerPermit, bytes memory takerSig ) internal { if (!_hasMetaTxn()) { assert(makerPermit.permitted.amount <= type(uint256).max - BASIS); } (ISignatureTransfer.SignatureTransferDetails memory makerTransferDetails, uint256 makerAmount) = _permitToTransferDetails(makerPermit, recipient); // In theory, the taker permit could invoke the balance-proportional sell amount logic. However, // because we hash the sell amount computed here into the maker's consideration (witness) only a // balance-proportional sell amount that corresponds exactly to the signed order would avoid a // revert. In other words, no unexpected behavior is possible. It's pointless to prohibit the // use of that logic. (ISignatureTransfer.SignatureTransferDetails memory takerTransferDetails, uint256 takerAmount) = _permitToTransferDetails(takerPermit, maker); bytes32 witness = _hashConsideration( Consideration({ token: IERC20(takerPermit.permitted.token), amount: takerAmount, counterparty: _msgSender(), partialFillAllowed: false }) ); _transferFrom(takerPermit, takerTransferDetails, takerSig); _transferFromIKnowWhatImDoing( makerPermit, makerTransferDetails, maker, witness, CONSIDERATION_WITNESS, makerSig, false ); _logRfqOrder( witness, _hashConsideration( Consideration({ token: IERC20(makerPermit.permitted.token), amount: makerAmount, counterparty: maker, partialFillAllowed: false }) ), uint128(makerAmount) ); } /// @dev Settle an RfqOrder between maker and Settler retaining funds in this contract. /// @dev pre-condition: msgSender has been authenticated against the requestor /// One Permit2 signature is consumed, with the maker Permit2 containing a witness of the RfqOrder. // In this variant, Maker pays recipient and Settler pays Maker function fillRfqOrderSelfFunded( address recipient, ISignatureTransfer.PermitTransferFrom memory permit, address maker, bytes memory makerSig, IERC20 takerToken, uint256 maxTakerAmount ) internal { if (!_hasMetaTxn()) { assert(permit.permitted.amount <= type(uint256).max - BASIS); } // Compute witnesses. These are based on the quoted maximum amounts. We will modify them // later to adjust for the actual settled amount, which may be modified by encountered // slippage. (ISignatureTransfer.SignatureTransferDetails memory transferDetails, uint256 makerAmount) = _permitToTransferDetails(permit, recipient); bytes32 takerWitness = _hashConsideration( Consideration({ token: IERC20(permit.permitted.token), amount: makerAmount, counterparty: maker, partialFillAllowed: true }) ); bytes32 makerWitness = _hashConsideration( Consideration({ token: takerToken, amount: maxTakerAmount, counterparty: _msgSender(), partialFillAllowed: true }) ); // Now we adjust the transfer amounts to compensate for encountered slippage. Rounding is // performed in the maker's favor. uint256 takerAmount = takerToken.fastBalanceOf(address(this)); takerAmount = (takerAmount > maxTakerAmount).ternary(maxTakerAmount, takerAmount); transferDetails.requestedAmount = makerAmount = makerAmount.unsafeMulDiv(takerAmount, maxTakerAmount); // Now that we have all the relevant information, make the transfers and log the order. takerToken.safeTransfer(maker, takerAmount); _transferFromIKnowWhatImDoing( permit, transferDetails, maker, makerWitness, CONSIDERATION_WITNESS, makerSig, false ); _logRfqOrder(makerWitness, takerWitness, uint128(makerAmount)); } } // src/core/Basic.sol abstract contract Basic is SettlerAbstract { using UnsafeMath for uint256; using SafeTransferLib for IERC20; using FullMath for uint256; using Revert for bool; /// @dev Sell to a pool with a generic approval, transferFrom interaction. /// offset in the calldata is used to update the sellAmount given a proportion of the sellToken balance function basicSellToPool(IERC20 sellToken, uint256 bps, address pool, uint256 offset, bytes memory data) internal { if (_isRestrictedTarget(pool)) { revertConfusedDeputy(); } bool success; bytes memory returnData; uint256 value; if (sellToken == ETH_ADDRESS) { unchecked { value = (address(this).balance * bps).unsafeDiv(BASIS); } 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)) { // TODO: check for zero `bps` if (offset != 0) revert InvalidOffset(); } else { // We treat `bps > BASIS` as a GIGO error uint256 amount = sellToken.fastBalanceOf(address(this)).unsafeMulDiv(bps, BASIS); 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); // forbid sending data to EOAs if (returnData.length == 0 && pool.code.length == 0) revert InvalidTarget(); } } // src/core/UniswapV3Fork.sol interface IUniswapV3Pool { /// @notice Swap token0 for token1, or token1 for token0 /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback /// @param recipient The address to receive the output of the swap /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0 /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), /// or exact output (negative) /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this /// value after the swap. If one for zero, the price cannot be greater than this value after the swap /// @param data Any data to be passed through to the callback /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive 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 Ternary for bool; using UnsafeMath for uint256; using UnsafeMath for int256; using SafeTransferLib for IERC20; /// @dev Minimum size of an encoded swap path: /// sizeof(address(inputToken) | uint8(forkId) | uint24(poolId) | address(outputToken)) uint256 private constant SINGLE_HOP_PATH_SIZE = 0x2c; /// @dev How many bytes to skip ahead in an encoded path to start at the next hop: /// sizeof(address(inputToken) | uint8(forkId) | uint24(poolId)) uint256 private constant PATH_SKIP_HOP_SIZE = 0x18; /// @dev The size of the swap callback prefix data before the Permit2 data. uint256 private constant SWAP_CALLBACK_PREFIX_DATA_SIZE = 0x28; /// @dev The offset from the pointer to the length of the swap callback prefix data to the start of the Permit2 data. uint256 private constant SWAP_CALLBACK_PERMIT2DATA_OFFSET = 0x48; uint256 private constant PERMIT_DATA_SIZE = 0x60; uint256 private constant ISFORWARDED_DATA_SIZE = 0x01; /// @dev Mask of lower 3 bytes. uint256 private constant UINT24_MASK = 0xffffff; /// @dev Sell a token for another token directly against uniswap v3. /// @param encodedPath Uniswap-encoded path. /// @param bps proportion of current balance of the first token in the path to sell. /// @param minBuyAmount Minimum amount of the last token in the path to buy. /// @param recipient The recipient of the bought tokens. /// @return buyAmount Amount of the last token in the path bought. function sellToUniswapV3(address recipient, uint256 bps, bytes memory encodedPath, uint256 minBuyAmount) internal returns (uint256 buyAmount) { buyAmount = _uniV3ForkSwap( recipient, encodedPath, // We don't care about phantom overflow here because reserves are // limited to 128 bits. Any token balance that would overflow here // would also break UniV3. (IERC20(address(bytes20(encodedPath))).fastBalanceOf(address(this)) * bps).unsafeDiv(BASIS), minBuyAmount, address(this), // payer new bytes(SWAP_CALLBACK_PREFIX_DATA_SIZE) ); } /// @dev Sell a token for another token directly against uniswap v3. Payment is using a Permit2 signature (or AllowanceHolder). /// @param encodedPath Uniswap-encoded path. /// @param minBuyAmount Minimum amount of the last token in the path to buy. /// @param recipient The recipient of the bought tokens. /// @param permit The PermitTransferFrom allowing this contract to spend the taker's tokens /// @param sig The taker's signature for Permit2 /// @return buyAmount Amount of the last token in the path bought. 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, _permitToSellAmount(permit), minBuyAmount, address(0), // payer swapCallbackData ); } // Executes successive swaps along an encoded uniswap path. 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); } // Intermediate tokens go to this contract. Final tokens go to `recipient`. address to = isPathMultiHop.ternary(address(this), recipient); uint256 freeMemPtr; bytes memory data; assembly ("memory-safe") { freeMemPtr := mload(0x40) data := freeMemPtr // encode the call to pool.swap let callbackLen := mload(swapCallbackData) mcopy(add(0xc4, data), swapCallbackData, add(0x20, callbackLen)) mstore(add(0xa4, data), 0xa0) mstore( add(0x84, data), xor( 4295128740, mul(xor(1461446703485210103287273052203988822378723970341, 4295128740), iszero(zeroForOne)) ) ) mstore(add(0x64, data), sellAmount) mstore(add(0x44, data), zeroForOne) mstore(add(0x24, data), to) mstore(add(0x10, data), 0x128acb08000000000000000000000000) // selector for `swap(address,bool,int256,uint160,bytes)` with `to`'s padding // set data.length mstore(data, add(0xc4, callbackLen)) // advance the free memory pointer (we'll put it back later) mstore(0x40, add(add(0xe4, callbackLen), data)) } (int256 amount0, int256 amount1) = abi.decode( _setOperatorAndCall(address(pool), data, callbackSelector, _uniV3ForkCallback), (int256, int256) ); assembly ("memory-safe") { // release the memory that we allocated above mstore(0x40, freeMemPtr) } { int256 _buyAmount = zeroForOne.ternary(amount1, amount0).unsafeNeg(); if (_buyAmount < 0) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } buyAmount = uint256(_buyAmount); } if (!isPathMultiHop) { // Done. break; } // Continue with next hop. payer = address(this); // Subsequent hops are paid for by us. sellAmount = buyAmount; // Skip to next hop along path. encodedPath = _shiftHopFromPathInPlace(encodedPath); assembly ("memory-safe") { mstore(swapCallbackData, SWAP_CALLBACK_PREFIX_DATA_SIZE) } } if (buyAmount < minBuyAmount) { revertTooMuchSlippage(outputToken, minBuyAmount, buyAmount); } } // Return whether or not an encoded uniswap path contains more than one hop. 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") { // Solidity cleans dirty bits automatically inputToken := mload(add(encodedPath, 0x14)) forkId := mload(add(encodedPath, 0x15)) poolId := mload(add(encodedPath, 0x18)) outputToken := mload(add(encodedPath, SINGLE_HOP_PATH_SIZE)) } } // Skip past the first hop of an encoded uniswap path in-place. 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) ) } } // Update `swapCallbackData` in place with new values. 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) } } // Compute the pool address given two tokens and a poolId. function _toPool(address factory, bytes32 initHash, IERC20 token0, IERC20 token1, uint24 poolId) private pure returns (IUniswapV3Pool) { // address(keccak256(abi.encodePacked( // hex"ff", // factory, // keccak256(abi.encode(token0, token1, poolId)), // initHash // ))) bytes32 salt; assembly ("memory-safe") { poolId := and(UINT24_MASK, poolId) let ptr := mload(0x40) mstore(0x40, poolId) mstore(0x20, token1) mstore(0x00, 0x00) mstore(0x0c, shl(0x60, token0)) 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); } /// @dev The UniswapV3 pool swap callback which pays the funds requested /// by the caller/pool to the pool. Can only be called by a valid /// UniswapV3 pool. /// @param amount0Delta Token0 amount owed. /// @param amount1Delta Token1 amount owed. /// @param data Arbitrary data forwarded from swap() caller. A packed encoding of: payer, sellToken, (optionally: permit[0x20:], isForwarded, sig) function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) private { address payer; assembly ("memory-safe") { payer := shr(0x60, calldataload(data.offset)) data.length := sub(data.length, 0x14) data.offset := add(0x14, data.offset) // We don't check for underflow/array-out-of-bounds here because the trusted inithash // ensures that `data` was passed unmodified from `_updateSwapCallbackData`. Therefore, // it is at least 40 bytes long. } uint256 sellAmount = (amount0Delta > 0).ternary(uint256(amount0Delta), uint256(amount1Delta)); _pay(payer, sellAmount, data); } function _pay(address payer, uint256 amount, bytes calldata permit2Data) private { if (payer == address(this)) { IERC20 token; assembly ("memory-safe") { token := shr(0x60, calldataload(permit2Data.offset)) } token.safeTransfer(msg.sender, amount); } else { assert(payer == address(0)); ISignatureTransfer.PermitTransferFrom calldata permit; bool isForwarded; bytes calldata sig; assembly ("memory-safe") { // this is super dirty, but it works because although `permit` is aliasing in the // middle of `payer`, because `payer` is all zeroes, it's treated as padding for the // first word of `permit`, which is the sell token 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) } ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer.SignatureTransferDetails({to: msg.sender, requestedAmount: amount}); _transferFrom(permit, transferDetails, sig, isForwarded); } } } // src/core/Velodrome.sol //import {Panic} from "../utils/Panic.sol"; 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 is SettlerAbstract { using Math for uint256; using UnsafeMath for uint256; using FastLogic for bool; using FullMath for uint256; using SafeTransferLib for IERC20; // This is the basis used for token balances. The original token may have fewer decimals, in // which case we scale up by the appropriate factor to give this basis. uint256 internal constant _VELODROME_TOKEN_BASIS = 1 ether; // When computing `k`, to minimize rounding error, we use a significantly larger basis. This // also allows us to save work in the Newton-Raphson step because dividing a quantity with this // basis by a quantity with `_VELODROME_TOKEN_BASIS` basis gives that same // `_VELODROME_TOKEN_BASIS` basis. Convenient *and* accurate. uint256 private constant _VELODROME_INTERNAL_BASIS = _VELODROME_TOKEN_BASIS * _VELODROME_TOKEN_BASIS; uint256 private constant _VELODROME_INTERNAL_TO_TOKEN_RATIO = _VELODROME_INTERNAL_BASIS / _VELODROME_TOKEN_BASIS; // When computing `d` we need to compute the cube of a token quantity and format the result with // `_VELODROME_TOKEN_BASIS`. In order to avoid overflow, we must divide the squared token // quantity by this before multiplying again by the token quantity. Setting this value as small // as possible preserves precision. This gives a result in an awkward basis, but we'll correct // that with `_VELODROME_CUBE_STEP_BASIS` after the cubing uint256 private constant _VELODROME_SQUARE_STEP_BASIS = 216840435; // After squaring a token quantity (in `_VELODROME_TOKEN_BASIS`), we need to multiply again by a // token quantity and then divide out the awkward basis to get back to // `_VELODROME_TOKEN_BASIS`. This constant is what gets us back to the original token quantity // basis. `_VELODROME_TOKEN_BASIS * _VELODROME_TOKEN_BASIS / _VELODROME_SQUARE_STEP_BASIS * // _VELODROME_TOKEN_BASIS / _VELODROME_CUBE_STEP_BASIS == _VELODROME_TOKEN_BASIS` uint256 private constant _VELODROME_CUBE_STEP_BASIS = 4611686007731906643703237360; // The maximum balance in the AMM's reference implementation of `k` is `b` such that `(b * b) / // 1 ether * ((b * b) / 1 ether + (b * b) / 1 ether)` does not overflow. This that quantity, // `b`. This is roughly 15.5 billion ether. uint256 internal constant _VELODROME_MAX_BALANCE = 15511800964685064948225197537; // This is the `k = x^3 * y + y^3 * x` constant function. Unlike the original formulation, the // result has a basis of `_VELODROME_INTERNAL_BASIS` instead of `_VELODROME_TOKEN_BASIS` function _k(uint256 x, uint256 y) private pure returns (uint256) { unchecked { return _k(x, y, x * x); } } function _k(uint256 x, uint256 y, uint256 x_squared) private pure returns (uint256) { unchecked { return _k(x, y, x_squared, y * y); } } function _k(uint256 x, uint256 y, uint256 x_squared, uint256 y_squared) private pure returns (uint256) { unchecked { return (x * y).unsafeMulDivAlt(x_squared + y_squared, _VELODROME_INTERNAL_BASIS); } } function _k_compat(uint256 x, uint256 y) internal pure returns (uint256) { unchecked { return (x * y).unsafeMulDivAlt(x * x + y * y, _VELODROME_INTERNAL_BASIS * _VELODROME_TOKEN_BASIS); } } function _k_compat(uint256 x, uint256 y, uint256 x_squared) private pure returns (uint256) { unchecked { return (x * y).unsafeMulDivAlt(x_squared + y * y, _VELODROME_INTERNAL_BASIS * _VELODROME_TOKEN_BASIS); } } // For numerically approximating a solution to the `k = x^3 * y + y^3 * x` constant function // using Newton-Raphson, this is `∂k/∂y = 3 * x * y^2 + x^3`. The result has a basis of // `_VELODROME_TOKEN_BASIS`. function _d(uint256 y, uint256 x) private pure returns (uint256) { unchecked { return _d(y, 3 * x, x * x / _VELODROME_SQUARE_STEP_BASIS * x); } } function _d(uint256 y, uint256 three_x, uint256 x_cubed) private pure returns (uint256) { unchecked { return _d(y, three_x, x_cubed, y * y / _VELODROME_SQUARE_STEP_BASIS); } } function _d(uint256, uint256 three_x, uint256 x_cubed, uint256 y_squared) private pure returns (uint256) { unchecked { return (y_squared * three_x + x_cubed) / _VELODROME_CUBE_STEP_BASIS; } } // Using Newton-Raphson iterations, compute the smallest `new_y` such that `_k(x + dx, new_y) >= // _k(x, y)`. As a function of `new_y`, we find the root of `_k(x + dx, new_y) - _k(x, y)`. function _get_y(uint256 x, uint256 dx, uint256 y) internal pure returns (uint256) { unchecked { uint256 k_orig = _k(x, y); // `k_orig` has a basis much greater than is actually required for correctness. To // achieve wei-level accuracy, we perform our final comparisons agains `k_target` // instead, which has the same precision as the AMM itself. uint256 k_target = _k_compat(x, y); // Now that we have `k` computed, we offset `x` to account for the sell amount and use // the constant-product formula to compute an initial estimate for `y`. x += dx; y -= (dx * y).unsafeDiv(x); // These intermediate values do not change throughout the Newton-Raphson iterations, so // precomputing and caching them saves us gas. uint256 three_x = 3 * x; uint256 x_squared_raw = x * x; uint256 x_cubed_raw = x_squared_raw / _VELODROME_SQUARE_STEP_BASIS * x; for (uint256 i; i < 255; i++) { uint256 y_squared_raw = y * y; uint256 k = _k(x, y, x_squared_raw, y_squared_raw); uint256 d = _d(y, three_x, x_cubed_raw, y_squared_raw / _VELODROME_SQUARE_STEP_BASIS); // This would exactly solve *OUR* formulation of the `k=x^3*y+y^3*x` constant // function. However, not only is it computationally and contract-size expensive, it // also does not necessarily exactly satisfy the *REFERENCE* implementations of the // same constant function (SolidlyV1, VelodromeV2). Therefore, it is commented out // and the relevant condition is handled by the "ordinary" parts of the // Newton-Raphson loop. /* if (k / _VELODROME_INTERNAL_TO_TOKEN_RATIO == k_target) { uint256 hi = y; uint256 lo = y - 1; uint256 k_next = _k_compat(x, lo, x_squared_raw); while (k_next == k_target) { (hi, lo) = (lo, lo - (hi - lo) * 2); k_next = _k_compat(x, lo, x_squared_raw); } while (hi != lo) { uint256 mid = (hi - lo) / 2 + lo; k_next = _k_compat(x, mid, x_squared_raw); if (k_next == k_target) { hi = mid; } else { lo = mid + 1; } } return lo; } else */ if (k < k_orig) { uint256 dy = (k_orig - k).unsafeDiv(d); // There are two cases where `dy == 0` // Case 1: The `y` is converged and we find the correct answer // Case 2: `_d(y, x)` is too large compare to `(k_orig - k)` and the rounding // error screwed us. // In this case, we need to increase `y` by 1 if (dy == 0) { if (_k_compat(x, y + 1, x_squared_raw) >= k_target) { // If `_k(x, y + 1) >= k_orig`, then we are close to the correct answer. // There's no closer answer than `y + 1` return y + 1; } // `y + 1` does not give us the condition `k >= k_orig`, so we have to do at // least 1 more iteration to find a satisfactory `y` value. Setting `dy = y // / 2` also solves the problem where the constant-product estimate of `y` // is very bad and convergence is only linear. dy = y / 2; } y += dy; if (y > _VELODROME_MAX_BALANCE) { y = _VELODROME_MAX_BALANCE; } } else { uint256 dy = (k - k_orig).unsafeDiv(d); if (dy == 0) { if (_k_compat(x, y - 1, x_squared_raw) < k_target) { // If `_k(x, y - 1) < k_orig`, then we are close to the correct answer. // There's no closer answer than `y`. We need to find `y` where `_k(x, // y) >= k_orig`. As a result, we can't return `y - 1` even it's closer // to the correct answer return y; } if (_k(x, y - 2, x_squared_raw) < k_orig) { // It may be the case that all 3 of `y`, `y - 1`, and `y - 2` give the // same value for `_k_compat`, but that `y - 2` gives a value for `_k` // that brackets `k_orig`. In this case, we would loop forever. This // branch causes us to bail out with the approximately correct value. return y - 1; } // It's possible that `y - 1` is the correct answer. To know that, we must // check that `y - 2` gives `k < k_orig`. We must do at least 1 more // iteration to determine this. dy = 2; } if (dy > y / 2) { dy = y / 2; } y -= dy; } } assembly ("memory-safe") { mstore(0x00, 0x481b61af) // selector for `NotConverged()` revert(0x1c, 0x04) } } } function sellToVelodrome(address recipient, uint256 bps, IVelodromePair pair, uint24 swapInfo, uint256 minAmountOut) internal { // Preventing calls to Permit2 or AH is not explicitly required as neither of these contracts implement the `swap` nor `transfer` selector // |7|6|5|4|3|2|1|0| - bit positions in swapInfo (uint8) // |0|0|0|0|0|0|F|Z| - Z: zeroForOne flag, F: sellTokenHasFee flag bool zeroForOne = (swapInfo & 1) == 1; // Extract the least significant bit (bit 0) bool sellTokenHasFee = (swapInfo & 2) >> 1 == 1; // Extract the second least significant bit (bit 1) and shift it right 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 { // Compute sell amount in native units uint256 sellAmount; if (bps != 0) { // It must be possible to square the sell token balance of the pool, otherwise it // will revert with an overflow. Therefore, it can't be so large that multiplying by // a "reasonable" `bps` value could overflow. We don't care to protect against // unreasonable `bps` values because that just means the taker is griefing themself. sellAmount = (sellToken.fastBalanceOf(address(this)) * bps).unsafeDiv(BASIS); } if (sellAmount != 0) { sellToken.safeTransfer(address(pair), sellAmount); } if ((sellAmount == 0).or(sellTokenHasFee)) { sellAmount = sellToken.fastBalanceOf(address(pair)) - sellReserve; } // Convert reserves from native units to `_VELODROME_TOKEN_BASIS` sellReserve = (sellReserve * _VELODROME_TOKEN_BASIS).unsafeDiv(sellBasis); buyReserve = (buyReserve * _VELODROME_TOKEN_BASIS).unsafeDiv(buyBasis); // This check is commented because values that are too large will // result in reverts inside the pool anyways. We don't need to // bother. /* // Check for overflow if (buyReserve > _VELODROME_MAX_BALANCE) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } if (sellReserve + (sellAmount * _VELODROME_TOKEN_BASIS).unsafeDiv(sellBasis) > _VELODROME_MAX_BALANCE) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } */ // Apply the fee in native units sellAmount -= sellAmount * feeBps / 10_000; // can't overflow // Convert sell amount from native units to `_VELODROME_TOKEN_BASIS` sellAmount = (sellAmount * _VELODROME_TOKEN_BASIS).unsafeDiv(sellBasis); // Solve the constant function numerically to get `buyAmount` from `sellAmount` buyAmount = buyReserve - _get_y(sellReserve, sellAmount, buyReserve); // Convert `buyAmount` from `_VELODROME_TOKEN_BASIS` to native units buyAmount = buyAmount * buyBasis / _VELODROME_TOKEN_BASIS; } // Compensate for rounding error in the reference implementation of the constant-function buyAmount--; buyAmount.dec((sellReserve < sellBasis).or(buyReserve < buyBasis)); // Check slippage if (buyAmount < minAmountOut) { revertTooMuchSlippage(sellToken, minAmountOut, buyAmount); } // Perform the swap { (uint256 buyAmount0, uint256 buyAmount1) = zeroForOne ? (uint256(0), buyAmount) : (buyAmount, uint256(0)); pair.swap(buyAmount0, buyAmount1, recipient, new bytes(0)); } } } // src/core/Permit2Payment.sol library TransientStorage { // bytes32((uint256(keccak256("operator slot")) - 1) & type(uint96).max) bytes32 private constant _OPERATOR_SLOT = 0x0000000000000000000000000000000000000000cdccd5c65a7d4860ce3abbe9; // bytes32((uint256(keccak256("witness slot")) - 1) & type(uint96).max) bytes32 private constant _WITNESS_SLOT = 0x0000000000000000000000000000000000000000c7aebfbc05485e093720deaa; // bytes32((uint256(keccak256("payer slot")) - 1) & type(uint96).max) bytes32 private constant _PAYER_SLOT = 0x0000000000000000000000000000000000000000cd1e9517bb0cb8d0d5cde893; // We assume (and our CI enforces) that internal function pointers cannot be // greater than 2 bytes. On chains not supporting the ViaIR pipeline, not // supporting EOF, and where the Spurious Dragon size limit is not enforced, // it might be possible to violate this assumption. However, our // `foundry.toml` enforces the use of the IR pipeline, so the point is moot. // // `operator` must not be `address(0)`. This is not checked. // `callback` must not be zero. This is checked in `_invokeCallback`. function setOperatorAndCallback( address operator, uint32 selector, function (bytes calldata) internal returns (bytes memory) callback ) internal { assembly ("memory-safe") { if iszero(shl(0x60, xor(tload(_PAYER_SLOT), operator))) { mstore(0x00, 0xe758b8d5) // selector for `ConfusedDeputy()` revert(0x1c, 0x04) } let slotValue := tload(_OPERATOR_SLOT) if slotValue { // It should be impossible to reach this error because the first thing the fallback // does is clear the operator. It's also not possible to reenter the entrypoint // function because `_PAYER_SLOT` is an implicit reentrancy guard. mstore(0x00, 0xab7646c4) // selector for `ReentrantCallback(uint256)` mstore(0x20, slotValue) revert(0x1c, 0x24) } tstore( _OPERATOR_SLOT, or( shl(0xe0, selector), or(shl(0xa0, and(0xffff, callback)), and(0xffffffffffffffffffffffffffffffffffffffff, operator)) ) ) } } function checkSpentOperatorAndCallback() internal view { assembly ("memory-safe") { let slotValue := tload(_OPERATOR_SLOT) if slotValue { mstore(0x00, 0xd66fcc38) // selector for `CallbackNotSpent(uint256)` mstore(0x20, slotValue) revert(0x1c, 0x24) } } } function getAndClearCallback() internal returns (function (bytes calldata) internal returns (bytes memory) callback) { assembly ("memory-safe") { let slotValue := tload(_OPERATOR_SLOT) if or(shr(0xe0, xor(calldataload(0), slotValue)), shl(0x60, xor(caller(), slotValue))) { revert(0x00, 0x00) } callback := and(0xffff, shr(0xa0, slotValue)) tstore(_OPERATOR_SLOT, 0x00) } } // `newWitness` must not be `bytes32(0)`. This is not checked. function setWitness(bytes32 newWitness) internal { assembly ("memory-safe") { let slotValue := tload(_WITNESS_SLOT) if slotValue { // It should be impossible to reach this error because the first thing a // metatransaction does on entry is to spend the `witness` (either directly or via a // callback) mstore(0x00, 0x9936cbab) // selector for `ReentrantMetatransaction(bytes32)` mstore(0x20, slotValue) revert(0x1c, 0x24) } tstore(_WITNESS_SLOT, newWitness) } } function checkSpentWitness() internal view { assembly ("memory-safe") { let slotValue := tload(_WITNESS_SLOT) if slotValue { mstore(0x00, 0xe25527c2) // selector for `WitnessNotSpent(bytes32)` mstore(0x20, slotValue) revert(0x1c, 0x24) } } } function getAndClearWitness() internal returns (bytes32 witness) { assembly ("memory-safe") { witness := tload(_WITNESS_SLOT) tstore(_WITNESS_SLOT, 0x00) } } function setPayer(address payer) internal { assembly ("memory-safe") { if iszero(shl(0x60, payer)) { mstore(0x00, 0xe758b8d5) // selector for `ConfusedDeputy()` revert(0x1c, 0x04) } let slotValue := tload(_PAYER_SLOT) if shl(0x60, slotValue) { mstore(0x14, slotValue) mstore(0x00, 0x7407c0f8000000000000000000000000) // selector for `ReentrantPayer(address)` with `oldPayer`'s padding revert(0x10, 0x24) } 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 { assembly ("memory-safe") { if shl(0x60, xor(tload(_PAYER_SLOT), expectedOldPayer)) { mstore(0x00, 0x5149e795) // selector for `PayerSpent()` revert(0x1c, 0x04) } tstore(_PAYER_SLOT, 0x00) } } } abstract contract Permit2PaymentBase is Context, SettlerAbstract { using Revert for bool; /// @dev Permit2 address ISignatureTransfer internal constant _PERMIT2 = ISignatureTransfer(0x000000000022D473030F116dDEE9F6B43aC78BA3); function _isRestrictedTarget(address target) internal pure virtual override returns (bool) { return target == address(_PERMIT2); } function _operator() internal view virtual override returns (address) { return super._msgSender(); } function _msgSender() internal view virtual override(AbstractContext, Context) returns (address) { return TransientStorage.getPayer(); } /// @dev You must ensure that `target` is derived by hashing trusted initcode or another /// equivalent mechanism that guarantees "reasonable"ness. `target` must not be /// user-supplied or attacker-controlled. This is required for security and is not checked /// here. For example, it must not do something weird like modifying the spender (possibly /// setting it to itself). If the callback is expected to relay a /// `ISignatureTransfer.PermitTransferFrom` struct, then the computation of `target` using /// the trusted initcode (or equivalent) must ensure that that calldata is relayed /// unmodified. The library function `AddressDerivation.deriveDeterministicContract` is /// recommended. 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) { // Retrieve callback and perform call with untrusted calldata return TransientStorage.getAndClearCallback()(data[4:]); } } abstract contract Permit2Payment is Permit2PaymentBase { fallback(bytes calldata) external virtual returns (bytes memory) { return _invokeCallback(_msgData()); } function _permitToTransferDetails(ISignatureTransfer.PermitTransferFrom memory permit, address recipient) internal view override returns (ISignatureTransfer.SignatureTransferDetails memory transferDetails, uint256 sellAmount) { transferDetails.to = recipient; transferDetails.requestedAmount = sellAmount = _permitToSellAmount(permit); } // This function is provided *EXCLUSIVELY* for use here and in RfqOrderSettlement. Any other use // of this function is forbidden. You must use the version that does *NOT* take a `from` or // `witness` argument. 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) { assembly ("memory-safe") { mstore(0x00, 0x1c500e5c) // selector for `ForwarderNotAllowed()` revert(0x1c, 0x04) } } // This is effectively /* _PERMIT2.permitWitnessTransferFrom(permit, transferDetails, from, witness, witnessTypeString, sig); */ // but it's written in assembly for contract size reasons. This produces a non-strict ABI // encoding (https://docs.soliditylang.org/en/v0.8.25/abi-spec.html#strict-encoding-mode), // but it's fine because Solidity's ABI *decoder* will handle anything that is validly // encoded, strict or not. // Solidity won't let us reference the constant `_PERMIT2` in assembly, but this compiles // down to just a single PUSH opcode just before the CALL, with optimization turned on. ISignatureTransfer __PERMIT2 = _PERMIT2; assembly ("memory-safe") { let ptr := mload(0x40) mstore(ptr, 0x137c29fe) // selector for `permitWitnessTransferFrom(((address,uint256),uint256,uint256),(address,uint256),address,bytes32,string,bytes)` // The layout of nested structs in memory is different from that in calldata. We have to // chase the pointer to `permit.permitted`. mcopy(add(0x20, ptr), mload(permit), 0x40) // The rest of the members of `permit` are laid out linearly, mcopy(add(0x60, ptr), add(0x20, permit), 0x40) // as are the members of `transferDetails. mcopy(add(0xa0, ptr), transferDetails, 0x40) // Because we're passing `from` on the stack, it must be cleaned. mstore(add(0xe0, ptr), and(0xffffffffffffffffffffffffffffffffffffffff, from)) mstore(add(0x100, ptr), witness) mstore(add(0x120, ptr), 0x140) // Offset to `witnessTypeString` (the end of of the non-dynamic types) let witnessTypeStringLength := mload(witnessTypeString) mstore(add(0x140, ptr), add(0x160, witnessTypeStringLength)) // Offset to `sig` (past the end of `witnessTypeString`) // Now we encode the 2 dynamic objects, `witnessTypeString` and `sig`. mcopy(add(0x160, ptr), witnessTypeString, add(0x20, witnessTypeStringLength)) let sigLength := mload(sig) mcopy(add(0x180, add(ptr, witnessTypeStringLength)), sig, add(0x20, sigLength)) // We don't need to check that Permit2 has code, and it always signals failure by // reverting. if iszero( call( gas(), __PERMIT2, 0x00, add(0x1c, ptr), add(0x184, add(witnessTypeStringLength, sigLength)), 0x00, 0x00 ) ) { let ptr_ := mload(0x40) returndatacopy(ptr_, 0x00, returndatasize()) revert(ptr_, returndatasize()) } } } // See comment in above overload; don't use this function 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()); } } // DANGER: the order of the base contracts here is very significant for the use of `super` below // (and in derived contracts). Do not change this order. abstract contract Permit2PaymentTakerSubmitted is AllowanceHolderContext, Permit2Payment { using FullMath for uint256; using SafeTransferLib for IERC20; using FastLogic for bool; constructor() { assert(!_hasMetaTxn()); } function _permitToSellAmountCalldata(ISignatureTransfer.PermitTransferFrom calldata permit) internal view override returns (uint256 sellAmount) { sellAmount = permit.permitted.amount; unchecked { if (~sellAmount < BASIS) { sellAmount = BASIS - ~sellAmount; sellAmount = IERC20(permit.permitted.token).fastBalanceOf(_msgSender()).unsafeMulDiv(sellAmount, BASIS); } } } function _permitToSellAmount(ISignatureTransfer.PermitTransferFrom memory permit) internal view override returns (uint256 sellAmount) { sellAmount = permit.permitted.amount; unchecked { if (~sellAmount < BASIS) { sellAmount = BASIS - ~sellAmount; sellAmount = IERC20(permit.permitted.token).fastBalanceOf(_msgSender()).unsafeMulDiv(sellAmount, BASIS); } } } function _isRestrictedTarget(address target) internal pure virtual override returns (bool) { return (target == address(ALLOWANCE_HOLDER)).or(super._isRestrictedTarget(target)); } function _transferFrom( ISignatureTransfer.PermitTransferFrom memory permit, ISignatureTransfer.SignatureTransferDetails memory transferDetails, bytes memory sig, bool isForwarded ) internal override { if (isForwarded) { if (sig.length != 0) { assembly ("memory-safe") { mstore(0x00, 0xc321526c) // selector for `InvalidSignatureLen()` revert(0x1c, 0x04) } } if (permit.nonce != 0) Panic.panic(Panic.ARITHMETIC_OVERFLOW); if (block.timestamp > permit.deadline) { assembly ("memory-safe") { mstore(0x00, 0xcd21db4f) // selector for `SignatureExpired(uint256)` mstore(0x20, mload(add(0x60, permit))) revert(0x1c, 0x24) } } // we don't check `requestedAmount` because it's checked by AllowanceHolder itself _allowanceHolderTransferFrom( permit.permitted.token, _msgSender(), transferDetails.to, transferDetails.requestedAmount ); } else { // This is effectively /* _PERMIT2.permitTransferFrom(permit, transferDetails, _msgSender(), sig); */ // but it's written in assembly for contract size reasons. This produces a non-strict // ABI encoding // (https://docs.soliditylang.org/en/v0.8.25/abi-spec.html#strict-encoding-mode), but // it's fine because Solidity's ABI *decoder* will handle anything that is validly // encoded, strict or not. // Solidity won't let us reference the constant `_PERMIT2` in assembly, but this // compiles down to just a single PUSH opcode just before the CALL, with optimization // turned on. ISignatureTransfer __PERMIT2 = _PERMIT2; address from = _msgSender(); assembly ("memory-safe") { let ptr := mload(0x40) mstore(ptr, 0x30f28b7a) // selector for `permitTransferFrom(((address,uint256),uint256,uint256),(address,uint256),address,bytes)` // The layout of nested structs in memory is different from that in calldata. We // have to chase the pointer to `permit.permitted`. mcopy(add(0x20, ptr), mload(permit), 0x40) // The rest of the members of `permit` are laid out linearly, mcopy(add(0x60, ptr), add(0x20, permit), 0x40) // as are the members of `transferDetails. mcopy(add(0xa0, ptr), transferDetails, 0x40) // Because we're passing `from` on the stack, it must be cleaned. mstore(add(0xe0, ptr), and(0xffffffffffffffffffffffffffffffffffffffff, from)) mstore(add(0x100, ptr), 0x100) // Offset to `sig` (the end of the non-dynamic types) // Encode the dynamic object `sig` let sigLength := mload(sig) mcopy(add(0x120, ptr), sig, add(0x20, sigLength)) // We don't need to check that Permit2 has code, and it always signals failure by // reverting. if iszero(call(gas(), __PERMIT2, 0x00, add(0x1c, ptr), add(0x124, sigLength), 0x00, 0x00)) { let ptr_ := mload(0x40) returndatacopy(ptr_, 0x00, returndatasize()) revert(ptr_, returndatasize()) } } } } function _allowanceHolderTransferFrom(address token, address owner, address recipient, uint256 amount) internal override { // `owner` is always `_msgSender()` // This is effectively /* _ALLOWANCE_HOLDER.transferFrom(token, owner, recipient, amount); */ // but it's written in assembly for contract size reasons. // Solidity won't let us reference the constant `_ALLOWANCE_HOLDER` in assembly, but this // compiles down to just a single PUSH opcode just before the CALL, with optimization turned // on. address _ALLOWANCE_HOLDER = address(ALLOWANCE_HOLDER); assembly ("memory-safe") { let ptr := mload(0x40) mstore(add(0x80, ptr), amount) mstore(add(0x60, ptr), recipient) mstore(add(0x4c, ptr), shl(0x60, owner)) // clears `recipient`'s padding mstore(add(0x2c, ptr), shl(0x60, token)) // clears `owner`'s padding mstore(add(0x0c, ptr), 0x15dacbea000000000000000000000000) // selector for `transferFrom(address,address,address,uint256)` with `token`'s padding // Although `transferFrom` returns `bool`, we don't need to bother checking the return // value because `AllowanceHolder` always either reverts or returns `true`. We also // don't need to check that it has code. if iszero(call(gas(), _ALLOWANCE_HOLDER, 0x00, add(0x1c, ptr), 0x84, 0x00, 0x00)) { let ptr_ := mload(0x40) returndatacopy(ptr_, 0x00, returndatasize()) revert(ptr_, returndatasize()) } } } modifier takerSubmitted() override { address msgSender = _operator(); TransientStorage.setPayer(msgSender); _; TransientStorage.clearPayer(msgSender); } modifier metaTx(address, bytes32) override { revert(); _; } // Solidity inheritance is stupid function _isForwarded() internal view virtual override(AbstractContext, Context, AllowanceHolderContext) returns (bool) { return super._isForwarded(); } function _msgData() internal view virtual override(AbstractContext, Context, AllowanceHolderContext) returns (bytes calldata) { return super._msgData(); } function _msgSender() internal view virtual override(AllowanceHolderContext, Permit2PaymentBase) returns (address) { return super._msgSender(); } } // DANGER: the order of the base contracts here is very significant for the use of `super` below // (and in derived contracts). Do not change this order. abstract contract Permit2PaymentMetaTxn is Context, Permit2Payment { constructor() { assert(_hasMetaTxn()); assert( keccak256(bytes(Permit2PaymentMetaTxn._witnessTypeSuffix())) == keccak256( abi.encodePacked( "SlippageAndActions slippageAndActions)", SLIPPAGE_AND_ACTIONS_TYPE, TOKEN_PERMISSIONS_TYPE ) ) ); } function _permitToSellAmountCalldata(ISignatureTransfer.PermitTransferFrom calldata permit) internal view virtual override returns (uint256) { return permit.permitted.amount; } function _permitToSellAmount(ISignatureTransfer.PermitTransferFrom memory permit) internal view virtual override returns (uint256) { return permit.permitted.amount; } function _witnessTypeSuffix() internal pure virtual returns (string memory) { return "SlippageAndActions slippageAndActions)SlippageAndActions(address recipient,address buyToken,uint256 minAmountOut,bytes[] actions)TokenPermissions(address token,uint256 amount)"; } function _transferFrom( ISignatureTransfer.PermitTransferFrom memory permit, ISignatureTransfer.SignatureTransferDetails memory transferDetails, bytes memory sig, bool isForwarded // must be false ) internal override { bytes32 witness = TransientStorage.getAndClearWitness(); if (witness == bytes32(0)) { revertConfusedDeputy(); } _transferFromIKnowWhatImDoing( permit, transferDetails, _msgSender(), witness, _witnessTypeSuffix(), sig, isForwarded ); } function _allowanceHolderTransferFrom(address, address, address, uint256) internal pure override { revertConfusedDeputy(); } modifier takerSubmitted() override { revert(); _; } modifier metaTx(address msgSender, bytes32 witness) override { if (_isForwarded()) { assembly ("memory-safe") { mstore(0x00, 0x1c500e5c) // selector for `ForwarderNotAllowed()` revert(0x1c, 0x04) } } if (_operator() == msgSender) { revertConfusedDeputy(); } TransientStorage.setWitness(witness); TransientStorage.setPayer(msgSender); _; TransientStorage.clearPayer(msgSender); // It should not be possible for this check to revert because the very first thing that a // metatransaction does is spend the witness. TransientStorage.checkSpentWitness(); } // Solidity inheritance is stupid function _msgSender() internal view virtual override(Context, Permit2PaymentBase) returns (address) { return super._msgSender(); } } abstract contract Permit2PaymentIntent is Permit2PaymentMetaTxn { using FullMath for uint256; using SafeTransferLib for IERC20; constructor() { assert( keccak256(bytes(Permit2PaymentIntent._witnessTypeSuffix())) == keccak256(abi.encodePacked("Slippage slippage)", SLIPPAGE_TYPE, TOKEN_PERMISSIONS_TYPE)) ); } function _witnessTypeSuffix() internal pure virtual override returns (string memory) { return "Slippage slippage)Slippage(address recipient,address buyToken,uint256 minAmountOut)TokenPermissions(address token,uint256 amount)"; } bytes32 private constant _BRIDGE_WALLET_CODEHASH = 0xe98f46388916ca2f096ea767dc04dddb45d2ca2c2f44e7bcc529d6aded9c11f0; function _toCanonicalSellAmount(IERC20 token, uint256 sellAmount) private view returns (uint256) { unchecked { if (~sellAmount < BASIS) { if (_msgSender().codehash == _BRIDGE_WALLET_CODEHASH) { sellAmount = BASIS - ~sellAmount; sellAmount = token.fastBalanceOf(_msgSender()).unsafeMulDiv(sellAmount, BASIS); } } } return sellAmount; } function _permitToSellAmountCalldata(ISignatureTransfer.PermitTransferFrom calldata permit) internal view virtual override returns (uint256 sellAmount) { sellAmount = _toCanonicalSellAmount(IERC20(permit.permitted.token), permit.permitted.amount); } function _permitToSellAmount(ISignatureTransfer.PermitTransferFrom memory permit) internal view virtual override returns (uint256 sellAmount) { sellAmount = _toCanonicalSellAmount(IERC20(permit.permitted.token), permit.permitted.amount); } } // src/SettlerBase.sol /// @dev This library's ABIDecoding is more lax than the Solidity ABIDecoder. This library omits index bounds/overflow /// checking when accessing calldata arrays for gas efficiency. It also omits checks against `calldatasize()`. This /// means that it is possible that `args` will run off the end of calldata and be implicitly padded with zeroes. That we /// don't check for overflow means that offsets can be negative. This can also result in `args` that alias other parts /// of calldata, or even the `actions` array itself. library CalldataDecoder { function decodeCall(bytes[] calldata data, uint256 i) internal pure returns (uint256 selector, bytes calldata args) { assembly ("memory-safe") { // initially, we set `args.offset` to the pointer to the length. this is 32 bytes before the actual start of data args.offset := add( data.offset, // We allow the indirection/offset to `calls[i]` to be negative calldataload(i) ) // now we load `args.length` and set `args.offset` to the start of data args.length := calldataload(args.offset) args.offset := add(0x20, args.offset) // slice off the first 4 bytes of `args` as the selector selector := shr(0xe0, calldataload(args.offset)) args.length := sub(args.length, 0x04) args.offset := add(0x04, args.offset) } } } abstract contract SettlerBase is ISettlerBase, Basic, RfqOrderSettlement, UniswapV3Fork, UniswapV2, Velodrome { using SafeTransferLib for IERC20; using SafeTransferLib for address payable; receive() external payable {} event GitCommit(bytes20 indexed); // When/if you change this, you must make corresponding changes to // `sh/deploy_new_chain.sh` and 'sh/common_deploy_settler.sh' to set // `constructor_args`. constructor(bytes20 gitCommit) { if (block.chainid != 31337) { emit GitCommit(gitCommit); assert(IERC721Owner(DEPLOYER).ownerOf(_tokenId()) == address(this)); } else { assert(gitCommit == bytes20(0)); } } function _div512to256(uint512 n, uint512 d) internal view virtual override returns (uint256) { return n.div(d); } function _mandatorySlippageCheck() internal pure virtual returns (bool) { return false; } function _checkSlippageAndTransfer(AllowedSlippage calldata slippage) internal { // This final slippage check effectively prohibits custody optimization on the // final hop of every swap. This is gas-inefficient. This is on purpose. Because // ISettlerActions.BASIC could interact with an intents-based settlement // mechanism, we must ensure that the user's want token increase is coming // directly from us instead of from some other form of exchange of value. (address payable recipient, IERC20 buyToken, uint256 minAmountOut) = (slippage.recipient, slippage.buyToken, slippage.minAmountOut); if (_mandatorySlippageCheck()) { require(minAmountOut != 0); } else if (minAmountOut == 0 && address(buyToken) == address(0)) { return; } bool isETH = (buyToken == ETH_ADDRESS); uint256 amountOut = isETH ? address(this).balance : buyToken.fastBalanceOf(address(this)); if (amountOut < minAmountOut) { revertTooMuchSlippage(buyToken, minAmountOut, amountOut); } if (isETH) { recipient.safeTransferETH(amountOut); } else { buyToken.safeTransfer(recipient, amountOut); } } function _dispatch(uint256, uint256 action, bytes calldata data) internal virtual override returns (bool) { //// NOTICE: This function has been largely copy/paste'd into //// `src/chains/Mainnet/Common.sol:MainnetMixin._dispatch`. If you make changes here, you //// need to make sure that corresponding changes are made to that function. if (action == uint32(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 == uint32(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 == uint32(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 == uint32(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 == uint32(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 == uint32(ISettlerActions.POSITIVE_SLIPPAGE.selector)) { (address payable recipient, IERC20 token, uint256 expectedAmount) = abi.decode(data, (address, IERC20, uint256)); bool isETH = (token == ETH_ADDRESS); uint256 balance = isETH ? address(this).balance : token.fastBalanceOf(address(this)); if (balance > expectedAmount) { unchecked { balance -= expectedAmount; } if (isETH) { recipient.safeTransferETH(balance); } else { token.safeTransfer(recipient, balance); } } } else { return false; } return true; } } // src/chains/Katana/Common.sol // Solidity inheritance is stupid abstract contract KatanaMixin is FreeMemory, SettlerBase { constructor() { assert(block.chainid == 747474 || block.chainid == 31337); } function _dispatch(uint256 i, uint256 action, bytes calldata data) internal virtual override(/* SettlerAbstract, */ SettlerBase) DANGEROUS_freeMemory returns (bool) { // This does not make use of `super._dispatch`. This chain's Settler is extremely // stripped-down and has almost no capabilities if (action == uint32(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 { return false; } return true; } function _uniV3ForkInfo(uint8 forkId) internal pure override returns (address factory, bytes32 initHash, uint32 callbackSelector) { revertUnknownForkId(forkId); } } // src/SettlerMetaTxn.sol abstract contract SettlerMetaTxn is ISettlerMetaTxn, Permit2PaymentMetaTxn, SettlerBase { using UnsafeMath for uint256; using CalldataDecoder for bytes[]; function _tokenId() internal pure virtual override returns (uint256) { return 3; } function _hasMetaTxn() internal pure override returns (bool) { return true; } function _hashArrayOfBytes(bytes[] calldata actions) internal pure returns (bytes32 result) { // This function deliberately does no bounds checking on `actions` for // gas efficiency. We assume that `actions` will get used elsewhere in // this context and any OOB or other malformed calldata will result in a // revert later. assembly ("memory-safe") { let ptr := mload(0x40) let hashesLength := shl(0x05, actions.length) for { let i := actions.offset let dst := ptr let end := add(i, hashesLength) } lt(i, end) { i := add(0x20, i) dst := add(0x20, dst) } { let src := add(calldataload(i), actions.offset) let length := calldataload(src) calldatacopy(dst, add(0x20, src), length) mstore(dst, keccak256(dst, length)) } result := keccak256(ptr, hashesLength) } } function _hashActionsAndSlippage(bytes[] calldata actions, AllowedSlippage calldata slippage) internal pure returns (bytes32 result) { // This function does not check for or clean any dirty bits that might // exist in `slippage`. We assume that `slippage` will be used elsewhere // in this context and that if there are dirty bits it will result in a // revert later. bytes32 arrayOfBytesHash = _hashArrayOfBytes(actions); assembly ("memory-safe") { let ptr := mload(0x40) mstore(ptr, SLIPPAGE_AND_ACTIONS_TYPEHASH) calldatacopy(add(0x20, ptr), slippage, 0x60) mstore(add(0x80, ptr), arrayOfBytesHash) result := keccak256(ptr, 0xa0) } } function _dispatchVIP(uint256 action, bytes calldata data, bytes calldata sig) internal virtual returns (bool) { if (action == uint32(ISettlerActions.METATXN_TRANSFER_FROM.selector)) { (address recipient, ISignatureTransfer.PermitTransferFrom memory permit) = abi.decode(data, (address, ISignatureTransfer.PermitTransferFrom)); (ISignatureTransfer.SignatureTransferDetails memory transferDetails,) = _permitToTransferDetails(permit, recipient); // We simultaneously transfer-in the taker's tokens and authenticate the // metatransaction. _transferFrom(permit, transferDetails, sig); } /* // METATXN_RFQ_VIP is temporarily removed because Solver has no support // for it. When support for METATXN_RFQ_VIP is reenabled, the test // testSettler_metaTxn_rfq should be reenabled else if (action == uint32(ISettlerActions.METATXN_RFQ_VIP.selector)) { // An optimized path involving a maker/taker in a single trade // The RFQ order is signed by both maker and taker, validation is // performed inside the RfqOrderSettlement so there is no need to // validate `sig` against `actions` here ( 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 == uint32(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, bytes calldata sig) internal returns (bool) { require(actions.length != 0); uint256 it; assembly ("memory-safe") { it := actions.offset } { (uint256 action, bytes calldata data) = actions.decodeCall(it); // By forcing the first action to be one of the witness-aware // actions, we ensure that the entire sequence of actions is // authorized. `msgSender` is the signer of the metatransaction. if (!_dispatchVIP(action, data, sig)) { revertActionInvalid(0, action, data); } } it = it.unsafeAdd(32); for (uint256 i = 1; i < actions.length; (i, it) = (i.unsafeInc(), it.unsafeAdd(32))) { (uint256 action, bytes calldata data) = actions.decodeCall(it); if (!_dispatch(i, action, data)) { revertActionInvalid(i, action, data); } } _checkSlippageAndTransfer(slippage); return true; } function executeMetaTxn( AllowedSlippage calldata slippage, bytes[] calldata actions, bytes32 /* zid & affiliate */, address msgSender, bytes calldata sig ) public virtual override metaTx(msgSender, _hashActionsAndSlippage(actions, slippage)) returns (bool) { return _executeMetaTxn(slippage, actions, sig); } // Solidity inheritance is stupid function _msgSender() internal view virtual override(Permit2PaymentMetaTxn, AbstractContext) returns (address) { return super._msgSender(); } } // src/chains/Katana/MetaTxn.sol // Solidity inheritance is stupid /// @custom:security-contact [email protected] contract KatanaSettlerMetaTxn is SettlerMetaTxn, KatanaMixin { constructor(bytes20 gitCommit) SettlerBase(gitCommit) {} function _dispatchVIP(uint256 action, bytes calldata data, bytes calldata sig) internal virtual override DANGEROUS_freeMemory returns (bool) { // This does not make use of `super._dispatchVIP`. This chain's Settler is extremely // stripped-down and has almost no capabilities if (action == uint32(ISettlerActions.METATXN_TRANSFER_FROM.selector)) { (address recipient, ISignatureTransfer.PermitTransferFrom memory permit) = abi.decode(data, (address, ISignatureTransfer.PermitTransferFrom)); (ISignatureTransfer.SignatureTransferDetails memory transferDetails,) = _permitToTransferDetails(permit, recipient); // We simultaneously transfer-in the taker's tokens and authenticate the // metatransaction. _transferFrom(permit, transferDetails, sig); } else { return false; } return true; } // Solidity inheritance is stupid function _dispatch(uint256 i, uint256 action, bytes calldata data) internal virtual override(SettlerAbstract, SettlerBase, KatanaMixin) returns (bool) { return super._dispatch(i, action, data); } function _msgSender() internal view virtual override(SettlerMetaTxn, AbstractContext) returns (address) { return super._msgSender(); } } // src/SettlerIntent.sol // DANGER: do not reorder the inheritance list here. You will get shocking and incorrect results // inside `MultiCallContext` if `super._msgSender` is `Permit2PaymentMetaTxn._msgSender`. abstract contract SettlerIntent is MultiCallContext, Permit2PaymentIntent, SettlerMetaTxn { bytes32 private constant _SOLVER_LIST_BASE_SLOT = 0x000000000000000000000000000000000000000008054751d605e5c08a2210bf; // uint96(uint256(keccak256("SettlerIntentSolverList")) - 1) /// This mapping forms a circular singly-linked list that traverses all the authorized callers /// of `executeMetaTxn`. The head and tail of the list is `address(1)`, which is the constant /// `_SENTINEL_SOLVER`. As a consequence of the structure of this list, the check for whether an /// address is on the list is extremely simple: `_$()[query] != address(0)`. This technique is /// cribbed from Safe{Wallet} function _$() private pure returns (mapping(address => address) storage $) { assembly ("memory-safe") { $.slot := _SOLVER_LIST_BASE_SLOT } } address private constant _SENTINEL_SOLVER = 0x0000000000000000000000000000000000000001; constructor() { assert(_SOLVER_LIST_BASE_SLOT == bytes32(uint256(uint96(uint256(keccak256("SettlerIntentSolverList")) - 1)))); _$()[_SENTINEL_SOLVER] = _SENTINEL_SOLVER; } function owner() public view returns (address owner_) { // Solidity generates extremely bloated code for the following block, so it has been // rewritten in assembly so as not to blow out the contract size limit /* (address owner_, uint40 expiry) = IDeployer(DEPLOYER).authorized(Feature.wrap(uint128(_tokenId()))); */ address deployer_ = DEPLOYER; uint256 tokenId_ = _tokenId(); assembly ("memory-safe") { // We lay out the calldata in memory in the first 2 slots. The first slot is the // selector, but aligned incorrectly (this significantly saves on contract size). The // second slot is the token ID. Therefore calldata starts at offset 0x1c (32 - 4) and is // 0x24 bytes long (32 + 4) mstore(0x00, 0x2bb83987) // selector for `authorized(uint128)` mstore(0x20, tokenId_) // Perform the call and bubble any revert. The expected returndata (2 arguments, each 1 // slot) is copied back into the first 2 slots of memory. if iszero(staticcall(gas(), deployer_, 0x1c, 0x24, 0x00, 0x40)) { let ptr := mload(0x40) returndatacopy(ptr, 0x00, returndatasize()) revert(ptr, returndatasize()) } // If returndata is short (we need at least 64 bytes), revert with an empty reason. if lt(returndatasize(), 0x40) { revert(0x00, 0x00) } // Load the return values that were automatically written into the first 2 slots of // memory. owner_ := mload(0x00) let expiry := mload(0x20) // If there are any dirty bits in the return values, revert with an empty // reason. Likewise, if `expiry` has elapsed, there is no owner; revert with an empty // reason. if or(gt(timestamp(), expiry), or(shr(0xa0, owner_), shr(0x28, expiry))) { revert(0x00, 0x00) } } } modifier onlyOwner() { // Check that the caller (in this case `_operator()`, because we aren't using the special // transient-storage taker logic) is the owner. address operator = _operator(); address owner_ = owner(); assembly ("memory-safe") { if shl(0x60, xor(operator, owner_)) { mstore(0x00, 0x1e092104) // selector for `PermissionDenied()` revert(0x1c, 0x04) } } _; } modifier onlySolver() { address operator = _operator(); assembly ("memory-safe") { mstore(0x00, and(0xffffffffffffffffffffffffffffffffffffffff, operator)) mstore(0x20, _SOLVER_LIST_BASE_SLOT) if iszero(shl(0x60, sload(keccak256(0x00, 0x40)))) { mstore(0x00, 0x1e092104) // selector for `PermissionDenied()` revert(0x1c, 0x04) } } _; } error InvalidSolver(address prev, address solver); /// This pattern is cribbed from Safe{Wallet}. See `OwnerManager.sol` from /// 0x3E5c63644E683549055b9Be8653de26E0B4CD36E. function setSolver(address prev, address solver, bool addNotRemove) external onlyOwner { // Solidity generates extremely bloated code for the following block, so it has been // rewritten in assembly so as not to blow out the contract size limit /* require(solver != address(0)); mapping(address => address) storage $ = _$(); require(($[solver] == address(0)) == addNotRemove); if (addNotRemove) { require($[prev] == _SENTINEL_SOLVER); $[prev] = solver; $[solver] = _SENTINEL_SOLVER; } else { require($[prev] == solver); $[prev] = $[solver]; $[solver] = address(0); } */ assembly ("memory-safe") { // Clean dirty bits. prev := shr(0x60, shl(0x60, prev)) solver := shr(0x60, shl(0x60, solver)) // A solver of zero is special-cased. It is forbidden to set it because that would // corrupt the list. let fail := iszero(solver) // Derive the slot for `solver` and load it. mstore(0x00, solver) mstore(0x20, _SOLVER_LIST_BASE_SLOT) let solverSlot := keccak256(0x00, 0x40) let solverSlotValue := shr(0x60, shl(0x60, sload(solverSlot))) // If the slot contains zero, `addNotRemove` must be true (we are adding a new // solver). Likewise if the slot contains nonzero, `addNotRemove` must be false (we are // removing one). fail := or(xor(iszero(solverSlotValue), addNotRemove), fail) // Derive the slot for `prev`. mstore(0x00, prev) let prevSlot := keccak256(0x00, 0x40) // This is a very fancy way of writing: // expectedPrevSlotValue = addNotRemove ? _SENTINEL_SOLVER : solver // newPrevSlotValue = addNotRemove ? solver : solverSlotValue let expectedPrevSlotValue := xor(solver, mul(xor(_SENTINEL_SOLVER, solver), addNotRemove)) let newPrevSlotValue := xor(solverSlotValue, mul(xor(solverSlotValue, solver), addNotRemove)) // Check that the value for `prev` matches the value for `solver`. If we are adding a // new solver, then `prev` must be the last element of the list (it points at // `_SENTINEL_SOLVER`). If we are removing an existing solver, then `prev` must point at // `solver`. fail := or(shl(0x60, xor(sload(prevSlot), expectedPrevSlotValue)), fail) // Update the linked list. This either points `$[prev]` at `$[solver]` and zeroes // `$[solver]` or it points `$[prev]` at `solver` and points `$[solver]` at // `_SENTINEL_SOLVER` sstore(prevSlot, newPrevSlotValue) sstore(solverSlot, addNotRemove) // If any of the checks failed, revert. This check is deferred because it makes the // contract substantially smaller. if fail { mstore(0x00, 0xe2b339fd) // selector for `InvalidSolver(address,address)` mstore(0x20, prev) mstore(0x40, solver) revert(0x1c, 0x44) } } } /// This function is not intended to be called on-chain. It's only for being `eth_call`'d. There /// is a somewhat obvious DoS vector here if called on-chain, so just don't do that. function getSolvers() external view returns (address[] memory) { // This function is roughly /* address[] memory result = new address[](); mapping(address => address) storage $ = _$(); address cursor = $[_SENTINEL_SOLVER]; uint256 i; for (; cursor != _SENTINEL_SOLVER; i++) { result[i] = cursor; cursor = $[cursor]; } result.length = i; return result; */ assembly ("memory-safe") { let ptr := mload(0x40) let len { let start := add(0x40, ptr) let i := start for { mstore(0x20, _SOLVER_LIST_BASE_SLOT) mstore(0x00, _SENTINEL_SOLVER) let x := shr(0x60, shl(0x60, sload(keccak256(0x00, 0x40)))) } xor(_SENTINEL_SOLVER, x) { i := add(0x20, i) x := shr(0x60, shl(0x60, sload(keccak256(0x00, 0x40)))) } { mstore(i, x) mstore(0x00, x) } len := sub(i, start) } mstore(ptr, 0x20) mstore(add(0x20, ptr), shr(0x05, len)) return(ptr, add(0x40, len)) } } function _tokenId() internal pure virtual override(SettlerAbstract, SettlerMetaTxn) returns (uint256) { return 4; } function _mandatorySlippageCheck() internal pure virtual override returns (bool) { return true; } function _hashSlippage(AllowedSlippage calldata slippage) internal pure returns (bytes32 result) { // This function does not check for or clean any dirty bits that might // exist in `slippage`. We assume that `slippage` will be used elsewhere // in this context and that if there are dirty bits it will result in a // revert later. assembly ("memory-safe") { let ptr := mload(0x40) mstore(ptr, SLIPPAGE_TYPEHASH) calldatacopy(add(0x20, ptr), slippage, 0x60) result := keccak256(ptr, 0x80) } } function executeMetaTxn( AllowedSlippage calldata slippage, bytes[] calldata actions, bytes32 /* zid & affiliate */, address msgSender, bytes calldata sig ) public virtual override onlySolver metaTx(msgSender, _hashSlippage(slippage)) returns (bool) { return _executeMetaTxn(slippage, actions, sig); } function _isForwarded() internal view virtual override(AbstractContext, Context, MultiCallContext) returns (bool) { return Context._isForwarded(); // false } // Solidity inheritance is stupid function _msgSender() internal view virtual override(Permit2PaymentMetaTxn, SettlerMetaTxn, MultiCallContext) returns (address) { return super._msgSender(); } function _msgData() internal view virtual override(AbstractContext, Context, MultiCallContext) returns (bytes calldata) { return super._msgData(); } function _witnessTypeSuffix() internal pure virtual override(Permit2PaymentMetaTxn, Permit2PaymentIntent) returns (string memory) { return super._witnessTypeSuffix(); } function _permitToSellAmountCalldata(ISignatureTransfer.PermitTransferFrom calldata permit) internal view virtual override(Permit2PaymentAbstract, Permit2PaymentMetaTxn, Permit2PaymentIntent) returns (uint256) { return super._permitToSellAmountCalldata(permit); } function _permitToSellAmount(ISignatureTransfer.PermitTransferFrom memory permit) internal view virtual override(Permit2PaymentAbstract, Permit2PaymentMetaTxn, Permit2PaymentIntent) returns (uint256) { return super._permitToSellAmount(permit); } } // src/chains/Katana/Intent.sol // Solidity inheritance is stupid /// @custom:security-contact [email protected] contract KatanaSettlerIntent is SettlerIntent, KatanaSettlerMetaTxn { constructor(bytes20 gitCommit) KatanaSettlerMetaTxn(gitCommit) {} // Solidity inheritance is stupid function executeMetaTxn( AllowedSlippage calldata slippage, bytes[] calldata actions, bytes32, /* zid & affiliate */ address msgSender, bytes calldata sig ) public override(SettlerIntent, SettlerMetaTxn) returns (bool) { return super.executeMetaTxn(slippage, actions, bytes32(0), msgSender, sig); } function _dispatch(uint256 i, uint256 action, bytes calldata data) internal override(KatanaSettlerMetaTxn, SettlerBase, SettlerAbstract) returns (bool) { return super._dispatch(i, action, data); } function _isForwarded() internal view override(AbstractContext, Context, SettlerIntent) returns (bool) { return super._isForwarded(); } function _msgData() internal view override(AbstractContext, Context, SettlerIntent) returns (bytes calldata) { return super._msgData(); } function _msgSender() internal view override(SettlerIntent, KatanaSettlerMetaTxn) returns (address) { return super._msgSender(); } function _witnessTypeSuffix() internal pure override(SettlerIntent, Permit2PaymentMetaTxn) returns (string memory) { return super._witnessTypeSuffix(); } function _mandatorySlippageCheck() internal pure override(SettlerBase, SettlerIntent) returns (bool) { return super._mandatorySlippageCheck(); } function _tokenId() internal pure override(SettlerIntent, SettlerMetaTxn, SettlerAbstract) returns (uint256) { return super._tokenId(); } function _dispatchVIP(uint256 action, bytes calldata data, bytes calldata sig) internal override(KatanaSettlerMetaTxn, SettlerMetaTxn) returns (bool) { return super._dispatchVIP(action, data, sig); } function _permitToSellAmountCalldata(ISignatureTransfer.PermitTransferFrom calldata permit) internal view override(SettlerIntent, Permit2PaymentAbstract, Permit2PaymentMetaTxn) returns (uint256) { return super._permitToSellAmountCalldata(permit); } function _permitToSellAmount(ISignatureTransfer.PermitTransferFrom memory permit) internal view override(SettlerIntent, Permit2PaymentAbstract, Permit2PaymentMetaTxn) returns (uint256) { return super._permitToSellAmount(permit); } }
{ "remappings": [ "@solmate/=lib/solmate/src/", "@permit2/=lib/permit2/src/", "@forge-std/=lib/forge-std/src/", "@forge-gas-snapshot/=lib/forge-gas-snapshot/src/", "@uniswapv4/=lib/v4-core/src/", "@eulerswap/=lib/euler-swap/src/", "forge-std/src/=lib/forge-std/src/", "solmate/=lib/solmate/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 2000, "details": { "constantOptimizer": true, "yul": true } }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": false }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": true }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"bytes20","name":"gitCommit","type":"bytes20"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidOffset","type":"error"},{"inputs":[{"internalType":"address","name":"prev","type":"address"},{"internalType":"address","name":"solver","type":"address"}],"name":"InvalidSolver","type":"error"},{"inputs":[],"name":"InvalidTarget","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes20","name":"","type":"bytes20"}],"name":"GitCommit","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[{"components":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"internalType":"struct ISettlerBase.AllowedSlippage","name":"slippage","type":"tuple"},{"internalType":"bytes[]","name":"actions","type":"bytes[]"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"msgSender","type":"address"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"executeMetaTxn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getSolvers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"prev","type":"address"},{"internalType":"address","name":"solver","type":"address"},{"internalType":"bool","name":"addNotRemove","type":"bool"}],"name":"setSolver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040908082523461055757806116b8803803809161001f82856105bb565b833960209283918101031261055757516001600160601b03198116908190036105575761007a61004d610747565b8381519101207f615e8d716cef7295e75dd3f1f10d679914ad6d7759e8e9459f0109ef75241701146105de565b6100b261008561067e565b8381519101207fdc83993a2ffc65b01b71ed08790b6e39c5c55d76937b62a3b5085b02071f1259146105de565b82516001600160401b039060e08101908282118183101761058c5761021a91865260af815260af8582016e75696e7432353620616d6f756e742960881b60c07f536c697070616765416e64416374696f6e7320736c697070616765416e644163948584527f74696f6e7329536c697070616765416e64416374696f6e7328616464726573738b8201527f20726563697069656e742c6164647265737320627579546f6b656e2c75696e7460608201527f323536206d696e416d6f756e744f75742c62797465735b5d20616374696f6e7360808201527f29546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c60a0820152015220906574696f6e732960d01b610211604689896101ca610747565b816101d36106e7565b9184519788958387019a8b528601528051918291018686015e8301908482015f8152815193849201905e015f838201520360268101845201826105bb565b519020146105de565b83519060c082019081118282101761058c57610341916081918652818152602960f81b60a0868301927f536c69707061676520736c69707061676529536c69707061676528616464726584527f737320726563697069656e742c6164647265737320627579546f6b656e2c7569898201527f6e74323536206d696e416d6f756e744f757429546f6b656e5065726d6973736960608201527f6f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7460808201520152206102e261067e565b8461021160326102f06106e7565b8951938491818084019771536c69707061676520736c6970706167652960701b89528051918291018686015e8301908482015f8152815193849201905e015f838201520360128101845201826105bb565b61037961034c6105f9565b8381519101207f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa146105de565b6104528351610387816105a0565b604b81528381017f5266714f7264657228436f6e73696465726174696f6e206d616b6572436f6e7381527f696465726174696f6e2c436f6e73696465726174696f6e2074616b6572436f6e868301526a73696465726174696f6e2960a81b6060830152610428856103f66105f9565b9281895194859282840197518091895e8301908282015f8152815193849201905e015f838201520380845201826105bb565b5190207f49fa719b76f0f6b7e76be94b56c26671a548e1c712d5b13dc2874f70a7598276146105de565b46617a6914908161056c578351907f16fbd3a71aa6d159973eb9ff1e1199f9fe242767e6f30ac662a492f92ac704115f80a26331a9108f60e11b815260048082015282816024816d04533fe15556b1e086bb1a72ceae5afa908115610562575f9161051f575b5061050a926b08054751d605e5c08a2210bf916104df906001600160a01b031630146105de565b60015f5252825f206001808060a01b0319825416179055620b67d24614908115610517575b506105de565b51610eeb90816107cd8239f35b90505f610504565b90508281813d831161055b575b61053681836105bb565b8101031261055757516001600160a01b03811681036105575761050a6104b8565b5f80fd5b503d61052c565b84513d5f823e3d90fd5b61050a926105876b08054751d605e5c08a2210bf92156105de565b6104df565b634e487b7160e01b5f52604160045260245ffd5b608081019081106001600160401b0382111761058c57604052565b601f909101601f19168101906001600160401b0382119082101761058c57604052565b156105e557565b634e487b7160e01b5f52600160045260245ffd5b60405190610606826105a0565b605882527f626f6f6c207061727469616c46696c6c416c6c6f7765642900000000000000006060837f436f6e73696465726174696f6e286164647265737320746f6b656e2c75696e7460208201527f32353620616d6f756e742c6164647265737320636f756e74657270617274792c60408201520152565b6040519061068b826105a0565b60418252602960f81b6060837f536c697070616765286164647265737320726563697069656e742c616464726560208201527f737320627579546f6b656e2c75696e74323536206d696e416d6f756e744f757460408201520152565b60405190606082016001600160401b0381118382101761058c57604052602e82526d696e7432353620616d6f756e742960901b6040837f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c7560208201520152565b60405190610754826105a0565b605b82527f6e416d6f756e744f75742c62797465735b5d20616374696f6e732900000000006060837f536c697070616765416e64416374696f6e73286164647265737320726563697060208201527f69656e742c6164647265737320627579546f6b656e2c75696e74323536206d696040820152015256fe60806040526004361015610073575b3615610071573461006d576bcdccd5c65a7d4860ce3abbe9805c80331860601b905f351860e01c1761006d575f905d336ccf9e3c5a26621af382fa17f24f14601402360360041161006d57634e487b7160e01b5f52605160045260245ffd5b5f80fd5b005b5f3560e01c80634b7758a5146106045780638bc1e8eb1461056a5780638da5cb5b1461053f5763fd3ad6d40361000e573461006d57600319360160e0811261006d5760601361006d5767ffffffffffffffff806064351161006d5736602360643501121561006d5780606435600401351161006d573660246064356004013560051b60643501011161006d576001600160a01b0360a43516908160a4350361006d5760c4359181831161006d573660238401121561006d57826004013591821161006d57366024838501011161006d57610170336ccf9e3c5a26621af382fa17f24f1860601b1536600310163360131936013560601c1802331890565b90816001600160a01b03165f526b08054751d605e5c08a2210bf60205260405f205460601b15610532576001600160a01b0360806040517fdc83993a2ffc65b01b71ed08790b6e39c5c55d76937b62a3b5085b02071f1259815260606004826020013720921614610515576bc7aebfbc05485e093720deaa5c8061052257506bc7aebfbc05485e093720deaa5d60a43560601b15610515576bcd1e9517bb0cb8d0d5cde8935c8060601b6104f9575060a4356001600160a01b03166bcd1e9517bb0cb8d0d5cde8935d606435600401351561006d57602460643501356064350160248101359060448101359261027b604860031985019301916024604051970184848860e01c6107e1565b85604052156104ab5760016064356044015b606435600401358210610412576004356001600160a01b0381169081810361006d576024356001600160a01b0381169283820361006d5760443593841561006d5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156104025747945b8086106103dd5750156103785750505f80809381935af11561036d575b60a4356bcd1e9517bb0cb8d0d5cde8935c1860601b610360575f6bcd1e9517bb0cb8d0d5cde8935d6bc7aebfbc05485e093720deaa5c8061035057602060405160018152f35b63e25527c25f526020526024601cfd5b635149e7955f526004601cfd5b6040513d5f823e3d90fd5b5f8093506044926020956010936014526034526fa9059cbb00000000000000000000000082525af1156103cd573d153d601f1060015f51141617156103c0575f60345261030a565b6390b8ec185f526004601cfd5b60405162ffffff163d5f823e3d90fd5b8390866054526034526014526f97a6f3b90000000000000000000000005f5260646010fd5b61040c3084610aaf565b946102ed565b80356064350160248101356044820135916048600319830191016040519361043e83838360e01c610ae3565b856040521561045a57505050505060206001910191019061028d565b8495507fffffffff000000000000000000000000000000000000000000000000000000009087633c74eed660809752876020015216856040015260608581015281858501528460a001370190601c01fd5b7fffffffff00000000000000000000000000000000000000000000000000000000608094633c74eed687525f876020015216856040015260608581015281858501528460a001370190601c01fd5b6014526f7407c0f80000000000000000000000005f5260246010fd5b63e758b8d55f526004601cfd5b639936cbab5f526020526024601cfd5b631e0921045f526004601cfd5b3461006d575f60031936011261006d5760206105596106f2565b6001600160a01b0360405191168152f35b3461006d575f60031936011261006d57604051808060400160206b08054751d605e5c08a2210bf60205260019060015f526001600160a01b03908160405f2054165b8084036105ea57505050500390602081527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820160051c8160200152f35b8085525f90815260409020548695509381019382166105ac565b3461006d57606060031936011261006d576004356001600160a01b039081811680910361006d576024359180831680930361006d57604435801515810361006d57610672336ccf9e3c5a26621af382fa17f24f1860601b1536600310163360131936013560601c1802331890565b61067a6106f2565b1860601b61053257835f526b08054751d605e5c08a2210bf60205260405f209182541691835f5260405f2085158385151817838760011802871882541860601b17938387821802189055556106cb57005b63e2b339fd5f526020526040526044601cfd5b35906001600160a01b038216820361006d57565b632bb839875f52600460205260405f6024601c6d04533fe15556b1e086bb1a72ceae5afa1561036d5760403d1061006d575f51906020518060281c8360a01c179042111761006d57565b6040810190811067ffffffffffffffff82111761075857604052565b634e487b7160e01b5f52604160045260245ffd5b90601f601f19910116810190811067ffffffffffffffff82111761075857604052565b67ffffffffffffffff811161075857601f01601f191660200190565b9291926107b78261078f565b916107c5604051938461076c565b82948184528183011161006d578281602093845f960137010152565b9093929190630dfeb41903610aa75783908101039060a0821261006d57610807846106de565b91601f1960209101936080851261006d576040958651936060850167ffffffffffffffff97868210898311176107585789908282521261006d576108bd928161085160809361073c565b61085c8783016106de565b81528a8201358389015287526060810135868801520135888601526001600160a01b039288519661088c8861073c565b84868901915f835216885286519086868351169201519182199061271091828110610a45575b5050505236916107ab565b6bc7aebfbc05485e093720deaa5f815c915d8015610515576bcd1e9517bb0cb8d0d5cde8935c88519360c0850198858a10908a111761075857895f99988a998252608187527f536c69707061676520736c69707061676529536c697070616765286164647265888801527f737320726563697069656e742c6164647265737320627579546f6b656e2c7569828801527f6e74323536206d696e416d6f756e744f757429546f6b656e5065726d6973736960608801527f6f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7460808801527f290000000000000000000000000000000000000000000000000000000000000060a08801528180519963137c29fe8b528181518c8c015e89018a6060015e8860a0015e168560e001528461010001526101408085610120015282519261016091868584019101528584860192015e805180930190828501610180015e016101840190601c01826e22d473030f116ddee9f6b43ac78ba35af115610a3c5750600190565b513d5f823e3d90fd5b6bcd1e9517bb0cb8d0d5cde893927fe98f46388916ca2f096ea767dc04dddb45d2ca2c2f44e7bcc529d6aded9c11f0845c3f14610a83575b506108b2565b610a9d94955090610a98929103925c90610aaf565b610e8f565b905f808080610a7d565b505050505f90565b602460105f926020946014526f70a0823100000000000000000000000084525afa1561036d573d601f101561006d575f5190565b9091906338c9c14703610b6a5781019060a08183031261006d5780356001600160a01b0391828216820361006d57610b1d604082016106de565b91608082013567ffffffffffffffff811161006d5782019480601f8701121561006d57610b546020918783610b65993591016107ab565b946060840135941692013590610b9f565b600190565b50505f90565b3d15610b9a573d90610b818261078f565b91610b8f604051938461076c565b82523d5f602084013e565b606090565b9291906001600160a01b03808316946e22d473030f116ddee9f6b43ac78ba38614610515575f91811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103610cea5750505061271090470204938051155f14610c48575050610c1e575f80809381935af1610c0d610b70565b9015610c165750565b602081519101fd5b60046040517f01da1572000000000000000000000000000000000000000000000000000000008152fd5b90939260208301808411610cd657825110610cc457835f9460208695850101525b602083519301915af1610c7a610b70565b9015610c165751159081610cba575b50610c9057565b60046040517f82d5d76a000000000000000000000000000000000000000000000000000000008152fd5b90503b155f610c89565b634e487b715f5260326020526024601cfd5b634e487b7160e01b5f52601160045260245ffd5b9091949281979497155f14610d0957505050610c1e575f928392610c69565b610d1a90610a989695963085610aaf565b90602093848101808211610cd657875110610e7e5784839188010152868103610d4c575b50505050905f928392610c69565b9083604492604051938480927fdd62ed3e0000000000000000000000000000000000000000000000000000000082523060048301528b60248301525afa91821561036d575f92610e4f575b508110610da5575b80610d3e565b939293610e07575b604460105f8093896014525f196034526f095ea7b300000000000000000000000082525af1156103cd573d153d601f1060015f5114161715610dfa575f9283928360345291928194610d9f565b633e3f8f735f526004601cfd5b856014525f6034526f095ea7b30000000000000000000000005f52815f6044601082855af1156103cd573d153d601f1060015f51141617610dad57633e3f8f735f526004601cfd5b9091508381813d8311610e77575b610e67818361076c565b8101031261006d5751905f610d97565b503d610e5d565b603285634e487b715f52526024601cfd5b5f1982820982820291828083109203906127109485910991808214610ee4577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91945083831191030360fc1b910360041c170290565b505050049056a2ca15a3e0b5d90d91c40619293f311b3e1b807e000000000000000000000000
Deployed Bytecode
0x60806040526004361015610073575b3615610071573461006d576bcdccd5c65a7d4860ce3abbe9805c80331860601b905f351860e01c1761006d575f905d336ccf9e3c5a26621af382fa17f24f14601402360360041161006d57634e487b7160e01b5f52605160045260245ffd5b5f80fd5b005b5f3560e01c80634b7758a5146106045780638bc1e8eb1461056a5780638da5cb5b1461053f5763fd3ad6d40361000e573461006d57600319360160e0811261006d5760601361006d5767ffffffffffffffff806064351161006d5736602360643501121561006d5780606435600401351161006d573660246064356004013560051b60643501011161006d576001600160a01b0360a43516908160a4350361006d5760c4359181831161006d573660238401121561006d57826004013591821161006d57366024838501011161006d57610170336ccf9e3c5a26621af382fa17f24f1860601b1536600310163360131936013560601c1802331890565b90816001600160a01b03165f526b08054751d605e5c08a2210bf60205260405f205460601b15610532576001600160a01b0360806040517fdc83993a2ffc65b01b71ed08790b6e39c5c55d76937b62a3b5085b02071f1259815260606004826020013720921614610515576bc7aebfbc05485e093720deaa5c8061052257506bc7aebfbc05485e093720deaa5d60a43560601b15610515576bcd1e9517bb0cb8d0d5cde8935c8060601b6104f9575060a4356001600160a01b03166bcd1e9517bb0cb8d0d5cde8935d606435600401351561006d57602460643501356064350160248101359060448101359261027b604860031985019301916024604051970184848860e01c6107e1565b85604052156104ab5760016064356044015b606435600401358210610412576004356001600160a01b0381169081810361006d576024356001600160a01b0381169283820361006d5760443593841561006d5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156104025747945b8086106103dd5750156103785750505f80809381935af11561036d575b60a4356bcd1e9517bb0cb8d0d5cde8935c1860601b610360575f6bcd1e9517bb0cb8d0d5cde8935d6bc7aebfbc05485e093720deaa5c8061035057602060405160018152f35b63e25527c25f526020526024601cfd5b635149e7955f526004601cfd5b6040513d5f823e3d90fd5b5f8093506044926020956010936014526034526fa9059cbb00000000000000000000000082525af1156103cd573d153d601f1060015f51141617156103c0575f60345261030a565b6390b8ec185f526004601cfd5b60405162ffffff163d5f823e3d90fd5b8390866054526034526014526f97a6f3b90000000000000000000000005f5260646010fd5b61040c3084610aaf565b946102ed565b80356064350160248101356044820135916048600319830191016040519361043e83838360e01c610ae3565b856040521561045a57505050505060206001910191019061028d565b8495507fffffffff000000000000000000000000000000000000000000000000000000009087633c74eed660809752876020015216856040015260608581015281858501528460a001370190601c01fd5b7fffffffff00000000000000000000000000000000000000000000000000000000608094633c74eed687525f876020015216856040015260608581015281858501528460a001370190601c01fd5b6014526f7407c0f80000000000000000000000005f5260246010fd5b63e758b8d55f526004601cfd5b639936cbab5f526020526024601cfd5b631e0921045f526004601cfd5b3461006d575f60031936011261006d5760206105596106f2565b6001600160a01b0360405191168152f35b3461006d575f60031936011261006d57604051808060400160206b08054751d605e5c08a2210bf60205260019060015f526001600160a01b03908160405f2054165b8084036105ea57505050500390602081527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820160051c8160200152f35b8085525f90815260409020548695509381019382166105ac565b3461006d57606060031936011261006d576004356001600160a01b039081811680910361006d576024359180831680930361006d57604435801515810361006d57610672336ccf9e3c5a26621af382fa17f24f1860601b1536600310163360131936013560601c1802331890565b61067a6106f2565b1860601b61053257835f526b08054751d605e5c08a2210bf60205260405f209182541691835f5260405f2085158385151817838760011802871882541860601b17938387821802189055556106cb57005b63e2b339fd5f526020526040526044601cfd5b35906001600160a01b038216820361006d57565b632bb839875f52600460205260405f6024601c6d04533fe15556b1e086bb1a72ceae5afa1561036d5760403d1061006d575f51906020518060281c8360a01c179042111761006d57565b6040810190811067ffffffffffffffff82111761075857604052565b634e487b7160e01b5f52604160045260245ffd5b90601f601f19910116810190811067ffffffffffffffff82111761075857604052565b67ffffffffffffffff811161075857601f01601f191660200190565b9291926107b78261078f565b916107c5604051938461076c565b82948184528183011161006d578281602093845f960137010152565b9093929190630dfeb41903610aa75783908101039060a0821261006d57610807846106de565b91601f1960209101936080851261006d576040958651936060850167ffffffffffffffff97868210898311176107585789908282521261006d576108bd928161085160809361073c565b61085c8783016106de565b81528a8201358389015287526060810135868801520135888601526001600160a01b039288519661088c8861073c565b84868901915f835216885286519086868351169201519182199061271091828110610a45575b5050505236916107ab565b6bc7aebfbc05485e093720deaa5f815c915d8015610515576bcd1e9517bb0cb8d0d5cde8935c88519360c0850198858a10908a111761075857895f99988a998252608187527f536c69707061676520736c69707061676529536c697070616765286164647265888801527f737320726563697069656e742c6164647265737320627579546f6b656e2c7569828801527f6e74323536206d696e416d6f756e744f757429546f6b656e5065726d6973736960608801527f6f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7460808801527f290000000000000000000000000000000000000000000000000000000000000060a08801528180519963137c29fe8b528181518c8c015e89018a6060015e8860a0015e168560e001528461010001526101408085610120015282519261016091868584019101528584860192015e805180930190828501610180015e016101840190601c01826e22d473030f116ddee9f6b43ac78ba35af115610a3c5750600190565b513d5f823e3d90fd5b6bcd1e9517bb0cb8d0d5cde893927fe98f46388916ca2f096ea767dc04dddb45d2ca2c2f44e7bcc529d6aded9c11f0845c3f14610a83575b506108b2565b610a9d94955090610a98929103925c90610aaf565b610e8f565b905f808080610a7d565b505050505f90565b602460105f926020946014526f70a0823100000000000000000000000084525afa1561036d573d601f101561006d575f5190565b9091906338c9c14703610b6a5781019060a08183031261006d5780356001600160a01b0391828216820361006d57610b1d604082016106de565b91608082013567ffffffffffffffff811161006d5782019480601f8701121561006d57610b546020918783610b65993591016107ab565b946060840135941692013590610b9f565b600190565b50505f90565b3d15610b9a573d90610b818261078f565b91610b8f604051938461076c565b82523d5f602084013e565b606090565b9291906001600160a01b03808316946e22d473030f116ddee9f6b43ac78ba38614610515575f91811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103610cea5750505061271090470204938051155f14610c48575050610c1e575f80809381935af1610c0d610b70565b9015610c165750565b602081519101fd5b60046040517f01da1572000000000000000000000000000000000000000000000000000000008152fd5b90939260208301808411610cd657825110610cc457835f9460208695850101525b602083519301915af1610c7a610b70565b9015610c165751159081610cba575b50610c9057565b60046040517f82d5d76a000000000000000000000000000000000000000000000000000000008152fd5b90503b155f610c89565b634e487b715f5260326020526024601cfd5b634e487b7160e01b5f52601160045260245ffd5b9091949281979497155f14610d0957505050610c1e575f928392610c69565b610d1a90610a989695963085610aaf565b90602093848101808211610cd657875110610e7e5784839188010152868103610d4c575b50505050905f928392610c69565b9083604492604051938480927fdd62ed3e0000000000000000000000000000000000000000000000000000000082523060048301528b60248301525afa91821561036d575f92610e4f575b508110610da5575b80610d3e565b939293610e07575b604460105f8093896014525f196034526f095ea7b300000000000000000000000082525af1156103cd573d153d601f1060015f5114161715610dfa575f9283928360345291928194610d9f565b633e3f8f735f526004601cfd5b856014525f6034526f095ea7b30000000000000000000000005f52815f6044601082855af1156103cd573d153d601f1060015f51141617610dad57633e3f8f735f526004601cfd5b9091508381813d8311610e77575b610e67818361076c565b8101031261006d5751905f610d97565b503d610e5d565b603285634e487b715f52526024601cfd5b5f1982820982820291828083109203906127109485910991808214610ee4577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91945083831191030360fc1b910360041c170290565b505050049056
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
a2ca15a3e0b5d90d91c40619293f311b3e1b807e000000000000000000000000
-----Decoded View---------------
Arg [0] : gitCommit (bytes20): 0xa2ca15a3e0b5d90d91c40619293f311b3e1b807e
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : a2ca15a3e0b5d90d91c40619293f311b3e1b807e000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.