Overview
ETH Balance
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 357985501 | 194 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {Auth} from "src/misc/Auth.sol";
import {CastLib} from "src/misc/libraries/CastLib.sol";
import {BytesLib} from "src/misc/libraries/BytesLib.sol";
import {IERC165} from "src/misc/interfaces/IERC7575.sol";
import {BitmapLib} from "src/misc/libraries/BitmapLib.sol";
import {IRoot} from "src/common/interfaces/IRoot.sol";
import {ITransferHook, HookData} from "src/common/interfaces/ITransferHook.sol";
import {IShareToken} from "src/spoke/interfaces/IShareToken.sol";
import {IFreezable} from "src/hooks/interfaces/IFreezable.sol";
import {UpdateRestrictionType, UpdateRestrictionMessageLib} from "src/hooks/libraries/UpdateRestrictionMessageLib.sol";
/// @title Freeze Only
/// @notice Hook implementation that:
/// * Allows any non-frozen account to receive tokens and transfer tokens
/// * Supports freezing accounts which blocks transfers both to and from them
///
/// @dev The last bit of hookData is used to denote whether the account is frozen.
contract FreezeOnly is Auth, IFreezable, ITransferHook {
using BitmapLib for *;
using UpdateRestrictionMessageLib for *;
using BytesLib for bytes;
using CastLib for bytes32;
/// @dev Least significant bit
uint8 public constant FREEZE_BIT = 0;
IRoot public immutable root;
constructor(address root_, address deployer) Auth(deployer) {
root = IRoot(root_);
}
//----------------------------------------------------------------------------------------------
// Callback from share token
//----------------------------------------------------------------------------------------------
/// @inheritdoc ITransferHook
function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)
external
virtual
returns (bytes4)
{
require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());
return ITransferHook.onERC20Transfer.selector;
}
/// @inheritdoc ITransferHook
function onERC20AuthTransfer(
address, /* sender */
address, /* from */
address, /* to */
uint256, /* value */
HookData calldata /* hookData */
) external pure returns (bytes4) {
return ITransferHook.onERC20AuthTransfer.selector;
}
/// @inheritdoc ITransferHook
function checkERC20Transfer(address from, address, /* to */ uint256, /* value */ HookData calldata hookData)
public
view
returns (bool)
{
uint128 fromHookData = uint128(hookData.from);
if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {
// Source is frozen and not endorsed
return false;
}
uint128 toHookData = uint128(hookData.to);
if (toHookData.getBit(FREEZE_BIT) == true) {
// Destination is frozen
return false;
}
return true;
}
//----------------------------------------------------------------------------------------------
// Restriction updates
//----------------------------------------------------------------------------------------------
/// @inheritdoc ITransferHook
function updateRestriction(address token, bytes memory payload) external auth {
UpdateRestrictionType updateId = payload.updateRestrictionType();
if (updateId == UpdateRestrictionType.Freeze) {
UpdateRestrictionMessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();
freeze(token, m.user.toAddress());
} else if (updateId == UpdateRestrictionType.Unfreeze) {
UpdateRestrictionMessageLib.UpdateRestrictionUnfreeze memory m =
payload.deserializeUpdateRestrictionUnfreeze();
unfreeze(token, m.user.toAddress());
} else {
revert InvalidUpdate();
}
}
/// @inheritdoc IFreezable
function freeze(address token, address user) public auth {
require(user != address(0), CannotFreezeZeroAddress());
require(!root.endorsed(user), EndorsedUserCannotBeFrozen());
uint128 hookData = uint128(IShareToken(token).hookDataOf(user));
IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));
emit Freeze(token, user);
}
/// @inheritdoc IFreezable
function unfreeze(address token, address user) public auth {
uint128 hookData = uint128(IShareToken(token).hookDataOf(user));
IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));
emit Unfreeze(token, user);
}
/// @inheritdoc IFreezable
function isFrozen(address token, address user) public view returns (bool) {
return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);
}
//----------------------------------------------------------------------------------------------
// ERC-165
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return interfaceId == type(ITransferHook).interfaceId || interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IAuth} from "src/misc/interfaces/IAuth.sol";
/// @title Auth
/// @notice Simple authentication pattern
/// @author Based on code from https://github.com/makerdao/dss
abstract contract Auth is IAuth {
/// @inheritdoc IAuth
mapping(address => uint256) public wards;
constructor(address initialWard) {
wards[initialWard] = 1;
emit Rely(initialWard);
}
/// @dev Check if the msg.sender has permissions
modifier auth() {
require(wards[msg.sender] == 1, NotAuthorized());
_;
}
/// @inheritdoc IAuth
function rely(address user) public auth {
wards[user] = 1;
emit Rely(user);
}
/// @inheritdoc IAuth
function deny(address user) public auth {
wards[user] = 0;
emit Deny(user);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
/// @title CastLib
library CastLib {
function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {
require(bytes12(addr) == 0, "First 12 bytes should be zero");
return address(uint160(uint256(addr)));
}
function toBytes32LeftPadded(address addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}
function toAddress(bytes32 addr) internal pure returns (address) {
require(uint96(uint256(addr)) == 0, "Input should be 20 bytes");
return address(bytes20(addr));
}
function toBytes32(address addr) internal pure returns (bytes32) {
return bytes32(bytes20(addr));
}
/// @dev Adds zero padding
function toBytes32(string memory source) internal pure returns (bytes32) {
return bytes32(bytes(source));
}
/// @dev Removes zero padding
function bytes128ToString(bytes memory _bytes128) internal pure returns (string memory) {
require(_bytes128.length == 128, "Input should be 128 bytes");
uint8 i = 0;
while (i < 128 && _bytes128[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (uint8 j; j < i; j++) {
bytesArray[j] = _bytes128[j];
}
return string(bytesArray);
}
function toString(bytes32 _bytes32) internal pure returns (string memory) {
uint8 i = 0;
while (i < 32 && _bytes32[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
bytesArray[i] = _bytes32[i];
}
return string(bytesArray);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
/// @title Bytes Lib
/// @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.
/// @author Modified from Solidity Bytes Arrays Utils v0.8.0
library BytesLib {
error SliceOverflow();
error SliceOutOfBounds();
function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
unchecked {
require(_length + 31 >= _length, SliceOverflow());
}
require(_bytes.length >= _start + _length, SliceOutOfBounds());
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 sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)
internal
pure
returns (bytes memory)
{
bool needsPad = _bytes.length < _start + _length;
if (!needsPad) return slice(_bytes, _start, _length);
bytes memory slice_ = slice(_bytes, _start, _bytes.length - _start);
bytes memory padding = new bytes(_length + _start - _bytes.length);
return bytes.concat(slice_, padding);
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_bytes.length >= _start + 20, SliceOutOfBounds());
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
require(_bytes.length >= _start + 1, SliceOutOfBounds());
uint8 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
require(_bytes.length >= _start + 2, SliceOutOfBounds());
uint16 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x2), _start))
}
return tempUint;
}
function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
require(_bytes.length >= _start + 4, SliceOutOfBounds());
uint32 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x4), _start))
}
return tempUint;
}
function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
require(_bytes.length >= _start + 8, SliceOutOfBounds());
uint64 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x8), _start))
}
return tempUint;
}
function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
require(_bytes.length >= _start + 16, SliceOutOfBounds());
uint128 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x10), _start))
}
return tempUint;
}
function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
require(_bytes.length >= _start + 32, SliceOutOfBounds());
uint256 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x20), _start))
}
return tempUint;
}
function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
require(_bytes.length >= _start + 32, SliceOutOfBounds());
bytes32 tempBytes32;
assembly {
tempBytes32 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes32;
}
function toBytes16(bytes memory _bytes, uint256 _start) internal pure returns (bytes16) {
require(_bytes.length >= _start + 16, SliceOutOfBounds());
bytes16 tempBytes16;
assembly {
tempBytes16 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes16;
}
function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {
require(_bytes.length > _start, SliceOutOfBounds());
return _bytes[_start] != 0;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IERC165} from "src/misc/interfaces/IERC165.sol";
interface IERC7575 is IERC165 {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the address of the share token
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function share() external view returns (address shareTokenAddress);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
interface IERC7575Share is IERC165 {
event VaultUpdate(address indexed asset, address vault);
/**
* @dev Returns the address of the Vault for the given asset.
*
* @param asset the ERC-20 token to deposit with into the Vault
*/
function vault(address asset) external view returns (address);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
/// @title BitmapLib
library BitmapLib {
function setBit(uint128 bitmap, uint128 index, bool isTrue) internal pure returns (uint128) {
if (isTrue) {
return bitmap | (uint128(1) << index);
}
return bitmap & ~(uint128(1) << index);
}
function getBit(uint128 bitmap, uint128 index) internal pure returns (bool) {
uint128 bitAtIndex = uint128(bitmap & (1 << index));
return bitAtIndex != 0;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IRoot {
// --- Events ---
event File(bytes32 indexed what, uint256 data);
event Pause();
event Unpause();
event ScheduleRely(address indexed target, uint256 indexed scheduledTime);
event CancelRely(address indexed target);
event RelyContract(address indexed target, address indexed user);
event DenyContract(address indexed target, address indexed user);
event Endorse(address indexed user);
event Veto(address indexed user);
error DelayTooLong();
error FileUnrecognizedParam();
error TargetNotScheduled();
error TargetNotReady();
/// @notice Returns whether the root is paused
function paused() external view returns (bool);
/// @notice Returns the current timelock for adding new wards
function delay() external view returns (uint256);
/// @notice Trusted contracts within the system
function endorsements(address target) external view returns (uint256);
/// @notice Returns when `relyTarget` has passed the timelock
function schedule(address relyTarget) external view returns (uint256 timestamp);
// --- Administration ---
/// @notice Updates a contract parameter
/// @param what Accepts a bytes32 representation of 'delay'
function file(bytes32 what, uint256 data) external;
/// --- Endorsements ---
/// @notice Endorses the `user`
/// @dev Endorsed users are trusted contracts in the system. They are allowed to bypass
/// token restrictions (e.g. the Escrow can automatically receive share class tokens by being endorsed), and
/// can automatically set operators in ERC-7540 vaults (e.g. the VaultRouter) is always an operator.
function endorse(address user) external;
/// @notice Removes the endorsed user
function veto(address user) external;
/// @notice Returns whether the user is endorsed
function endorsed(address user) external view returns (bool);
// --- Pause management ---
/// @notice Pause any contracts that depend on `Root.paused()`
function pause() external;
/// @notice Unpause any contracts that depend on `Root.paused()`
function unpause() external;
/// --- Timelocked ward management ---
/// @notice Schedule relying a new ward after the delay has passed
function scheduleRely(address target) external;
/// @notice Cancel a pending scheduled rely
function cancelRely(address target) external;
/// @notice Execute a scheduled rely
/// @dev Can be triggered by anyone since the scheduling is protected
function executeScheduledRely(address target) external;
/// --- External contract ward management ---
/// @notice Make an address a ward on any contract that Root is a ward on
function relyContract(address target, address user) external;
/// @notice Removes an address as a ward on any contract that Root is a ward on
function denyContract(address target, address user) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IERC165} from "src/misc/interfaces/IERC7575.sol";
struct HookData {
bytes16 from;
bytes16 to;
}
uint8 constant SUCCESS_CODE_ID = 0;
string constant SUCCESS_MESSAGE = "transfer-allowed";
uint8 constant ERROR_CODE_ID = 1;
string constant ERROR_MESSAGE = "transfer-blocked";
/// @dev Magic address denoting a transfer to the escrow
/// @dev Solely used for gas saving since escrow is per pool
/// @dev Equals 118_624 such that there is no collision with any uint16 Centrifuge ID
address constant ESCROW_HOOK_ID = address(uint160(0x1CF60));
/// @notice Hook interface to customize share token behaviour
/// @dev To detect specific system actions:
/// Deposit request: address(0) -> address(user)
/// Deposit request fulfillment: address(0) -> ESCROW_HOOK_ID
/// Deposit claim: ESCROW_HOOK_ID -> address(user)
/// Redeem request: address(user) -> ESCROW_HOOK_ID
/// Redeem request fulfillment: ESCROW_HOOK_ID -> address(0)
/// Redeem claim: address(user) -> address(0)
/// Cross-chain transfer: address(user) -> address(uint160(chainId))
interface ITransferHook is IERC165 {
// --- Errors ---
error TransferBlocked();
error InvalidUpdate();
/// @notice Callback on standard ERC20 transfer.
/// @dev MUST return bytes4(keccak256("onERC20Transfer(address,address,uint256,(bytes16,bytes16))"))
/// if successful
function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookdata)
external
returns (bytes4);
/// @notice Callback on authorized ERC20 transfer.
/// @dev Cannot be blocked, can only be used to update state.
/// Return value is ignored, only kept for compatibility with V2 share tokens.
function onERC20AuthTransfer(address sender, address from, address to, uint256 value, HookData calldata hookdata)
external
returns (bytes4);
/// @notice Check if given transfer can be performed
function checkERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)
external
view
returns (bool);
/// @notice Update a set of restriction for a token
/// @dev MAY be user specific, which would be included in the encoded `update` value
function updateRestriction(address token, bytes memory update) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IERC20Metadata} from "src/misc/interfaces/IERC20.sol";
import {IERC7575Share} from "src/misc/interfaces/IERC7575.sol";
interface IERC1404 {
/// @notice Detects if a transfer will be reverted and if so returns an appropriate reference code
/// @param from Sending address
/// @param to Receiving address
/// @param value Amount of tokens being transferred
/// @return Code by which to reference message for rejection reasoning
/// @dev Overwrite with your custom transfer restriction logic
function detectTransferRestriction(address from, address to, uint256 value) external view returns (uint8);
/// @notice Returns a human-readable message for a given restriction code
/// @param restrictionCode Identifier for looking up a message
/// @return Text showing the restriction's reasoning
/// @dev Overwrite with your custom message and restrictionCode handling
function messageForTransferRestriction(uint8 restrictionCode) external view returns (string memory);
}
interface IShareToken is IERC20Metadata, IERC7575Share, IERC1404 {
// --- Events ---
event File(bytes32 indexed what, address data);
event SetHookData(address indexed user, bytes16 data);
// --- Errors ---
error NotAuthorizedOrHook();
error ExceedsMaxSupply();
error RestrictionsFailed();
struct Balance {
/// @dev The user balance is limited to uint128. This is safe because the decimals are limited to 18,
/// thus the max balance is 2^128-1 / 10**18 = 3.40 * 10**20. This is also enforced on mint.
uint128 amount;
/// @dev There are 16 bytes that are used to store hook data (e.g. restrictions for users).
bytes16 hookData;
}
// --- Administration ---
/// @notice returns the hook that transfers perform callbacks to
/// @dev MUST comply to `ITransferHook` interface
function hook() external view returns (address);
/// @notice Updates a contract parameter
/// @param what Accepts a bytes32 representation of 'name', 'symbol'
function file(bytes32 what, string memory data) external;
/// @notice Updates a contract parameter
/// @param what Accepts a bytes32 representation of 'hook'
function file(bytes32 what, address data) external;
/// @notice updates the vault for a given `asset`
function updateVault(address asset, address vault_) external;
// --- ERC20 overrides ---
/// @notice returns the 16 byte hook data of the given `user`.
/// @dev Stored in the 128 most significant bits of the user balance
function hookDataOf(address user) external view returns (bytes16);
/// @notice update the 16 byte hook data of the given `user`
function setHookData(address user, bytes16 hookData) external;
/// @notice Function to mint tokens
function mint(address user, uint256 value) external;
/// @notice Function to burn tokens
function burn(address user, uint256 value) external;
/// @notice Checks if the tokens can be transferred given the input values
function checkTransferRestriction(address from, address to, uint256 value) external view returns (bool);
/// @notice Performs an authorized transfer, with `sender` as the given sender.
/// @dev Requires allowance if `sender` != `from`
function authTransferFrom(address sender, address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
interface IFreezable {
// --- Events ---
event Freeze(address indexed token, address indexed user);
event Unfreeze(address indexed token, address indexed user);
// --- Errors ---
error CannotFreezeZeroAddress();
error EndorsedUserCannotBeFrozen();
// --- Handling freezes ---
/// @notice Freeze a user balance. Frozen users cannot receive nor send tokens
function freeze(address token, address user) external;
/// @notice Unfreeze a user balance
function unfreeze(address token, address user) external;
/// @notice Returns whether the user's tokens are frozen
function isFrozen(address token, address user) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {CastLib} from "src/misc/libraries/CastLib.sol";
import {BytesLib} from "src/misc/libraries/BytesLib.sol";
enum UpdateRestrictionType {
/// @dev Placeholder for null update restriction type
Invalid,
Member,
Freeze,
Unfreeze
}
library UpdateRestrictionMessageLib {
using UpdateRestrictionMessageLib for bytes;
using BytesLib for bytes;
using CastLib for *;
error UnknownMessageType();
function updateRestrictionType(bytes memory message) internal pure returns (UpdateRestrictionType) {
return UpdateRestrictionType(message.toUint8(0));
}
//---------------------------------------
// UpdateRestrictionMember (submsg)
//---------------------------------------
struct UpdateRestrictionMember {
bytes32 user;
uint64 validUntil;
}
function deserializeUpdateRestrictionMember(bytes memory data)
internal
pure
returns (UpdateRestrictionMember memory)
{
require(updateRestrictionType(data) == UpdateRestrictionType.Member, UnknownMessageType());
return UpdateRestrictionMember({user: data.toBytes32(1), validUntil: data.toUint64(33)});
}
function serialize(UpdateRestrictionMember memory t) internal pure returns (bytes memory) {
return abi.encodePacked(UpdateRestrictionType.Member, t.user, t.validUntil);
}
//---------------------------------------
// UpdateRestrictionFreeze (submsg)
//---------------------------------------
struct UpdateRestrictionFreeze {
bytes32 user;
}
function deserializeUpdateRestrictionFreeze(bytes memory data)
internal
pure
returns (UpdateRestrictionFreeze memory)
{
require(updateRestrictionType(data) == UpdateRestrictionType.Freeze, UnknownMessageType());
return UpdateRestrictionFreeze({user: data.toBytes32(1)});
}
function serialize(UpdateRestrictionFreeze memory t) internal pure returns (bytes memory) {
return abi.encodePacked(UpdateRestrictionType.Freeze, t.user);
}
//---------------------------------------
// UpdateRestrictionUnfreeze (submsg)
//---------------------------------------
struct UpdateRestrictionUnfreeze {
bytes32 user;
}
function deserializeUpdateRestrictionUnfreeze(bytes memory data)
internal
pure
returns (UpdateRestrictionUnfreeze memory)
{
require(updateRestrictionType(data) == UpdateRestrictionType.Unfreeze, UnknownMessageType());
return UpdateRestrictionUnfreeze({user: data.toBytes32(1)});
}
function serialize(UpdateRestrictionUnfreeze memory t) internal pure returns (bytes memory) {
return abi.encodePacked(UpdateRestrictionType.Unfreeze, t.user);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IAuth {
event Rely(address indexed user);
event Deny(address indexed user);
error NotAuthorized();
/// @notice Returns whether the target is a ward (has admin access)
function wards(address target) external view returns (uint256);
/// @notice Make user a ward (give them admin access)
function rely(address user) external;
/// @notice Remove user as a ward (remove admin access)
function deny(address user) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title IERC20
/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @author Modified from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
interface IERC20 {
error InvalidAddress();
error InsufficientBalance();
error InsufficientAllowance();
/**
* @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);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
error PermitExpired();
error InvalidPermit();
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
interface IERC20Wrapper {
/**
* @dev Returns the address of the underlying ERC-20 token that is being wrapped.
*/
function underlying() external view returns (address);
/**
* @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.
*/
function depositFor(address account, uint256 value) external returns (bool);
/**
* @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.
*/
function withdrawTo(address account, uint256 value) external returns (bool);
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"@chimera/=lib/chimera/src/",
"createx-forge/=lib/createx-forge/",
"chimera/=lib/chimera/src/",
"ds-test/=lib/chimera/lib/forge-std/lib/ds-test/src/",
"setup-helpers/=lib/setup-helpers/src/"
],
"optimizer": {
"enabled": true,
"runs": 1
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"root_","type":"address"},{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotFreezeZeroAddress","type":"error"},{"inputs":[],"name":"EndorsedUserCannotBeFrozen","type":"error"},{"inputs":[],"name":"InvalidUpdate","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"TransferBlocked","type":"error"},{"inputs":[],"name":"UnknownMessageType","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Freeze","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Unfreeze","type":"event"},{"inputs":[],"name":"FREEZE_BIT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"components":[{"internalType":"bytes16","name":"from","type":"bytes16"},{"internalType":"bytes16","name":"to","type":"bytes16"}],"internalType":"struct HookData","name":"hookData","type":"tuple"}],"name":"checkERC20Transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"freeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"isFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"components":[{"internalType":"bytes16","name":"from","type":"bytes16"},{"internalType":"bytes16","name":"to","type":"bytes16"}],"internalType":"struct HookData","name":"","type":"tuple"}],"name":"onERC20AuthTransfer","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"components":[{"internalType":"bytes16","name":"from","type":"bytes16"},{"internalType":"bytes16","name":"to","type":"bytes16"}],"internalType":"struct HookData","name":"hookData","type":"tuple"}],"name":"onERC20Transfer","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"contract IRoot","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"unfreeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"updateRestriction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a060405234801561000f575f5ffd5b50604051610ef3380380610ef383398101604081905261002e9161009f565b6001600160a01b0381165f8181526020819052604080822060019055518392917fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6091a250506001600160a01b03166080526100d0565b80516001600160a01b038116811461009a575f5ffd5b919050565b5f5f604083850312156100b0575f5ffd5b6100b983610084565b91506100c760208401610084565b90509250929050565b608051610dfd6100f65f395f81816101e3015281816102c8015261085f0152610dfd5ff3fe608060405234801561000f575f5ffd5b50600436106100ad575f3560e01c806301ffc9a7146100b1578063078d18cd146100d957806315748250146101115780633f71910e1461012657806346de0fb1146101395780635adb6ddb1461014c57806365fae35e1461015f5780637aeba8d5146101725780637f5ca5a3146101855780639c52a7f11461019e578063bf353dbb146101b1578063ebf0c717146101de578063ef59bc9214610212575b5f5ffd5b6100c46100bf366004610ad3565b610225565b60405190151581526020015b60405180910390f35b6100f86100e7366004610b2b565b63078d18cd60e01b95945050505050565b6040516001600160e01b031990911681526020016100d0565b61012461011f366004610b86565b61025b565b005b6100f8610134366004610bb7565b610471565b6100c4610147366004610b86565b6104ad565b61012461015a366004610b86565b610530565b61012461016d366004610c02565b610675565b610124610180366004610c2f565b6106e8565b61018c5f81565b60405160ff90911681526020016100d0565b6101246101ac366004610c02565b6107ac565b6101d06101bf366004610c02565b5f6020819052908152604090205481565b6040519081526020016100d0565b6102057f000000000000000000000000000000000000000000000000000000000000000081565b6040516100d09190610cf0565b6100c4610220366004610bb7565b61081e565b5f6001600160e01b03198216632b53a76160e21b148061025557506001600160e01b031982166301ffc9a760e01b145b92915050565b335f9081526020819052604090205460011461028a5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381166102b157604051631e778ac960e21b815260040160405180910390fd5b60405163854b89d560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063854b89d5906102fd908490600401610cf0565b602060405180830381865afa158015610318573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061033c9190610d04565b1561035a576040516307bd5aa160e51b815260040160405180910390fd5b60405163e8e6dc7560e01b81525f906001600160a01b0384169063e8e6dc7590610388908590600401610cf0565b602060405180830381865afa1580156103a3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103c79190610d3b565b60801c90506001600160a01b038316636a9154aa836103e8845f6001610923565b60801b6040518363ffffffff1660e01b8152600401610408929190610d56565b5f604051808303815f87803b15801561041f575f5ffd5b505af1158015610431573d5f5f3e3d5ffd5b50506040516001600160a01b038086169350861691507f51d18786e9cb144f87d46e7b796309ea84c7c687d91e09c97f051eacf59bc528905f90a3505050565b5f61047e8585858561081e565b61049b57604051637c8733a560e11b815260040160405180910390fd5b50631fb8c88760e11b5b949350505050565b60405163e8e6dc7560e01b81525f906105299082906001600160a01b0386169063e8e6dc75906104e1908790600401610cf0565b602060405180830381865afa1580156104fc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105209190610d3b565b60801c90610955565b9392505050565b335f9081526020819052604090205460011461055f5760405163ea8e4eb560e01b815260040160405180910390fd5b60405163e8e6dc7560e01b81525f906001600160a01b0384169063e8e6dc759061058d908590600401610cf0565b602060405180830381865afa1580156105a8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105cc9190610d3b565b60801c90506001600160a01b038316636a9154aa836105ec845f80610923565b60801b6040518363ffffffff1660e01b815260040161060c929190610d56565b5f604051808303815f87803b158015610623575f5ffd5b505af1158015610635573d5f5f3e3d5ffd5b50506040516001600160a01b038086169350861691507f4f3ab9ff0cc4f039268532098e01239544b0420171876e36889d01c62c784c79905f90a3505050565b335f908152602081905260409020546001146106a45760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b335f908152602081905260409020546001146107175760405163ea8e4eb560e01b815260040160405180910390fd5b5f6107218261096d565b9050600281600381111561073757610737610d79565b0361075e575f6107468361098c565b90506107588461011f835f01516109f4565b50505050565b600381600381111561077257610772610d79565b03610793575f61078183610a52565b90506107588461015a835f01516109f4565b604051637d5ba07f60e01b815260040160405180910390fd5b335f908152602081905260409020546001146107db5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b5f8061082d6020840184610d8d565b60801c905061083c815f610955565b151560011480156108d5575060405163854b89d560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063854b89d590610894908990600401610cf0565b602060405180830381865afa1580156108af573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108d39190610d04565b155b156108e3575f9150506104a5565b5f6108f46040850160208601610d8d565b60801c9050610903815f610955565b1515600103610916575f925050506104a5565b5060019695505050505050565b5f811561093f575060016001600160801b0383161b8317610529565b505060016001600160801b03919091161b191690565b60016001600160801b039182161b9190911616151590565b5f6109788282610a67565b60ff16600381111561025557610255610d79565b60408051602081019091525f815260025b6109a68361096d565b60038111156109b7576109b7610d79565b146109d5576040516304c735eb60e11b815260040160405180910390fd5b6040805160208101909152806109ec846001610a9d565b905292915050565b5f6001600160601b03821615610a4b5760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b604482015260640160405180910390fd5b5060601c90565b60408051602081019091525f8152600361099d565b5f610a73826001610da8565b83511015610a9457604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f610aa9826020610da8565b83511015610aca57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f60208284031215610ae3575f5ffd5b81356001600160e01b031981168114610529575f5ffd5b80356001600160a01b0381168114610b10575f5ffd5b919050565b5f60408284031215610b25575f5ffd5b50919050565b5f5f5f5f5f60c08688031215610b3f575f5ffd5b610b4886610afa565b9450610b5660208701610afa565b9350610b6460408701610afa565b925060608601359150610b7a8760808801610b15565b90509295509295909350565b5f5f60408385031215610b97575f5ffd5b610ba083610afa565b9150610bae60208401610afa565b90509250929050565b5f5f5f5f60a08587031215610bca575f5ffd5b610bd385610afa565b9350610be160208601610afa565b925060408501359150610bf78660608701610b15565b905092959194509250565b5f60208284031215610c12575f5ffd5b61052982610afa565b634e487b7160e01b5f52604160045260245ffd5b5f5f60408385031215610c40575f5ffd5b610c4983610afa565b915060208301356001600160401b03811115610c63575f5ffd5b8301601f81018513610c73575f5ffd5b80356001600160401b03811115610c8c57610c8c610c1b565b604051601f8201601f19908116603f011681016001600160401b0381118282101715610cba57610cba610c1b565b604052818152828201602001871015610cd1575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b6001600160a01b0391909116815260200190565b5f60208284031215610d14575f5ffd5b81518015158114610529575f5ffd5b6001600160801b031981168114610d38575f5ffd5b50565b5f60208284031215610d4b575f5ffd5b815161052981610d23565b6001600160a01b039290921682526001600160801b031916602082015260400190565b634e487b7160e01b5f52602160045260245ffd5b5f60208284031215610d9d575f5ffd5b813561052981610d23565b8082018082111561025557634e487b7160e01b5f52601160045260245ffdfea26469706673582212202c3d8959afa4c1ad3c120ee5054d12d2c426a8269b4dae819ad53c0976e5c6aa64736f6c634300081c00330000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f000000000000000000000000b8f0141317f8410a1f87f1b26af3d8bdc4bcf16e
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106100ad575f3560e01c806301ffc9a7146100b1578063078d18cd146100d957806315748250146101115780633f71910e1461012657806346de0fb1146101395780635adb6ddb1461014c57806365fae35e1461015f5780637aeba8d5146101725780637f5ca5a3146101855780639c52a7f11461019e578063bf353dbb146101b1578063ebf0c717146101de578063ef59bc9214610212575b5f5ffd5b6100c46100bf366004610ad3565b610225565b60405190151581526020015b60405180910390f35b6100f86100e7366004610b2b565b63078d18cd60e01b95945050505050565b6040516001600160e01b031990911681526020016100d0565b61012461011f366004610b86565b61025b565b005b6100f8610134366004610bb7565b610471565b6100c4610147366004610b86565b6104ad565b61012461015a366004610b86565b610530565b61012461016d366004610c02565b610675565b610124610180366004610c2f565b6106e8565b61018c5f81565b60405160ff90911681526020016100d0565b6101246101ac366004610c02565b6107ac565b6101d06101bf366004610c02565b5f6020819052908152604090205481565b6040519081526020016100d0565b6102057f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f81565b6040516100d09190610cf0565b6100c4610220366004610bb7565b61081e565b5f6001600160e01b03198216632b53a76160e21b148061025557506001600160e01b031982166301ffc9a760e01b145b92915050565b335f9081526020819052604090205460011461028a5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381166102b157604051631e778ac960e21b815260040160405180910390fd5b60405163854b89d560e01b81526001600160a01b037f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f169063854b89d5906102fd908490600401610cf0565b602060405180830381865afa158015610318573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061033c9190610d04565b1561035a576040516307bd5aa160e51b815260040160405180910390fd5b60405163e8e6dc7560e01b81525f906001600160a01b0384169063e8e6dc7590610388908590600401610cf0565b602060405180830381865afa1580156103a3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103c79190610d3b565b60801c90506001600160a01b038316636a9154aa836103e8845f6001610923565b60801b6040518363ffffffff1660e01b8152600401610408929190610d56565b5f604051808303815f87803b15801561041f575f5ffd5b505af1158015610431573d5f5f3e3d5ffd5b50506040516001600160a01b038086169350861691507f51d18786e9cb144f87d46e7b796309ea84c7c687d91e09c97f051eacf59bc528905f90a3505050565b5f61047e8585858561081e565b61049b57604051637c8733a560e11b815260040160405180910390fd5b50631fb8c88760e11b5b949350505050565b60405163e8e6dc7560e01b81525f906105299082906001600160a01b0386169063e8e6dc75906104e1908790600401610cf0565b602060405180830381865afa1580156104fc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105209190610d3b565b60801c90610955565b9392505050565b335f9081526020819052604090205460011461055f5760405163ea8e4eb560e01b815260040160405180910390fd5b60405163e8e6dc7560e01b81525f906001600160a01b0384169063e8e6dc759061058d908590600401610cf0565b602060405180830381865afa1580156105a8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105cc9190610d3b565b60801c90506001600160a01b038316636a9154aa836105ec845f80610923565b60801b6040518363ffffffff1660e01b815260040161060c929190610d56565b5f604051808303815f87803b158015610623575f5ffd5b505af1158015610635573d5f5f3e3d5ffd5b50506040516001600160a01b038086169350861691507f4f3ab9ff0cc4f039268532098e01239544b0420171876e36889d01c62c784c79905f90a3505050565b335f908152602081905260409020546001146106a45760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b335f908152602081905260409020546001146107175760405163ea8e4eb560e01b815260040160405180910390fd5b5f6107218261096d565b9050600281600381111561073757610737610d79565b0361075e575f6107468361098c565b90506107588461011f835f01516109f4565b50505050565b600381600381111561077257610772610d79565b03610793575f61078183610a52565b90506107588461015a835f01516109f4565b604051637d5ba07f60e01b815260040160405180910390fd5b335f908152602081905260409020546001146107db5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b5f8061082d6020840184610d8d565b60801c905061083c815f610955565b151560011480156108d5575060405163854b89d560e01b81526001600160a01b037f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f169063854b89d590610894908990600401610cf0565b602060405180830381865afa1580156108af573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108d39190610d04565b155b156108e3575f9150506104a5565b5f6108f46040850160208601610d8d565b60801c9050610903815f610955565b1515600103610916575f925050506104a5565b5060019695505050505050565b5f811561093f575060016001600160801b0383161b8317610529565b505060016001600160801b03919091161b191690565b60016001600160801b039182161b9190911616151590565b5f6109788282610a67565b60ff16600381111561025557610255610d79565b60408051602081019091525f815260025b6109a68361096d565b60038111156109b7576109b7610d79565b146109d5576040516304c735eb60e11b815260040160405180910390fd5b6040805160208101909152806109ec846001610a9d565b905292915050565b5f6001600160601b03821615610a4b5760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b604482015260640160405180910390fd5b5060601c90565b60408051602081019091525f8152600361099d565b5f610a73826001610da8565b83511015610a9457604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f610aa9826020610da8565b83511015610aca57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f60208284031215610ae3575f5ffd5b81356001600160e01b031981168114610529575f5ffd5b80356001600160a01b0381168114610b10575f5ffd5b919050565b5f60408284031215610b25575f5ffd5b50919050565b5f5f5f5f5f60c08688031215610b3f575f5ffd5b610b4886610afa565b9450610b5660208701610afa565b9350610b6460408701610afa565b925060608601359150610b7a8760808801610b15565b90509295509295909350565b5f5f60408385031215610b97575f5ffd5b610ba083610afa565b9150610bae60208401610afa565b90509250929050565b5f5f5f5f60a08587031215610bca575f5ffd5b610bd385610afa565b9350610be160208601610afa565b925060408501359150610bf78660608701610b15565b905092959194509250565b5f60208284031215610c12575f5ffd5b61052982610afa565b634e487b7160e01b5f52604160045260245ffd5b5f5f60408385031215610c40575f5ffd5b610c4983610afa565b915060208301356001600160401b03811115610c63575f5ffd5b8301601f81018513610c73575f5ffd5b80356001600160401b03811115610c8c57610c8c610c1b565b604051601f8201601f19908116603f011681016001600160401b0381118282101715610cba57610cba610c1b565b604052818152828201602001871015610cd1575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b6001600160a01b0391909116815260200190565b5f60208284031215610d14575f5ffd5b81518015158114610529575f5ffd5b6001600160801b031981168114610d38575f5ffd5b50565b5f60208284031215610d4b575f5ffd5b815161052981610d23565b6001600160a01b039290921682526001600160801b031916602082015260400190565b634e487b7160e01b5f52602160045260245ffd5b5f60208284031215610d9d575f5ffd5b813561052981610d23565b8082018082111561025557634e487b7160e01b5f52601160045260245ffdfea26469706673582212202c3d8959afa4c1ad3c120ee5054d12d2c426a8269b4dae819ad53c0976e5c6aa64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f000000000000000000000000b8f0141317f8410a1f87f1b26af3d8bdc4bcf16e
-----Decoded View---------------
Arg [0] : root_ (address): 0x7Ed48C31f2fdC40d37407cBaBf0870B2b688368f
Arg [1] : deployer (address): 0xB8f0141317f8410a1F87F1B26AF3D8bdc4BcF16E
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f
Arg [1] : 000000000000000000000000b8f0141317f8410a1f87f1b26af3d8bdc4bcf16e
Net Worth in USD
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.