Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts/access/Ownable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
"
},
"@openzeppelin/contracts/math/Math.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow, so we distribute
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
"
},
"@openzeppelin/contracts/math/SafeMath.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
"
},
"@openzeppelin/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
"
},
"@openzeppelin/contracts/utils/SafeCast.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128) {
require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
return int128(value);
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64) {
require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
return int64(value);
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32) {
require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
return int32(value);
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16) {
require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
return int16(value);
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8) {
require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
return int8(value);
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
require(value < 2**255, "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
"
},
"@uniswap/v3-periphery/contracts/libraries/BytesLib.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
/*
* @title Solidity Bytes Arrays Utils
* @author Gonçalo Sá <goncalo.sa@consensys.net>
*
* @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
*/
pragma solidity >=0.5.0 <0.8.0;
library BytesLib {
function slice(
bytes memory _bytes,
uint256 _start,
uint256 _length
) internal pure returns (bytes memory) {
require(_length + 31 >= _length, 'slice_overflow');
require(_start + _length >= _start, 'slice_overflow');
require(_bytes.length >= _start + _length, 'slice_outOfBounds');
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(_length, 31)
// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
//zero out the 32 bytes slice we are about to return
//we need to do it because Solidity does not garbage collect
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_start + 20 >= _start, 'toAddress_overflow');
require(_bytes.length >= _start + 20, 'toAddress_outOfBounds');
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) {
require(_start + 3 >= _start, 'toUint24_overflow');
require(_bytes.length >= _start + 3, 'toUint24_outOfBounds');
uint24 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x3), _start))
}
return tempUint;
}
}
"
},
"contracts/guards/contractGuards/odos/OdosV2ContractGuard.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;
import {TxDataUtils} from "../../../utils/TxDataUtils.sol";
import {ITransactionTypes} from "../../../interfaces/ITransactionTypes.sol";
import {SlippageAccumulator, SlippageAccumulatorUser} from "../../../utils/SlippageAccumulatorUser.sol";
import {IOdosRouterV2} from "../../../interfaces/odos/IOdosRouterV2.sol";
import {IPoolManagerLogic} from "../../../interfaces/IPoolManagerLogic.sol";
import {IHasSupportedAsset} from "../../../interfaces/IHasSupportedAsset.sol";
/// @notice Contract guard contract for OdosRouterV2
/// @dev As this contract inherits `SlippageAccumulatorUser`, it also inherits the `ITxTrackingGuard` interface.
contract OdosV2ContractGuard is TxDataUtils, ITransactionTypes, SlippageAccumulatorUser {
mapping(address => mapping(address => bool)) internal _beforeSwapSrcAssetCheck; // poolLogic -> srcAsset -> bool
constructor(address _slippageAccumulator) SlippageAccumulatorUser(_slippageAccumulator) {}
/// @dev Support methods `swapCompact, `swap`
/// @param _poolManagerLogic Pool manager logic address
/// @param _data Transaction data
/// @return txType Transaction type
/// @return isPublic If the transaction is public or private
function txGuard(
address _poolManagerLogic,
address _to,
bytes memory _data
) external override returns (uint16 txType, bool) {
address poolLogic = _accessControl(_poolManagerLogic);
bytes4 method = getMethod(_data);
if (method == IOdosRouterV2.swap.selector) {
bytes memory params = getParams(_data);
IOdosRouterV2.SwapTokenInfo memory swapTokenInfo = abi.decode(params, (IOdosRouterV2.SwapTokenInfo));
txType = _verifySwap(swapTokenInfo, _poolManagerLogic, poolLogic);
} else if (method == IOdosRouterV2.swapCompact.selector) {
(bool success, bytes memory swapData) = address(this).staticcall(
abi.encodePacked(this._decodeCompactCalldata.selector, _to, _data)
);
require(success, "decodeCompactCalldata failed");
IOdosRouterV2.SwapTokenInfo memory swapTokenInfo = abi.decode(swapData, (IOdosRouterV2.SwapTokenInfo));
txType = _verifySwap(swapTokenInfo, _poolManagerLogic, poolLogic);
}
return (txType, false);
}
function afterTxGuard(address _poolManagerLogic, address _to, bytes memory _data) public override {
address poolLogic = IPoolManagerLogic(_poolManagerLogic).poolLogic();
bytes4 method = getMethod(_data);
if (method == IOdosRouterV2.swap.selector) {
bytes memory params = getParams(_data);
IOdosRouterV2.SwapTokenInfo memory swapTokenInfo = abi.decode(params, (IOdosRouterV2.SwapTokenInfo));
_verifySwapAfterTxGuard(swapTokenInfo, _poolManagerLogic, poolLogic);
SlippageAccumulatorUser.afterTxGuard(_poolManagerLogic, _to, _data);
} else if (method == IOdosRouterV2.swapCompact.selector) {
(bool success, bytes memory swapData) = address(this).staticcall(
abi.encodePacked(this._decodeCompactCalldata.selector, _to, _data)
);
require(success, "decodeCompactCalldata failed");
IOdosRouterV2.SwapTokenInfo memory swapTokenInfo = abi.decode(swapData, (IOdosRouterV2.SwapTokenInfo));
_verifySwapAfterTxGuard(swapTokenInfo, _poolManagerLogic, poolLogic);
SlippageAccumulatorUser.afterTxGuard(_poolManagerLogic, _to, _data);
}
}
function _verifySwap(
IOdosRouterV2.SwapTokenInfo memory _swapTokenInfo,
address _poolManagerLogic,
address _poolLogic
) internal returns (uint16 txType) {
require(_swapTokenInfo.outputReceiver == _poolLogic, "recipient is not pool");
require(_swapTokenInfo.inputToken != address(0), "invalid input token"); // do not support native ETH
require(_swapTokenInfo.inputAmount != 0, "invalid input amount"); // do not support entire balance trade
require(
IHasSupportedAsset(_poolManagerLogic).isSupportedAsset(_swapTokenInfo.outputToken),
"unsupported destination asset"
);
intermediateSwapData = SlippageAccumulator.SwapData({
srcAsset: _swapTokenInfo.inputToken,
dstAsset: _swapTokenInfo.outputToken,
srcAmount: _getBalance(_swapTokenInfo.inputToken, _poolLogic),
dstAmount: _getBalance(_swapTokenInfo.outputToken, _poolLogic)
});
if (IHasSupportedAsset(_poolManagerLogic).isSupportedAsset(_swapTokenInfo.inputToken)) {
_beforeSwapSrcAssetCheck[_poolLogic][_swapTokenInfo.inputToken] = true;
}
txType = uint16(TransactionType.Exchange);
}
function _verifySwapAfterTxGuard(
IOdosRouterV2.SwapTokenInfo memory _swapTokenInfo,
address _poolManagerLogic,
address _poolLogic
) internal {
require(
IHasSupportedAsset(_poolManagerLogic).isSupportedAsset(_swapTokenInfo.outputToken),
"unsupported destination asset"
);
if (_beforeSwapSrcAssetCheck[_poolLogic][_swapTokenInfo.inputToken]) {
require(
IHasSupportedAsset(_poolManagerLogic).isSupportedAsset(_swapTokenInfo.inputToken),
"unsupported source asset"
);
_beforeSwapSrcAssetCheck[_poolLogic][_swapTokenInfo.inputToken] = false;
}
}
/// @notice Decode the compact calldata for a swap
/// modified from https://github.com/odos-xyz/odos-router-v2/blob/main/contracts/OdosRouterV2.sol#L103
/// and use assembly to call storage variable `address[] public addressList` in the OdosRouterV2 contract
function _decodeCompactCalldata() public view returns (IOdosRouterV2.SwapTokenInfo memory tokenInfo) {
address executor;
{
address msgSender = msg.sender;
assembly {
// Define function to load in token address, either from calldata or from storage
function getAddress(currPos, routerAddress) -> result, newPos {
let inputPos := shr(240, calldataload(currPos))
switch inputPos
// Reserve the null address as a special case that can be specified with 2 null bytes
case 0x0000 {
newPos := add(currPos, 2)
}
// This case means that the address is encoded in the calldata directly following the code
case 0x0001 {
result := and(shr(80, calldataload(currPos)), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
newPos := add(currPos, 22)
}
// Otherwise we use the case to load in from the cached address list
default {
let ptr := mload(0x40) // the free memory pointer
let selector := 0xb810fb43 // for function addressList(uint256)
mstore(ptr, shl(224, selector)) // selector is only 4 bytes, so shift left by (32 - 4) * 8 = 224 bits
mstore(add(ptr, 4), sub(inputPos, 2)) // store the uint256 argument after the selector
let success := staticcall(gas(), routerAddress, ptr, 36, ptr, 32)
if iszero(success) {
revert(0, 0)
}
result := mload(ptr) // load the address from memory
newPos := add(currPos, 2) // update the position in calldata
}
}
let result := 0
let pos := 28 // 4 + 20 + 4 Skip the first 4 bytes of the _decodeCompactCalldata.selector and 20 bytes of _to address and 4 bytes of the swapCompact.selector
let routerAddress := shr(96, calldataload(4)) // shift to remove upper 12 bytes (96 bits)
// Load in the input and output token addresses
result, pos := getAddress(pos, routerAddress)
mstore(tokenInfo, result)
result, pos := getAddress(pos, routerAddress)
mstore(add(tokenInfo, 0x60), result)
// Load in the input amount - a 0 byte means the full balance is to be used
let inputAmountLength := shr(248, calldataload(pos))
pos := add(pos, 1)
if inputAmountLength {
mstore(add(tokenInfo, 0x20), shr(mul(sub(32, inputAmountLength), 8), calldataload(pos)))
pos := add(pos, inputAmountLength)
}
// Load in the quoted output amount
let quoteAmountLength := shr(248, calldataload(pos))
pos := add(pos, 1)
let outputQuote := shr(mul(sub(32, quoteAmountLength), 8), calldataload(pos))
mstore(add(tokenInfo, 0x80), outputQuote)
pos := add(pos, quoteAmountLength)
// Load the slippage tolerance and use to get the minimum output amount
{
let slippageTolerance := shr(232, calldataload(pos))
mstore(add(tokenInfo, 0xA0), div(mul(outputQuote, sub(0xFFFFFF, slippageTolerance)), 0xFFFFFF))
}
pos := add(pos, 3)
// Load in the executor address
executor, pos := getAddress(pos, routerAddress)
// Load in the destination to send the input to - Zero denotes the executor
result, pos := getAddress(pos, routerAddress)
if eq(result, 0) {
result := executor
}
mstore(add(tokenInfo, 0x40), result)
// Load in the destination to send the output to - Zero denotes msg.sender
result, pos := getAddress(pos, routerAddress)
if eq(result, 0) {
result := msgSender
}
mstore(add(tokenInfo, 0xC0), result)
//
// we don't need to load the referral code and the pathDefinition
}
}
}
}
"
},
"contracts/interfaces/guards/IGuard.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
interface IGuard {
function txGuard(
address poolManagerLogic,
address to,
bytes calldata data
) external returns (uint16 txType, bool isPublic); // TODO: eventually update `txType` to be of enum type as per ITransactionTypes
}
"
},
"contracts/interfaces/guards/ITxTrackingGuard.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
import {IGuard} from "./IGuard.sol";
interface ITxTrackingGuard is IGuard {
function isTxTrackingGuard() external view returns (bool);
function afterTxGuard(address poolManagerLogic, address to, bytes calldata data) external;
}
"
},
"contracts/interfaces/IERC20Extended.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6;
interface IERC20Extended {
// ERC20 Optional Views
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
// Views
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function scaledBalanceOf(address user) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
// Mutative functions
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
// Events
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
"
},
"contracts/interfaces/IHasAssetInfo.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6;
interface IHasAssetInfo {
function isValidAsset(address asset) external view returns (bool);
function getAssetPrice(address asset) external view returns (uint256);
function getAssetType(address asset) external view returns (uint16);
function getMaximumSupportedAssetCount() external view returns (uint256);
}
"
},
"contracts/interfaces/IHasGuardInfo.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
interface IHasGuardInfo {
// Get guard
function getContractGuard(address extContract) external view returns (address);
// Get asset guard
function getAssetGuard(address extContract) external view returns (address);
}
"
},
"contracts/interfaces/IHasSupportedAsset.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6;
pragma experimental ABIEncoderV2;
interface IHasSupportedAsset {
struct Asset {
address asset;
bool isDeposit;
}
function getSupportedAssets() external view returns (Asset[] memory);
function isSupportedAsset(address asset) external view returns (bool);
}
"
},
"contracts/interfaces/IPoolFactory.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6;
interface IPoolFactory {
function governanceAddress() external view returns (address);
function isPool(address pool) external view returns (bool);
function customCooldownWhitelist(address from) external view returns (bool);
function receiverWhitelist(address to) external view returns (bool);
function emitPoolEvent() external;
function emitPoolManagerEvent() external;
function isValidAsset(address asset) external view returns (bool);
function getAssetPrice(address asset) external view returns (uint256);
function getAssetHandler() external view returns (address);
}
"
},
"contracts/interfaces/IPoolManagerLogic.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
interface IPoolManagerLogic {
function poolLogic() external view returns (address);
function isDepositAsset(address asset) external view returns (bool);
function validateAsset(address asset) external view returns (bool);
function assetValue(address asset) external view returns (uint256);
function assetValue(address asset, uint256 amount) external view returns (uint256);
function assetBalance(address asset) external view returns (uint256 balance);
function factory() external view returns (address);
function setPoolLogic(address fundAddress) external returns (bool);
function totalFundValue() external view returns (uint256);
function isMemberAllowed(address member) external view returns (bool);
function getFee() external view returns (uint256, uint256, uint256, uint256, uint256);
function minDepositUSD() external view returns (uint256);
function getEntryFeeInfo()
external
view
returns (uint256 entryFeeNumerator, uint256 poolFeeShareNumerator, uint256 feeDenominator);
function getExitFeeInfo()
external
view
returns (uint256 exitFeeNumerator, uint256 poolFeeShareNumerator, uint256 feeDenominator);
function maxSupplyCap() external view returns (uint256 supplyCap);
}
"
},
"contracts/interfaces/ITransactionTypes.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;
/// @title Transaction types used in pool execTransaction() contract guards
/// @dev Gradually migrate to this enum as we update / add new contract guards
interface ITransactionTypes {
enum TransactionType {
NotUsed, // 0
Approve, // 1
Exchange, // 2
AddLiquidity, // 3
RemoveLiquidity, // 4
Stake, // 5
Unstake, // 6
Claim, // 7
UnstakeAndClaim, // 8
AaveDeposit, // 9
AaveWithdraw, // 10
AaveSetUserUseReserveAsCollateral, // 11
AaveBorrow, // 12
AaveRepay, // 13
AaveSwapBorrowRateMode, // 14
AaveRebalanceStableBorrowRate, // 15
BalancerJoinPool, // 16
BalancerExitPool, // 17
EasySwapperDeposit, // 18
EasySwapperWithdraw, // 19
UniswapV3Mint, // 20
UniswapV3IncreaseLiquidity, // 21
UniswapV3DecreaseLiquidity, // 22
UniswapV3Burn, // 23
UniswapV3Collect, // 24
UniswapV3Multicall, // 25
LyraOpenPosition, // 26
LyraClosePosition, // 27
LyraForceClosePosition, // 28
KwentaFuturesMarket, // 29
AddLiquiditySingle, // 30
RemoveLiquiditySingle, // 31
MaiTx, // 32
LyraAddCollateral, // 33
LyraLiquidatePosition, // 34
KwentaPerpsV2Market, // 35
RedeemSynth, // 36
SynthetixV3CreateAccount, // 37
SynthetixV3DepositCollateral, // 38
SynthetixV3WithdrawCollateral, // 39
SynthetixV3DelegateCollateral, // 40
SynthetixV3MintUSD, // 41
SynthetixV3BurnUSD, // 42
SynthetixV3Multicall, // 43
XRamCreateVest, // 44
XRamExitVest, // 45
SynthetixV3Wrap, // 46
SynthetixV3Unwrap, // 47
SynthetixV3BuySynth, // 48
SynthetixV3SellSynth, // 49
SonneMint, // 50
SonneRedeem, // 51
SonneRedeemUnderlying, // 52
SonneBorrow, // 53
SonneRepay, // 54
SonneComptrollerEnterMarkets, // 55
SonneComptrollerExitMarket, // 56
SynthetixV3UndelegateCollateral, // 57
AaveMigrateToV3, // 58
FlatMoneyStableDeposit, // 59
FlatMoneyStableWithdraw, // 60
FlatMoneyCancelOrder, // 61
SynthetixV3ClaimReward, // 62
VelodromeCLStake, // 63
VelodromeCLUnstake, // 64
VelodromeCLMint, // 65
VelodromeCLIncreaseLiquidity, // 66
VelodromeCLDecreaseLiquidity, // 67
VelodromeCLBurn, // 68
VelodromeCLCollect, // 69
VelodromeCLMulticall, // 70
FlatMoneyLeverageOpen, // 71
FlatMoneyLeverageAdjust, // 72
FlatMoneyLeverageClose, // 73
SynthetixV3PerpsCreateAccount, // 74
SynthetixV3PerpsModifyCollateral, // 75
SynthetixV3PerpsCommitOrder, // 76
CompoundDeposit, // 77
CompoundWithdraw, // 78
CompoundClaimRewards, // 79
RamsesCLMint, // 80
RamsesCLIncreaseLiquidity, // 81
RamsesCLDecreaseLiquidity, // 82
RamsesCLBurn, // 83
RamsesCLCollect, // 84
RamsesCLMulticall, // 85
RamsesCLGetReward, // 86
EasySwapperV2Deposit, // 87
EasySwapperV2InitWithdraw, // 88
EasySwapperV2CompleteWithdrawSingle, // 89
EasySwapperV2CompleteWithdrawMultiple, // 90
SafeTransferERC721, // 91
PancakeCLMint, // 92
PancakeCLIncreaseLiquidity, // 93
PancakeCLDecreaseLiquidity, // 94
PancakeCLBurn, // 95
PancakeCLCollect, // 96
PancakeCLMulticall, // 97
PancakeCLStake, // 98
PancakeCLUnstake, // 99
PancakeCLHarvest, // 100
GmxMulticall, // 101
GmxClaimFundingFees, // 102
GmxClaimCollateral, // 103
GmxCancelOrder, // 104
GmxCancelDeposit, // 105
GmxCancelWithdrawal, // 106
AcrossDepositV3, // 107
FluidLendingDeposit, // 108
FluidLendingWithdraw, // 109
BuyPendlePT, // 110
SellPendlePT, // 111
AaveSetEfficiencyMode // 112
}
}
"
},
"contracts/interfaces/odos/IOdosRouterV2.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;
interface IOdosRouterV2 {
/// @dev Contains all information needed to describe the input and output for a swap
struct SwapTokenInfo {
address inputToken;
uint256 inputAmount;
address inputReceiver;
address outputToken;
uint256 outputQuote;
uint256 outputMin;
address outputReceiver;
}
/// @notice Custom decoder to swap with compact calldata for efficient execution on L2s
function swapCompact() external payable returns (uint256);
/// @notice Externally facing interface for swapping two tokens
/// @param tokenInfo All information about the tokens being swapped
/// @param pathDefinition Encoded path definition for executor
/// @param executor Address of contract that will execute the path
/// @param referralCode referral code to specify the source of the swap
function swap(
SwapTokenInfo memory tokenInfo,
bytes calldata pathDefinition,
address executor,
uint32 referralCode
) external payable returns (uint256 amountOut);
}
"
},
"contracts/utils/SlippageAccumulator.sol": {
"content": "//
// __ __ __ ________ _______ ______ ________
// / |/ | / |/ |/ \ / \ / |
// ____$$ |$$ | $$ |$$$$$$$$/ $$$$$$$ |/$$$$$$ |$$$$$$$$/
// / $$ |$$ |__$$ |$$ |__ $$ | $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$ $$ |$$ | $$ | $$ |$$ |/ |$$ |
// $$ | $$ |$$$$$$$$ |$$$$$/ $$ | $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ | $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$ $$ |$$ | $$ |$$ |$$ $$/ $$ $$/ $$ |
// $$$$$$$/ $$/ $$/ $$$$$$$$/ $$$$$$$/ $$$$$$/ $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2025 dHEDGE DAO
//
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma abicoder v2;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Math} from "@openzeppelin/contracts/math/Math.sol";
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol";
import {IERC20Extended} from "../interfaces/IERC20Extended.sol";
import {IHasAssetInfo} from "../interfaces/IHasAssetInfo.sol";
import {IHasGuardInfo} from "../interfaces/IHasGuardInfo.sol";
import {IHasSupportedAsset} from "../interfaces/IHasSupportedAsset.sol";
/// @notice Contract to check for accumulated slippage impact for a pool manager.
/// @author dHEDGE
contract SlippageAccumulator is Ownable {
using SafeMath for *;
using Math for *;
using SafeCast for *;
/// @dev Struct for passing swap related data to the slippage accumulator function.
/// @param srcAsset Source asset (asset to be exchanged).
/// @param dstAsset Destination asset (asset being exchanged for).
/// @param srcAmount Source asset amount.
/// @param dstAmount Destination asset amount.
struct SwapData {
address srcAsset;
address dstAsset;
uint256 srcAmount;
uint256 dstAmount;
}
/// @dev Struct to track the slippage data for a poolManager.
/// @param lastTradeTimestamp Last successful trade's timestamp.
/// @param accumulatedSlippage The accumulated slippage impact of a poolManager.
struct ManagerSlippageData {
uint64 lastTradeTimestamp;
uint128 accumulatedSlippage;
}
event DecayTimeChanged(uint64 oldDecayTime, uint64 newDecayTime);
event MaxCumulativeSlippageChanged(uint128 oldMaxCumulativeSlippage, uint128 newMaxCumulativeSlippage);
/// @dev Constant used to multiply the slippage loss percentage with 4 decimal precision.
uint128 private constant SCALING_FACTOR = 1e6;
/// @dev dHEDGE poolFactory address.
address public immutable poolFactory;
/// @notice Maximum acceptable cumulative trade slippage impact within a period of time (upto 4 decimal precision).
/// @dev Eg. 5% = 5e4
uint128 public maxCumulativeSlippage;
/// @notice Price accumulator decay time.
/// @dev Eg 6 hours = 21600.
uint64 public decayTime;
/// @notice Tracks the last trade timestamp and accumulated slippage for each poolManager.
mapping(address => ManagerSlippageData) public managerData;
/// @dev Modifier to make sure caller is a contract guard.
modifier onlyContractGuard(address to) {
address contractGuard = IHasGuardInfo(poolFactory).getContractGuard(to);
require(contractGuard == msg.sender, "Not authorised guard");
_;
}
constructor(address _poolFactory, uint64 _decayTime, uint128 _maxCumulativeSlippage) {
require(_poolFactory != address(0), "Null address");
poolFactory = _poolFactory;
decayTime = _decayTime;
maxCumulativeSlippage = _maxCumulativeSlippage;
}
/// @notice Updates the cumulative slippage impact and reverts if it's beyond limit.
/// @dev NOTE: It's important that the calling guard checks if the msg.sender in it's scope is authorised.
/// @dev If the caller is not checked for in the guard, anyone can trigger the `txGuard` transaction and update slippage impact.
/// @param poolManagerLogic Address of the poolManager whose cumulative impact is stored.
/// @param router Address of the router contract used for swapping.
/// @param swapData Common swap data for all guards.
function updateSlippageImpact(
address poolManagerLogic,
address router,
SwapData calldata swapData
) external onlyContractGuard(router) {
require(swapData.srcAmount != 0, "0 src amount");
if (IHasSupportedAsset(poolManagerLogic).isSupportedAsset(swapData.srcAsset)) {
uint256 srcValue = assetValue(swapData.srcAsset, swapData.srcAmount);
uint256 dstValue = assetValue(swapData.dstAsset, swapData.dstAmount);
// Only update the cumulative slippage in case the amount received is lesser than amount sent/traded.
if (dstValue < srcValue) {
uint128 newSlippage = srcValue.sub(dstValue).mul(SCALING_FACTOR).div(srcValue).toUint128();
uint128 newCumulativeSlippage = (uint256(newSlippage).add(getCumulativeSlippageImpact(poolManagerLogic)))
.toUint128();
require(newCumulativeSlippage < maxCumulativeSlippage, "slippage impact exceeded");
// Update the last traded timestamp.
managerData[poolManagerLogic].lastTradeTimestamp = (block.timestamp).toUint64();
// Update the accumulated slippage impact for the poolManager.
managerData[poolManagerLogic].accumulatedSlippage = newCumulativeSlippage;
}
}
}
/// Function to calculate an asset amount's value in usd.
/// @param asset The asset whose price oracle exists.
/// @param amount The amount of the `asset`.
function assetValue(address asset, uint256 amount) public view returns (uint256 value) {
value = amount.mul(IHasAssetInfo(poolFactory).getAssetPrice(asset)).div(10 ** IERC20Extended(asset).decimals()); // to USD amount
}
/// @notice Function to get the cumulative slippage adjusted using decayTime (current cumulative slippage impact).
/// @param poolManagerLogic Address of the poolManager whose cumulative impact is stored.
function getCumulativeSlippageImpact(address poolManagerLogic) public view returns (uint128 cumulativeSlippage) {
ManagerSlippageData memory managerSlippageData = managerData[poolManagerLogic];
return
(
uint256(managerSlippageData.accumulatedSlippage)
.mul(decayTime.sub(decayTime.min(block.timestamp.sub(managerSlippageData.lastTradeTimestamp))))
.div(decayTime)
).toUint128();
}
/**********************************************
* Owner Functions *
*********************************************/
/// @notice Function to change decay time for calculating price impact.
/// @param newDecayTime The new decay time (in seconds).
function setDecayTime(uint64 newDecayTime) external onlyOwner {
uint64 oldDecayTime = decayTime;
decayTime = newDecayTime;
emit DecayTimeChanged(oldDecayTime, newDecayTime);
}
/// @notice Function to change the max acceptable cumulative slippage impact.
/// @param newMaxCumulativeSlippage The new max acceptable cumulative slippage impact.
function setMaxCumulativeSlippage(uint128 newMaxCumulativeSlippage) external onlyOwner {
uint128 oldMaxCumulativeSlippage = maxCumulativeSlippage;
maxCumulativeSlippage = newMaxCumulativeSlippage;
emit MaxCumulativeSlippageChanged(oldMaxCumulativeSlippage, newMaxCumulativeSlippage);
}
}
"
},
"contracts/utils/SlippageAccumulatorUser.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IPoolFactory} from "../interfaces/IPoolFactory.sol";
import {IPoolManagerLogic} from "../interfaces/IPoolManagerLogic.sol";
import {ITxTrackingGuard} from "../interfaces/guards/ITxTrackingGuard.sol";
import {SlippageAccumulator} from "./SlippageAccumulator.sol";
abstract contract SlippageAccumulatorUser is ITxTrackingGuard {
using SafeMath for *;
bool public override isTxTrackingGuard = true;
SlippageAccumulator internal immutable slippageAccumulator;
/// @dev Note that the intermediateSwapData is used to store the data temporarily
/// after a swap is completed, this is used to update the slippage impact.
/// the `dstAmount` stored in this struct before execution of `afterTxGuard` is the prior balance of the pool for the destination asset.
SlippageAccumulator.SwapData internal intermediateSwapData;
constructor(address _slippageAccumulator) {
require(_slippageAccumulator != address(0), "invalid address");
slippageAccumulator = SlippageAccumulator(_slippageAccumulator);
}
function afterTxGuard(address poolManagerLogic, address to, bytes memory /* data */) public virtual override {
address poolLogic = _accessControl(poolManagerLogic);
slippageAccumulator.updateSlippageImpact(
poolManagerLogic,
to,
SlippageAccumulator.SwapData({
srcAsset: intermediateSwapData.srcAsset,
dstAsset: intermediateSwapData.dstAsset,
srcAmount: intermediateSwapData.srcAmount.sub(_getBalance(intermediateSwapData.srcAsset, poolLogic)),
dstAmount: _getBalance(intermediateSwapData.dstAsset, poolLogic).sub(intermediateSwapData.dstAmount)
})
);
intermediateSwapData = SlippageAccumulator.SwapData(address(0), address(0), 0, 0);
}
function _getBalance(address token, address holder) internal view returns (uint256) {
// This is to avoid reverts during wrap/unwrap attempts via 1inch (which still should revert downstream)
return (token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) ? holder.balance : IERC20(token).balanceOf(holder);
}
function _accessControl(address poolManagerLogic) internal view returns (address poolLogic) {
poolLogic = IPoolManagerLogic(poolManagerLogic).poolLogic();
require(
msg.sender == poolLogic && IPoolFactory(slippageAccumulator.poolFactory()).isPool(poolLogic),
"not pool logic"
);
}
}
"
},
"contracts/utils/TxDataUtils.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
import {BytesLib} from "@uniswap/v3-periphery/contracts/libraries/BytesLib.sol";
contract TxDataUtils {
using BytesLib for bytes;
function getMethod(bytes memory data) public pure returns (bytes4) {
return read4left(data, 0);
}
function getParams(bytes memory data) public pure returns (bytes memory) {
return data.slice(4, data.length - 4);
}
function getInput(bytes memory data, uint8 inputNum) public pure returns (bytes32) {
return read32(data, 32 * inputNum + 4, 32);
}
function getBytes(bytes memory data, uint8 inputNum, uint256 offset) public pure returns (bytes memory) {
require(offset < 20, "invalid offset"); // offset is in byte32 slots, not bytes
offset = offset * 32; // convert offset to bytes
uint256 bytesLenPos = uint256(read32(data, 32 * inputNum + 4 + offset, 32));
uint256 bytesLen = uint256(read32(data, bytesLenPos + 4 + offset, 32));
return data.slice(bytesLenPos + 4 + offset + 32, bytesLen);
}
function getArrayLast(bytes memory data, uint8 inputNum) public pure returns (bytes32) {
bytes32 arrayPos = read32(data, 32 * inputNum + 4, 32);
bytes32 arrayLen = read32(data, uint256(arrayPos) + 4, 32);
require(arrayLen > 0, "input is not array");
return read32(data, uint256(arrayPos) + 4 + (uint256(arrayLen) * 32), 32);
}
function getArrayLength(bytes memory data, uint8 inputNum) public pure returns (uint256) {
bytes32 arrayPos = read32(data, 32 * inputNum + 4, 32);
return uint256(read32(data, uint256(arrayPos) + 4, 32));
}
function getArrayIndex(bytes memory data, uint8 inputNum, uint8 arrayIndex) public pure returns (bytes32) {
bytes32 arrayPos = read32(data, 32 * inputNum + 4, 32);
bytes32 arrayLen = read32(data, uint256(arrayPos) + 4, 32);
require(arrayLen > 0, "input is not array");
require(uint256(arrayLen) > arrayIndex, "invalid array position");
return read32(data, uint256(arrayPos) + 4 + ((1 + uint256(arrayIndex)) * 32), 32);
}
function read4left(bytes memory data, uint256 offset) public pure returns (bytes4 o) {
require(data.length >= offset + 4, "Reading bytes out of bounds");
assembly {
o := mload(add(data, add(32, offset)))
}
}
function read32(bytes memory data, uint256 offset, uint256 length) public pure returns (bytes32 o) {
require(data.length >= offset + length, "Reading bytes out of bounds");
assembly {
o := mload(add(data, add(32, offset)))
let lb := sub(32, length)
if lb {
o := div(o, exp(2, mul(lb, 8)))
}
}
}
function convert32toAddress(bytes32 data) public pure returns (address o) {
return address(uint160(uint256(data)));
}
function sliceUint(bytes memory data, uint256 start) internal pure returns (uint256) {
require(data.length >= start + 32, "slicing out of range");
uint256 x;
assembly {
x := mload(add(data, add(0x20, start)))
}
return x;
}
}
"
}
},
"settings": {
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"optimizer": {
"enabled": true,
"runs": 20
}
}
}}
Submitted on: 2025-09-22 15:17:14
Comments
Log in to comment.
No comments yet.