| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| 0x9c76cb9bd85d7aab1459e84dd3ed0a71a502059d072c67e6aaf2397263959443 | Delegate All | (pending) | 23 hrs ago | IN | 0 ETH | (Pending) | |||
| Delegate All | 24565360 | 3 hrs ago | IN | 0 ETH | 0.00006145 | ||||
| Delegate All | 24562879 | 12 hrs ago | IN | 0 ETH | 0.00001307 | ||||
| Delegate All | 24559503 | 23 hrs ago | IN | 0 ETH | 0.00035628 | ||||
| Delegate All | 24552908 | 45 hrs ago | IN | 0 ETH | 0.00006062 | ||||
| Delegate All | 24552618 | 46 hrs ago | IN | 0 ETH | 0.00036595 | ||||
| Delegate All | 24551339 | 2 days ago | IN | 0 ETH | 0.00006213 | ||||
| Delegate ERC721 | 24549521 | 2 days ago | IN | 0 ETH | 0.0000317 | ||||
| Delegate ERC721 | 24545730 | 2 days ago | IN | 0.005 ETH | 0.00000408 | ||||
| Delegate ERC721 | 24545671 | 2 days ago | IN | 0 ETH | 0.00000275 | ||||
| Delegate ERC721 | 24545277 | 2 days ago | IN | 0.005 ETH | 0.0000142 | ||||
| Delegate All | 24539126 | 3 days ago | IN | 0 ETH | 0.0000011 | ||||
| Delegate ERC721 | 24539109 | 3 days ago | IN | 0 ETH | 0.00006424 | ||||
| Delegate All | 24539107 | 3 days ago | IN | 0 ETH | 0.00012462 | ||||
| Delegate ERC721 | 24539101 | 3 days ago | IN | 0 ETH | 0.00006411 | ||||
| Delegate ERC721 | 24539084 | 3 days ago | IN | 0 ETH | 0.00037979 | ||||
| Delegate ERC721 | 24539073 | 3 days ago | IN | 0 ETH | 0.00006401 | ||||
| Delegate All | 24537678 | 4 days ago | IN | 0.005 ETH | 0.00032494 | ||||
| Delegate ERC721 | 24534767 | 4 days ago | IN | 0.005 ETH | 0.00042451 | ||||
| Delegate ERC721 | 24534720 | 4 days ago | IN | 0.005 ETH | 0.00043524 | ||||
| Delegate All | 24534627 | 4 days ago | IN | 0.005 ETH | 0.00032963 | ||||
| Delegate All | 24532777 | 4 days ago | IN | 0 ETH | 0.00001428 | ||||
| Multicall | 24529824 | 5 days ago | IN | 0 ETH | 0.00085063 | ||||
| Multicall | 24529822 | 5 days ago | IN | 0 ETH | 0.00001262 | ||||
| Delegate All | 24527601 | 5 days ago | IN | 0.005 ETH | 0.00003849 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Delegate All | 24298725 | 37 days ago | 0.005 ETH | ||||
| Transfer | 24275970 | 40 days ago | 28.22549369 ETH | ||||
| Delegate All | 24194809 | 51 days ago | 0.005 ETH | ||||
| Delegate All | 24027742 | 75 days ago | 0.005 ETH | ||||
| Delegate All | 23991734 | 80 days ago | 0.005 ETH | ||||
| Delegate Contrac... | 23828420 | 103 days ago | 0.005 ETH | ||||
| Delegate ERC721 | 23798563 | 107 days ago | 0.005 ETH | ||||
| Delegate All | 23728668 | 117 days ago | 0.005 ETH | ||||
| Delegate All | 23715654 | 118 days ago | 0.005 ETH | ||||
| Delegate All | 23712734 | 119 days ago | 0.005 ETH | ||||
| Delegate All | 23657077 | 127 days ago | 0.005 ETH | ||||
| Delegate All | 23578098 | 138 days ago | 0.005 ETH | ||||
| Delegate All | 23199981 | 191 days ago | 0.005 ETH | ||||
| Delegate All | 23042793 | 213 days ago | 0.005 ETH | ||||
| Delegate All | 22725423 | 257 days ago | 0.005 ETH | ||||
| Delegate All | 22719454 | 258 days ago | 0.005 ETH | ||||
| Delegate All | 22702213 | 260 days ago | 0.005 ETH | ||||
| Delegate All | 22623644 | 271 days ago | 0.005 ETH | ||||
| Delegate All | 22596313 | 275 days ago | 0.005 ETH | ||||
| Delegate All | 22565754 | 279 days ago | 0.005 ETH | ||||
| Delegate All | 22546576 | 282 days ago | 0.005 ETH | ||||
| Delegate All | 22476658 | 292 days ago | 0.005 ETH | ||||
| Delegate All | 22474703 | 292 days ago | 0.005 ETH | ||||
| Delegate All | 22460767 | 294 days ago | 0.005 ETH | ||||
| Delegate All | 22446795 | 296 days ago | 0.005 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
DelegateRegistry
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 9999999 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.21;
import {IDelegateRegistry as IDelegateRegistry} from "./IDelegateRegistry.sol";
import {RegistryHashes as Hashes} from "./libraries/RegistryHashes.sol";
import {RegistryStorage as Storage} from "./libraries/RegistryStorage.sol";
import {RegistryOps as Ops} from "./libraries/RegistryOps.sol";
/**
* @title DelegateRegistry
* @custom:version 2.0
* @custom:coauthor foobar (0xfoobar)
* @custom:coauthor mireynolds
* @notice A standalone immutable registry storing delegated permissions from one address to another
*/
contract DelegateRegistry is IDelegateRegistry {
/// @dev Only this mapping should be used to verify delegations; the other mapping arrays are for enumerations
mapping(bytes32 delegationHash => bytes32[5] delegationStorage) internal delegations;
/// @dev Vault delegation enumeration outbox, for pushing new hashes only
mapping(address from => bytes32[] delegationHashes) internal outgoingDelegationHashes;
/// @dev Delegate enumeration inbox, for pushing new hashes only
mapping(address to => bytes32[] delegationHashes) internal incomingDelegationHashes;
/**
* ----------- WRITE -----------
*/
/// @inheritdoc IDelegateRegistry
function multicall(bytes[] calldata data) external payable override returns (bytes[] memory results) {
results = new bytes[](data.length);
bool success;
unchecked {
for (uint256 i = 0; i < data.length; ++i) {
//slither-disable-next-line calls-loop,delegatecall-loop
(success, results[i]) = address(this).delegatecall(data[i]);
if (!success) revert MulticallFailed();
}
}
}
/// @inheritdoc IDelegateRegistry
function delegateAll(address to, bytes32 rights, bool enable) external payable override returns (bytes32 hash) {
hash = Hashes.allHash(msg.sender, rights, to);
bytes32 location = Hashes.location(hash);
address loadedFrom = _loadFrom(location);
if (enable) {
if (loadedFrom == Storage.DELEGATION_EMPTY) {
_pushDelegationHashes(msg.sender, to, hash);
_writeDelegationAddresses(location, msg.sender, to, address(0));
if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights);
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
_updateFrom(location, msg.sender);
}
} else if (loadedFrom == msg.sender) {
_updateFrom(location, Storage.DELEGATION_REVOKED);
}
emit DelegateAll(msg.sender, to, rights, enable);
}
/// @inheritdoc IDelegateRegistry
function delegateContract(address to, address contract_, bytes32 rights, bool enable) external payable override returns (bytes32 hash) {
hash = Hashes.contractHash(msg.sender, rights, to, contract_);
bytes32 location = Hashes.location(hash);
address loadedFrom = _loadFrom(location);
if (enable) {
if (loadedFrom == Storage.DELEGATION_EMPTY) {
_pushDelegationHashes(msg.sender, to, hash);
_writeDelegationAddresses(location, msg.sender, to, contract_);
if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights);
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
_updateFrom(location, msg.sender);
}
} else if (loadedFrom == msg.sender) {
_updateFrom(location, Storage.DELEGATION_REVOKED);
}
emit DelegateContract(msg.sender, to, contract_, rights, enable);
}
/// @inheritdoc IDelegateRegistry
function delegateERC721(address to, address contract_, uint256 tokenId, bytes32 rights, bool enable) external payable override returns (bytes32 hash) {
hash = Hashes.erc721Hash(msg.sender, rights, to, tokenId, contract_);
bytes32 location = Hashes.location(hash);
address loadedFrom = _loadFrom(location);
if (enable) {
if (loadedFrom == Storage.DELEGATION_EMPTY) {
_pushDelegationHashes(msg.sender, to, hash);
_writeDelegationAddresses(location, msg.sender, to, contract_);
_writeDelegation(location, Storage.POSITIONS_TOKEN_ID, tokenId);
if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights);
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
_updateFrom(location, msg.sender);
}
} else if (loadedFrom == msg.sender) {
_updateFrom(location, Storage.DELEGATION_REVOKED);
}
emit DelegateERC721(msg.sender, to, contract_, tokenId, rights, enable);
}
// @inheritdoc IDelegateRegistry
function delegateERC20(address to, address contract_, bytes32 rights, uint256 amount) external payable override returns (bytes32 hash) {
hash = Hashes.erc20Hash(msg.sender, rights, to, contract_);
bytes32 location = Hashes.location(hash);
address loadedFrom = _loadFrom(location);
if (amount != 0) {
if (loadedFrom == Storage.DELEGATION_EMPTY) {
_pushDelegationHashes(msg.sender, to, hash);
_writeDelegationAddresses(location, msg.sender, to, contract_);
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights);
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
_updateFrom(location, msg.sender);
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
} else if (loadedFrom == msg.sender) {
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
}
} else if (loadedFrom == msg.sender) {
_updateFrom(location, Storage.DELEGATION_REVOKED);
_writeDelegation(location, Storage.POSITIONS_AMOUNT, uint256(0));
}
emit DelegateERC20(msg.sender, to, contract_, rights, amount);
}
/// @inheritdoc IDelegateRegistry
function delegateERC1155(address to, address contract_, uint256 tokenId, bytes32 rights, uint256 amount) external payable override returns (bytes32 hash) {
hash = Hashes.erc1155Hash(msg.sender, rights, to, tokenId, contract_);
bytes32 location = Hashes.location(hash);
address loadedFrom = _loadFrom(location);
if (amount != 0) {
if (loadedFrom == Storage.DELEGATION_EMPTY) {
_pushDelegationHashes(msg.sender, to, hash);
_writeDelegationAddresses(location, msg.sender, to, contract_);
_writeDelegation(location, Storage.POSITIONS_TOKEN_ID, tokenId);
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights);
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
_updateFrom(location, msg.sender);
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
} else if (loadedFrom == msg.sender) {
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
}
} else if (loadedFrom == msg.sender) {
_updateFrom(location, Storage.DELEGATION_REVOKED);
_writeDelegation(location, Storage.POSITIONS_AMOUNT, uint256(0));
}
emit DelegateERC1155(msg.sender, to, contract_, tokenId, rights, amount);
}
/// @dev Transfer native token out
function sweep() external {
assembly ("memory-safe") {
// This hardcoded address is a CREATE2 factory counterfactual smart contract wallet that will always accept native token transfers
let result := call(gas(), 0x000000dE1E80ea5a234FB5488fee2584251BC7e8, selfbalance(), 0, 0, 0, 0)
}
}
/**
* ----------- CHECKS -----------
*/
/// @inheritdoc IDelegateRegistry
function checkDelegateForAll(address to, address from, bytes32 rights) external view override returns (bool valid) {
if (!_invalidFrom(from)) {
valid = _validateFrom(Hashes.allLocation(from, "", to), from);
if (!Ops.or(rights == "", valid)) valid = _validateFrom(Hashes.allLocation(from, rights, to), from);
}
assembly ("memory-safe") {
// Only first 32 bytes of scratch space is accessed
mstore(0, iszero(iszero(valid))) // Compiler cleans dirty booleans on the stack to 1, so do the same here
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
}
}
/// @inheritdoc IDelegateRegistry
function checkDelegateForContract(address to, address from, address contract_, bytes32 rights) external view override returns (bool valid) {
if (!_invalidFrom(from)) {
valid = _validateFrom(Hashes.allLocation(from, "", to), from) || _validateFrom(Hashes.contractLocation(from, "", to, contract_), from);
if (!Ops.or(rights == "", valid)) {
valid = _validateFrom(Hashes.allLocation(from, rights, to), from) || _validateFrom(Hashes.contractLocation(from, rights, to, contract_), from);
}
}
assembly ("memory-safe") {
// Only first 32 bytes of scratch space is accessed
mstore(0, iszero(iszero(valid))) // Compiler cleans dirty booleans on the stack to 1, so do the same here
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
}
}
/// @inheritdoc IDelegateRegistry
function checkDelegateForERC721(address to, address from, address contract_, uint256 tokenId, bytes32 rights) external view override returns (bool valid) {
if (!_invalidFrom(from)) {
valid = _validateFrom(Hashes.allLocation(from, "", to), from) || _validateFrom(Hashes.contractLocation(from, "", to, contract_), from)
|| _validateFrom(Hashes.erc721Location(from, "", to, tokenId, contract_), from);
if (!Ops.or(rights == "", valid)) {
valid = _validateFrom(Hashes.allLocation(from, rights, to), from) || _validateFrom(Hashes.contractLocation(from, rights, to, contract_), from)
|| _validateFrom(Hashes.erc721Location(from, rights, to, tokenId, contract_), from);
}
}
assembly ("memory-safe") {
// Only first 32 bytes of scratch space is accessed
mstore(0, iszero(iszero(valid))) // Compiler cleans dirty booleans on the stack to 1, so do the same here
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
}
}
/// @inheritdoc IDelegateRegistry
function checkDelegateForERC20(address to, address from, address contract_, bytes32 rights) external view override returns (uint256 amount) {
if (!_invalidFrom(from)) {
amount = (_validateFrom(Hashes.allLocation(from, "", to), from) || _validateFrom(Hashes.contractLocation(from, "", to, contract_), from))
? type(uint256).max
: _loadDelegationUint(Hashes.erc20Location(from, "", to, contract_), Storage.POSITIONS_AMOUNT);
if (!Ops.or(rights == "", amount == type(uint256).max)) {
uint256 rightsBalance = (_validateFrom(Hashes.allLocation(from, rights, to), from) || _validateFrom(Hashes.contractLocation(from, rights, to, contract_), from))
? type(uint256).max
: _loadDelegationUint(Hashes.erc20Location(from, rights, to, contract_), Storage.POSITIONS_AMOUNT);
amount = Ops.max(rightsBalance, amount);
}
}
assembly ("memory-safe") {
mstore(0, amount) // Only first 32 bytes of scratch space being accessed
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
}
}
/// @inheritdoc IDelegateRegistry
function checkDelegateForERC1155(address to, address from, address contract_, uint256 tokenId, bytes32 rights) external view override returns (uint256 amount) {
if (!_invalidFrom(from)) {
amount = (_validateFrom(Hashes.allLocation(from, "", to), from) || _validateFrom(Hashes.contractLocation(from, "", to, contract_), from))
? type(uint256).max
: _loadDelegationUint(Hashes.erc1155Location(from, "", to, tokenId, contract_), Storage.POSITIONS_AMOUNT);
if (!Ops.or(rights == "", amount == type(uint256).max)) {
uint256 rightsBalance = (_validateFrom(Hashes.allLocation(from, rights, to), from) || _validateFrom(Hashes.contractLocation(from, rights, to, contract_), from))
? type(uint256).max
: _loadDelegationUint(Hashes.erc1155Location(from, rights, to, tokenId, contract_), Storage.POSITIONS_AMOUNT);
amount = Ops.max(rightsBalance, amount);
}
}
assembly ("memory-safe") {
mstore(0, amount) // Only first 32 bytes of scratch space is accessed
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
}
}
/**
* ----------- ENUMERATIONS -----------
*/
/// @inheritdoc IDelegateRegistry
function getIncomingDelegations(address to) external view override returns (Delegation[] memory delegations_) {
delegations_ = _getValidDelegationsFromHashes(incomingDelegationHashes[to]);
}
/// @inheritdoc IDelegateRegistry
function getOutgoingDelegations(address from) external view returns (Delegation[] memory delegations_) {
delegations_ = _getValidDelegationsFromHashes(outgoingDelegationHashes[from]);
}
/// @inheritdoc IDelegateRegistry
function getIncomingDelegationHashes(address to) external view returns (bytes32[] memory delegationHashes) {
delegationHashes = _getValidDelegationHashesFromHashes(incomingDelegationHashes[to]);
}
/// @inheritdoc IDelegateRegistry
function getOutgoingDelegationHashes(address from) external view returns (bytes32[] memory delegationHashes) {
delegationHashes = _getValidDelegationHashesFromHashes(outgoingDelegationHashes[from]);
}
/// @inheritdoc IDelegateRegistry
function getDelegationsFromHashes(bytes32[] calldata hashes) external view returns (Delegation[] memory delegations_) {
delegations_ = new Delegation[](hashes.length);
unchecked {
for (uint256 i = 0; i < hashes.length; ++i) {
bytes32 location = Hashes.location(hashes[i]);
address from = _loadFrom(location);
if (_invalidFrom(from)) {
delegations_[i] = Delegation({type_: DelegationType.NONE, to: address(0), from: address(0), rights: "", amount: 0, contract_: address(0), tokenId: 0});
} else {
(, address to, address contract_) = _loadDelegationAddresses(location);
delegations_[i] = Delegation({
type_: Hashes.decodeType(hashes[i]),
to: to,
from: from,
rights: _loadDelegationBytes32(location, Storage.POSITIONS_RIGHTS),
amount: _loadDelegationUint(location, Storage.POSITIONS_AMOUNT),
contract_: contract_,
tokenId: _loadDelegationUint(location, Storage.POSITIONS_TOKEN_ID)
});
}
}
}
}
/**
* ----------- EXTERNAL STORAGE ACCESS -----------
*/
function readSlot(bytes32 location) external view returns (bytes32 contents) {
assembly {
contents := sload(location)
}
}
function readSlots(bytes32[] calldata locations) external view returns (bytes32[] memory contents) {
uint256 length = locations.length;
contents = new bytes32[](length);
bytes32 tempLocation;
bytes32 tempValue;
unchecked {
for (uint256 i = 0; i < length; ++i) {
tempLocation = locations[i];
assembly {
tempValue := sload(tempLocation)
}
contents[i] = tempValue;
}
}
}
/**
* ----------- ERC165 -----------
*/
/// @notice Query if a contract implements an ERC-165 interface
/// @param interfaceId The interface identifier
/// @return valid Whether the queried interface is supported
function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
return Ops.or(interfaceId == type(IDelegateRegistry).interfaceId, interfaceId == 0x01ffc9a7);
}
/**
* ----------- INTERNAL -----------
*/
/// @dev Helper function to push new delegation hashes to the incoming and outgoing hashes mappings
function _pushDelegationHashes(address from, address to, bytes32 delegationHash) internal {
outgoingDelegationHashes[from].push(delegationHash);
incomingDelegationHashes[to].push(delegationHash);
}
/// @dev Helper function that writes bytes32 data to delegation data location at array position
function _writeDelegation(bytes32 location, uint256 position, bytes32 data) internal {
assembly {
sstore(add(location, position), data)
}
}
/// @dev Helper function that writes uint256 data to delegation data location at array position
function _writeDelegation(bytes32 location, uint256 position, uint256 data) internal {
assembly {
sstore(add(location, position), data)
}
}
/// @dev Helper function that writes addresses according to the packing rule for delegation storage
function _writeDelegationAddresses(bytes32 location, address from, address to, address contract_) internal {
(bytes32 firstSlot, bytes32 secondSlot) = Storage.packAddresses(from, to, contract_);
uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED;
uint256 secondPacked = Storage.POSITIONS_SECOND_PACKED;
assembly {
sstore(add(location, firstPacked), firstSlot)
sstore(add(location, secondPacked), secondSlot)
}
}
/// @dev Helper function that writes `from` while preserving the rest of the storage slot
function _updateFrom(bytes32 location, address from) internal {
uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED;
uint256 cleanAddress = Storage.CLEAN_ADDRESS;
uint256 cleanUpper12Bytes = type(uint256).max << 160;
assembly {
let slot := and(sload(add(location, firstPacked)), cleanUpper12Bytes)
sstore(add(location, firstPacked), or(slot, and(from, cleanAddress)))
}
}
/// @dev Helper function that takes an array of delegation hashes and returns an array of Delegation structs with their onchain information
function _getValidDelegationsFromHashes(bytes32[] storage hashes) internal view returns (Delegation[] memory delegations_) {
uint256 count = 0;
uint256 hashesLength = hashes.length;
bytes32 hash;
bytes32[] memory filteredHashes = new bytes32[](hashesLength);
unchecked {
for (uint256 i = 0; i < hashesLength; ++i) {
hash = hashes[i];
if (_invalidFrom(_loadFrom(Hashes.location(hash)))) continue;
filteredHashes[count++] = hash;
}
delegations_ = new Delegation[](count);
bytes32 location;
for (uint256 i = 0; i < count; ++i) {
hash = filteredHashes[i];
location = Hashes.location(hash);
(address from, address to, address contract_) = _loadDelegationAddresses(location);
delegations_[i] = Delegation({
type_: Hashes.decodeType(hash),
to: to,
from: from,
rights: _loadDelegationBytes32(location, Storage.POSITIONS_RIGHTS),
amount: _loadDelegationUint(location, Storage.POSITIONS_AMOUNT),
contract_: contract_,
tokenId: _loadDelegationUint(location, Storage.POSITIONS_TOKEN_ID)
});
}
}
}
/// @dev Helper function that takes an array of delegation hashes and returns an array of valid delegation hashes
function _getValidDelegationHashesFromHashes(bytes32[] storage hashes) internal view returns (bytes32[] memory validHashes) {
uint256 count = 0;
uint256 hashesLength = hashes.length;
bytes32 hash;
bytes32[] memory filteredHashes = new bytes32[](hashesLength);
unchecked {
for (uint256 i = 0; i < hashesLength; ++i) {
hash = hashes[i];
if (_invalidFrom(_loadFrom(Hashes.location(hash)))) continue;
filteredHashes[count++] = hash;
}
validHashes = new bytes32[](count);
for (uint256 i = 0; i < count; ++i) {
validHashes[i] = filteredHashes[i];
}
}
}
/// @dev Helper function that loads delegation data from a particular array position and returns as bytes32
function _loadDelegationBytes32(bytes32 location, uint256 position) internal view returns (bytes32 data) {
assembly {
data := sload(add(location, position))
}
}
/// @dev Helper function that loads delegation data from a particular array position and returns as uint256
function _loadDelegationUint(bytes32 location, uint256 position) internal view returns (uint256 data) {
assembly {
data := sload(add(location, position))
}
}
// @dev Helper function that loads the from address from storage according to the packing rule for delegation storage
function _loadFrom(bytes32 location) internal view returns (address) {
bytes32 data;
uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED;
assembly {
data := sload(add(location, firstPacked))
}
return Storage.unpackAddress(data);
}
/// @dev Helper function to establish whether a delegation is enabled
function _validateFrom(bytes32 location, address from) internal view returns (bool) {
return (from == _loadFrom(location));
}
/// @dev Helper function that loads the address for the delegation according to the packing rule for delegation storage
function _loadDelegationAddresses(bytes32 location) internal view returns (address from, address to, address contract_) {
bytes32 firstSlot;
bytes32 secondSlot;
uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED;
uint256 secondPacked = Storage.POSITIONS_SECOND_PACKED;
assembly {
firstSlot := sload(add(location, firstPacked))
secondSlot := sload(add(location, secondPacked))
}
(from, to, contract_) = Storage.unpackAddresses(firstSlot, secondSlot);
}
function _invalidFrom(address from) internal pure returns (bool) {
return Ops.or(from == Storage.DELEGATION_EMPTY, from == Storage.DELEGATION_REVOKED);
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.8.13;
/**
* @title IDelegateRegistry
* @custom:version 2.0
* @custom:author foobar (0xfoobar)
* @notice A standalone immutable registry storing delegated permissions from one address to another
*/
interface IDelegateRegistry {
/// @notice Delegation type, NONE is used when a delegation does not exist or is revoked
enum DelegationType {
NONE,
ALL,
CONTRACT,
ERC721,
ERC20,
ERC1155
}
/// @notice Struct for returning delegations
struct Delegation {
DelegationType type_;
address to;
address from;
bytes32 rights;
address contract_;
uint256 tokenId;
uint256 amount;
}
/// @notice Emitted when an address delegates or revokes rights for their entire wallet
event DelegateAll(address indexed from, address indexed to, bytes32 rights, bool enable);
/// @notice Emitted when an address delegates or revokes rights for a contract address
event DelegateContract(address indexed from, address indexed to, address indexed contract_, bytes32 rights, bool enable);
/// @notice Emitted when an address delegates or revokes rights for an ERC721 tokenId
event DelegateERC721(address indexed from, address indexed to, address indexed contract_, uint256 tokenId, bytes32 rights, bool enable);
/// @notice Emitted when an address delegates or revokes rights for an amount of ERC20 tokens
event DelegateERC20(address indexed from, address indexed to, address indexed contract_, bytes32 rights, uint256 amount);
/// @notice Emitted when an address delegates or revokes rights for an amount of an ERC1155 tokenId
event DelegateERC1155(address indexed from, address indexed to, address indexed contract_, uint256 tokenId, bytes32 rights, uint256 amount);
/// @notice Thrown if multicall calldata is malformed
error MulticallFailed();
/**
* ----------- WRITE -----------
*/
/**
* @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
* @param data The encoded function data for each of the calls to make to this contract
* @return results The results from each of the calls passed in via data
*/
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for all contracts
* @param to The address to act as delegate
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param enable Whether to enable or disable this delegation, true delegates and false revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateAll(address to, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for a specific contract
* @param to The address to act as delegate
* @param contract_ The contract whose rights are being delegated
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param enable Whether to enable or disable this delegation, true delegates and false revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateContract(address to, address contract_, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for a specific ERC721 token
* @param to The address to act as delegate
* @param contract_ The contract whose rights are being delegated
* @param tokenId The token id to delegate
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param enable Whether to enable or disable this delegation, true delegates and false revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateERC721(address to, address contract_, uint256 tokenId, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC20 tokens
* @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound)
* @param to The address to act as delegate
* @param contract_ The address for the fungible token contract
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param amount The amount to delegate, > 0 delegates and 0 revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateERC20(address to, address contract_, bytes32 rights, uint256 amount) external payable returns (bytes32 delegationHash);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC1155 tokens
* @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound)
* @param to The address to act as delegate
* @param contract_ The address of the contract that holds the token
* @param tokenId The token id to delegate
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param amount The amount of that token id to delegate, > 0 delegates and 0 revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateERC1155(address to, address contract_, uint256 tokenId, bytes32 rights, uint256 amount) external payable returns (bytes32 delegationHash);
/**
* ----------- CHECKS -----------
*/
/**
* @notice Check if `to` is a delegate of `from` for the entire wallet
* @param to The potential delegate address
* @param from The potential address who delegated rights
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return valid Whether delegate is granted to act on the from's behalf
*/
function checkDelegateForAll(address to, address from, bytes32 rights) external view returns (bool);
/**
* @notice Check if `to` is a delegate of `from` for the specified `contract_` or the entire wallet
* @param to The delegated address to check
* @param contract_ The specific contract address being checked
* @param from The cold wallet who issued the delegation
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return valid Whether delegate is granted to act on from's behalf for entire wallet or that specific contract
*/
function checkDelegateForContract(address to, address from, address contract_, bytes32 rights) external view returns (bool);
/**
* @notice Check if `to` is a delegate of `from` for the specific `contract` and `tokenId`, the entire `contract_`, or the entire wallet
* @param to The delegated address to check
* @param contract_ The specific contract address being checked
* @param tokenId The token id for the token to delegating
* @param from The wallet that issued the delegation
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return valid Whether delegate is granted to act on from's behalf for entire wallet, that contract, or that specific tokenId
*/
function checkDelegateForERC721(address to, address from, address contract_, uint256 tokenId, bytes32 rights) external view returns (bool);
/**
* @notice Returns the amount of ERC20 tokens the delegate is granted rights to act on the behalf of
* @param to The delegated address to check
* @param contract_ The address of the token contract
* @param from The cold wallet who issued the delegation
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return balance The delegated balance, which will be 0 if the delegation does not exist
*/
function checkDelegateForERC20(address to, address from, address contract_, bytes32 rights) external view returns (uint256);
/**
* @notice Returns the amount of a ERC1155 tokens the delegate is granted rights to act on the behalf of
* @param to The delegated address to check
* @param contract_ The address of the token contract
* @param tokenId The token id to check the delegated amount of
* @param from The cold wallet who issued the delegation
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return balance The delegated balance, which will be 0 if the delegation does not exist
*/
function checkDelegateForERC1155(address to, address from, address contract_, uint256 tokenId, bytes32 rights) external view returns (uint256);
/**
* ----------- ENUMERATIONS -----------
*/
/**
* @notice Returns all enabled delegations a given delegate has received
* @param to The address to retrieve delegations for
* @return delegations Array of Delegation structs
*/
function getIncomingDelegations(address to) external view returns (Delegation[] memory delegations);
/**
* @notice Returns all enabled delegations an address has given out
* @param from The address to retrieve delegations for
* @return delegations Array of Delegation structs
*/
function getOutgoingDelegations(address from) external view returns (Delegation[] memory delegations);
/**
* @notice Returns all hashes associated with enabled delegations an address has received
* @param to The address to retrieve incoming delegation hashes for
* @return delegationHashes Array of delegation hashes
*/
function getIncomingDelegationHashes(address to) external view returns (bytes32[] memory delegationHashes);
/**
* @notice Returns all hashes associated with enabled delegations an address has given out
* @param from The address to retrieve outgoing delegation hashes for
* @return delegationHashes Array of delegation hashes
*/
function getOutgoingDelegationHashes(address from) external view returns (bytes32[] memory delegationHashes);
/**
* @notice Returns the delegations for a given array of delegation hashes
* @param delegationHashes is an array of hashes that correspond to delegations
* @return delegations Array of Delegation structs, return empty structs for nonexistent or revoked delegations
*/
function getDelegationsFromHashes(bytes32[] calldata delegationHashes) external view returns (Delegation[] memory delegations);
/**
* ----------- STORAGE ACCESS -----------
*/
/**
* @notice Allows external contracts to read arbitrary storage slots
*/
function readSlot(bytes32 location) external view returns (bytes32);
/**
* @notice Allows external contracts to read an arbitrary array of storage slots
*/
function readSlots(bytes32[] calldata locations) external view returns (bytes32[] memory);
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.21;
import {IDelegateRegistry} from "../IDelegateRegistry.sol";
/**
* @title Library for calculating the hashes and storage locations used in the delegate registry
*
* The encoding for the 5 types of delegate registry hashes should be as follows:
*
* ALL: keccak256(abi.encodePacked(rights, from, to))
* CONTRACT: keccak256(abi.encodePacked(rights, from, to, contract_))
* ERC721: keccak256(abi.encodePacked(rights, from, to, contract_, tokenId))
* ERC20: keccak256(abi.encodePacked(rights, from, to, contract_))
* ERC1155: keccak256(abi.encodePacked(rights, from, to, contract_, tokenId))
*
* To avoid collisions between the hashes with respect to type, the hash is shifted left by one byte
* and the last byte is then encoded with a unique number for the delegation type
*
*/
library RegistryHashes {
/// @dev Used to delete everything but the last byte of a 32 byte word with and(word, EXTRACT_LAST_BYTE)
uint256 internal constant EXTRACT_LAST_BYTE = 0xff;
/// @dev Constants for the delegate registry delegation type enumeration
uint256 internal constant ALL_TYPE = 1;
uint256 internal constant CONTRACT_TYPE = 2;
uint256 internal constant ERC721_TYPE = 3;
uint256 internal constant ERC20_TYPE = 4;
uint256 internal constant ERC1155_TYPE = 5;
/// @dev Constant for the location of the delegations array in the delegate registry, defined to be zero
uint256 internal constant DELEGATION_SLOT = 0;
/**
* @notice Helper function to decode last byte of a delegation hash into its delegation type enum
* @param inputHash The bytehash to decode the type from
* @return decodedType The delegation type
*/
function decodeType(bytes32 inputHash) internal pure returns (IDelegateRegistry.DelegationType decodedType) {
assembly {
decodedType := and(inputHash, EXTRACT_LAST_BYTE)
}
}
/**
* @notice Helper function that computes the storage location of a particular delegation array
* @dev Storage keys further down the array can be obtained by adding computedLocation with the element position
* @dev Follows the solidity storage location encoding for a mapping(bytes32 => fixedArray) at the position of the delegationSlot
* @param inputHash The bytehash to decode the type from
* @return computedLocation is the storage key of the delegation array at position 0
*/
function location(bytes32 inputHash) internal pure returns (bytes32 computedLocation) {
assembly ("memory-safe") {
// This block only allocates memory in the scratch space
mstore(0, inputHash)
mstore(32, DELEGATION_SLOT)
computedLocation := keccak256(0, 64) // Run keccak256 over bytes in scratch space to obtain the storage key
}
}
/**
* @notice Helper function to compute delegation hash for `DelegationType.ALL`
* @dev Equivalent to `keccak256(abi.encodePacked(rights, from, to))` then left-shift by 1 byte and write the delegation type to the cleaned last byte
* @dev Will not revert if `from` or `to` are > uint160, any input larger than uint160 for `from` and `to` will be cleaned to its lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @return hash The delegation parameters encoded with ALL_TYPE
*/
function allHash(address from, bytes32 rights, address to) internal pure returns (bytes32 hash) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer
let ptr := mload(64) // Load the free memory pointer
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
hash := or(shl(8, keccak256(ptr, 72)), ALL_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte
}
}
/**
* @notice Helper function to compute delegation location for `DelegationType.ALL`
* @dev Equivalent to `location(allHash(rights, from, to))`
* @dev Will not revert if `from` or `to` are > uint160, any input larger than uint160 for `from` and `to` will be cleaned to its lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @return computedLocation The storage location of the all delegation with those parameters in the delegations mapping
*/
function allLocation(address from, bytes32 rights, address to) internal pure returns (bytes32 computedLocation) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer and in the scratch space
let ptr := mload(64) // Load the free memory pointer
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
mstore(0, or(shl(8, keccak256(ptr, 72)), ALL_TYPE)) // Computes `allHash`, then stores the result in scratch space
mstore(32, DELEGATION_SLOT)
computedLocation := keccak256(0, 64) // Runs keccak over the scratch space to obtain the storage key
}
}
/**
* @notice Helper function to compute delegation hash for `DelegationType.CONTRACT`
* @dev Equivalent to keccak256(abi.encodePacked(rights, from, to, contract_)) left-shifted by 1 then last byte overwritten with CONTRACT_TYPE
* @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @param contract_ The address of the contract specified by the delegation
* @return hash The delegation parameters encoded with CONTRACT_TYPE
*/
function contractHash(address from, bytes32 rights, address to, address contract_) internal pure returns (bytes32 hash) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer
let ptr := mload(64) // Load the free memory pointer
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 60), contract_)
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
hash := or(shl(8, keccak256(ptr, 92)), CONTRACT_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte
}
}
/**
* @notice Helper function to compute delegation location for `DelegationType.CONTRACT`
* @dev Equivalent to `location(contractHash(rights, from, to, contract_))`
* @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @param contract_ The address of the contract specified by the delegation
* @return computedLocation The storage location of the contract delegation with those parameters in the delegations mapping
*/
function contractLocation(address from, bytes32 rights, address to, address contract_) internal pure returns (bytes32 computedLocation) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer and in the scratch space
let ptr := mload(64) // Load free memory pointer
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 60), contract_)
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
mstore(0, or(shl(8, keccak256(ptr, 92)), CONTRACT_TYPE)) // Computes `contractHash`, then stores the result in scratch space
mstore(32, DELEGATION_SLOT)
computedLocation := keccak256(0, 64) // Runs keccak over the scratch space to obtain the storage key
}
}
/**
* @notice Helper function to compute delegation hash for `DelegationType.ERC721`
* @dev Equivalent to `keccak256(abi.encodePacked(rights, from, to, contract_, tokenId)) left-shifted by 1 then last byte overwritten with ERC721_TYPE
* @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @param tokenId The id of the token specified by the delegation
* @param contract_ The address of the contract specified by the delegation
* @return hash The delegation parameters encoded with ERC721_TYPE
*/
function erc721Hash(address from, bytes32 rights, address to, uint256 tokenId, address contract_) internal pure returns (bytes32 hash) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer
let ptr := mload(64) // Cache the free memory pointer.
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 92), tokenId)
mstore(add(ptr, 60), contract_)
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
hash := or(shl(8, keccak256(ptr, 124)), ERC721_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte
}
}
/**
* @notice Helper function to compute delegation location for `DelegationType.ERC721`
* @dev Equivalent to `location(ERC721Hash(rights, from, to, contract_, tokenId))`
* @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @param tokenId The id of the ERC721 token
* @param contract_ The address of the ERC721 token contract
* @return computedLocation The storage location of the ERC721 delegation with those parameters in the delegations mapping
*/
function erc721Location(address from, bytes32 rights, address to, uint256 tokenId, address contract_) internal pure returns (bytes32 computedLocation) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer and in the scratch space
let ptr := mload(64) // Cache the free memory pointer.
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 92), tokenId)
mstore(add(ptr, 60), contract_)
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
mstore(0, or(shl(8, keccak256(ptr, 124)), ERC721_TYPE)) // Computes erc721Hash, then stores the result in scratch space
mstore(32, DELEGATION_SLOT)
computedLocation := keccak256(0, 64) // Runs keccak256 over the scratch space to obtain the storage key
}
}
/**
* @notice Helper function to compute delegation hash for `DelegationType.ERC20`
* @dev Equivalent to `keccak256(abi.encodePacked(rights, from, to, contract_))` with the last byte overwritten with ERC20_TYPE
* @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @param contract_ The address of the ERC20 token contract
* @return hash The parameters encoded with ERC20_TYPE
*/
function erc20Hash(address from, bytes32 rights, address to, address contract_) internal pure returns (bytes32 hash) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer
let ptr := mload(64) // Load free memory pointer
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 60), contract_)
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
hash := or(shl(8, keccak256(ptr, 92)), ERC20_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte
}
}
/**
* @notice Helper function to compute delegation location for `DelegationType.ERC20`
* @dev Equivalent to `location(ERC20Hash(rights, from, to, contract_))`
* @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @param contract_ The address of the ERC20 token contract
* @return computedLocation The storage location of the ERC20 delegation with those parameters in the delegations mapping
*/
function erc20Location(address from, bytes32 rights, address to, address contract_) internal pure returns (bytes32 computedLocation) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer and in the scratch space
let ptr := mload(64) // Loads the free memory pointer
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 60), contract_)
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
mstore(0, or(shl(8, keccak256(ptr, 92)), ERC20_TYPE)) // Computes erc20Hash, then stores the result in scratch space
mstore(32, DELEGATION_SLOT)
computedLocation := keccak256(0, 64) // Runs keccak over the scratch space to obtain the storage key
}
}
/**
* @notice Helper function to compute delegation hash for `DelegationType.ERC1155`
* @dev Equivalent to keccak256(abi.encodePacked(rights, from, to, contract_, tokenId)) left-shifted with the last byte overwritten with ERC1155_TYPE
* @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @param tokenId The id of the ERC1155 token
* @param contract_ The address of the ERC1155 token contract
* @return hash The parameters encoded with ERC1155_TYPE
*/
function erc1155Hash(address from, bytes32 rights, address to, uint256 tokenId, address contract_) internal pure returns (bytes32 hash) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer
let ptr := mload(64) // Load the free memory pointer.
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 92), tokenId)
mstore(add(ptr, 60), contract_)
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
hash := or(shl(8, keccak256(ptr, 124)), ERC1155_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte
}
}
/**
* @notice Helper function to compute delegation location for `DelegationType.ERC1155`
* @dev Equivalent to `location(ERC1155Hash(rights, from, to, contract_, tokenId))`
* @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes
* @param from The address making the delegation
* @param rights The rights specified by the delegation
* @param to The address receiving the delegation
* @param tokenId The id of the ERC1155 token
* @param contract_ The address of the ERC1155 token contract
* @return computedLocation The storage location of the ERC1155 delegation with those parameters in the delegations mapping
*/
function erc1155Location(address from, bytes32 rights, address to, uint256 tokenId, address contract_) internal pure returns (bytes32 computedLocation) {
assembly ("memory-safe") {
// This block only allocates memory after the free memory pointer and in the scratch space
let ptr := mload(64) // Cache the free memory pointer.
// Lay out the variables from last to first, agnostic to upper 96 bits of address words.
mstore(add(ptr, 92), tokenId)
mstore(add(ptr, 60), contract_)
mstore(add(ptr, 40), to)
mstore(add(ptr, 20), from)
mstore(ptr, rights)
mstore(0, or(shl(8, keccak256(ptr, 124)), ERC1155_TYPE)) // Computes erc1155Hash, then stores the result in scratch space
mstore(32, DELEGATION_SLOT)
computedLocation := keccak256(0, 64) // Runs keccak over the scratch space to obtain the storage key
}
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.21;
library RegistryStorage {
/// @dev Standardizes `from` storage flags to prevent double-writes in the delegation in/outbox if the same delegation is revoked and rewritten
address internal constant DELEGATION_EMPTY = address(0);
address internal constant DELEGATION_REVOKED = address(1);
/// @dev Standardizes storage positions of delegation data
uint256 internal constant POSITIONS_FIRST_PACKED = 0; // | 4 bytes empty | first 8 bytes of contract address | 20 bytes of from address |
uint256 internal constant POSITIONS_SECOND_PACKED = 1; // | last 12 bytes of contract address | 20 bytes of to address |
uint256 internal constant POSITIONS_RIGHTS = 2;
uint256 internal constant POSITIONS_TOKEN_ID = 3;
uint256 internal constant POSITIONS_AMOUNT = 4;
/// @dev Used to clean address types of dirty bits with `and(address, CLEAN_ADDRESS)`
uint256 internal constant CLEAN_ADDRESS = 0x00ffffffffffffffffffffffffffffffffffffffff;
/// @dev Used to clean everything but the first 8 bytes of an address
uint256 internal constant CLEAN_FIRST8_BYTES_ADDRESS = 0xffffffffffffffff << 96;
/// @dev Used to clean everything but the first 8 bytes of an address in the packed position
uint256 internal constant CLEAN_PACKED8_BYTES_ADDRESS = 0xffffffffffffffff << 160;
/**
* @notice Helper function that packs from, to, and contract_ address to into the two slot configuration
* @param from The address making the delegation
* @param to The address receiving the delegation
* @param contract_ The contract address associated with the delegation (optional)
* @return firstPacked The firstPacked storage configured with the parameters
* @return secondPacked The secondPacked storage configured with the parameters
* @dev Will not revert if `from`, `to`, and `contract_` are > uint160, any inputs with dirty bits outside the last 20 bytes will be cleaned
*/
function packAddresses(address from, address to, address contract_) internal pure returns (bytes32 firstPacked, bytes32 secondPacked) {
assembly {
firstPacked := or(shl(64, and(contract_, CLEAN_FIRST8_BYTES_ADDRESS)), and(from, CLEAN_ADDRESS))
secondPacked := or(shl(160, contract_), and(to, CLEAN_ADDRESS))
}
}
/**
* @notice Helper function that unpacks from, to, and contract_ address inside the firstPacked secondPacked storage configuration
* @param firstPacked The firstPacked storage to be decoded
* @param secondPacked The secondPacked storage to be decoded
* @return from The address making the delegation
* @return to The address receiving the delegation
* @return contract_ The contract address associated with the delegation
* @dev Will not revert if `from`, `to`, and `contract_` are > uint160, any inputs with dirty bits outside the last 20 bytes will be cleaned
*/
function unpackAddresses(bytes32 firstPacked, bytes32 secondPacked) internal pure returns (address from, address to, address contract_) {
assembly {
from := and(firstPacked, CLEAN_ADDRESS)
to := and(secondPacked, CLEAN_ADDRESS)
contract_ := or(shr(64, and(firstPacked, CLEAN_PACKED8_BYTES_ADDRESS)), shr(160, secondPacked))
}
}
/**
* @notice Helper function that can unpack the from or to address from their respective packed slots in the registry
* @param packedSlot The slot containing the from or to address
* @return unpacked The `from` or `to` address
* @dev Will not work if you want to obtain the contract address, use unpackAddresses
*/
function unpackAddress(bytes32 packedSlot) internal pure returns (address unpacked) {
assembly {
unpacked := and(packedSlot, CLEAN_ADDRESS)
}
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.21;
library RegistryOps {
/// @dev `x > y ? x : y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
// `gt(y, x)` will evaluate to 1 if `y > x`, else 0.
//
// If `y > x`:
// `x ^ ((x ^ y) * 1) = x ^ (x ^ y) = (x ^ x) ^ y = 0 ^ y = y`.
// otherwise:
// `x ^ ((x ^ y) * 0) = x ^ 0 = x`.
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev `x & y`.
function and(bool x, bool y) internal pure returns (bool z) {
assembly {
z := and(iszero(iszero(x)), iszero(iszero(y))) // Compiler cleans dirty booleans on the stack to 1, so do the same here
}
}
/// @dev `x | y`.
function or(bool x, bool y) internal pure returns (bool z) {
assembly {
z := or(iszero(iszero(x)), iszero(iszero(y))) // Compiler cleans dirty booleans on the stack to 1, so do the same here
}
}
}{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"murky/=lib/murky/src/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 9999999
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"MulticallFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bytes32","name":"rights","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"enable","type":"bool"}],"name":"DelegateAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"contract_","type":"address"},{"indexed":false,"internalType":"bytes32","name":"rights","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"enable","type":"bool"}],"name":"DelegateContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"contract_","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"rights","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DelegateERC1155","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"contract_","type":"address"},{"indexed":false,"internalType":"bytes32","name":"rights","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DelegateERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"contract_","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"rights","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"enable","type":"bool"}],"name":"DelegateERC721","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"rights","type":"bytes32"}],"name":"checkDelegateForAll","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"bytes32","name":"rights","type":"bytes32"}],"name":"checkDelegateForContract","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes32","name":"rights","type":"bytes32"}],"name":"checkDelegateForERC1155","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"bytes32","name":"rights","type":"bytes32"}],"name":"checkDelegateForERC20","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes32","name":"rights","type":"bytes32"}],"name":"checkDelegateForERC721","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes32","name":"rights","type":"bytes32"},{"internalType":"bool","name":"enable","type":"bool"}],"name":"delegateAll","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"bytes32","name":"rights","type":"bytes32"},{"internalType":"bool","name":"enable","type":"bool"}],"name":"delegateContract","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes32","name":"rights","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"delegateERC1155","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"bytes32","name":"rights","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"delegateERC20","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes32","name":"rights","type":"bytes32"},{"internalType":"bool","name":"enable","type":"bool"}],"name":"delegateERC721","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"hashes","type":"bytes32[]"}],"name":"getDelegationsFromHashes","outputs":[{"components":[{"internalType":"enum IDelegateRegistry.DelegationType","name":"type_","type":"uint8"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"rights","type":"bytes32"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IDelegateRegistry.Delegation[]","name":"delegations_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"getIncomingDelegationHashes","outputs":[{"internalType":"bytes32[]","name":"delegationHashes","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"getIncomingDelegations","outputs":[{"components":[{"internalType":"enum IDelegateRegistry.DelegationType","name":"type_","type":"uint8"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"rights","type":"bytes32"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IDelegateRegistry.Delegation[]","name":"delegations_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"getOutgoingDelegationHashes","outputs":[{"internalType":"bytes32[]","name":"delegationHashes","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"getOutgoingDelegations","outputs":[{"components":[{"internalType":"enum IDelegateRegistry.DelegationType","name":"type_","type":"uint8"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"rights","type":"bytes32"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IDelegateRegistry.Delegation[]","name":"delegations_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"location","type":"bytes32"}],"name":"readSlot","outputs":[{"internalType":"bytes32","name":"contents","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"locations","type":"bytes32[]"}],"name":"readSlots","outputs":[{"internalType":"bytes32[]","name":"contents","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5061273e806100206000396000f3fe60806040526004361061015e5760003560e01c80638988eea9116100c0578063b9f3687411610074578063d90e73ab11610059578063d90e73ab14610383578063e839bd5314610396578063e8e834a9146103b657600080fd5b8063b9f3687414610343578063ba63c8171461036357600080fd5b8063ac9650d8116100a5578063ac9650d8146102f0578063b18e2bbb14610310578063b87058751461032357600080fd5b80638988eea9146102bd578063ab764683146102dd57600080fd5b806335faa416116101175780634705ed38116100fc5780634705ed381461025d57806351525e9a1461027d57806361451a301461029d57600080fd5b806335faa4161461021957806342f87c251461023057600080fd5b806301ffc9a71161014857806301ffc9a7146101b6578063063182a5146101e657806330ff31401461020657600080fd5b80623c2ba61461016357806301a920a014610189575b600080fd5b6101766101713660046120b4565b6103d5565b6040519081526020015b60405180910390f35b34801561019557600080fd5b506101a96101a43660046120f6565b610637565b6040516101809190612118565b3480156101c257600080fd5b506101d66101d136600461215c565b61066e565b6040519015158152602001610180565b3480156101f257600080fd5b506101a96102013660046120f6565b6106e1565b6101766102143660046121ae565b610712565b34801561022557600080fd5b5061022e6108f9565b005b34801561023c57600080fd5b5061025061024b3660046120f6565b610917565b6040516101809190612219565b34801561026957600080fd5b50610250610278366004612368565b610948565b34801561028957600080fd5b506102506102983660046120f6565b610bf0565b3480156102a957600080fd5b506101a96102b8366004612368565b610c21565b3480156102c957600080fd5b506101d66102d83660046123aa565b610cc6565b6101766102eb3660046123f5565b610dd8565b6103036102fe366004612368565b611056565b6040516101809190612442565b61017661031e366004612510565b61118d565b34801561032f57600080fd5b5061017661033e366004612567565b6113bd565b34801561034f57600080fd5b506101d661035e366004612567565b6115d8565b34801561036f57600080fd5b5061017661037e3660046123aa565b611767565b6101766103913660046125bc565b61192d565b3480156103a257600080fd5b506101d66103b1366004612609565b611b3f565b3480156103c257600080fd5b506101766103d1366004612645565b5490565b60408051603c810185905260288101869052336014820152838152605c902060081b6004176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff1683156105865773ffffffffffffffffffffffffffffffffffffffff81166104ec57336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8c1680855260028352818520805480860182559086529290942090910187905589901b7bffffffffffffffff000000000000000000000000000000000000000016909217845560a088901b17908301556104d582600486910155565b84156104e7576104e782600287910155565b6105d4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff82160161055d5781547fffffffffffffffffffffffff000000000000000000000000000000000000000016331782556104e782600486910155565b3373ffffffffffffffffffffffffffffffffffffffff8216036104e7576104e782600486910155565b3373ffffffffffffffffffffffffffffffffffffffff8216036105d45781547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001178255600060048301555b604080518681526020810186905273ffffffffffffffffffffffffffffffffffffffff80891692908a169133917f6ebd000dfc4dc9df04f723f827bae7694230795e8f22ed4af438e074cc982d1891015b60405180910390a45050949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260016020526040902060609061066890611bc2565b92915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083169081147f5f68bc5a0000000000000000000000000000000000000000000000000000000090911417610668565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020526040902060609061066890611bc2565b60408051602881018590523360148201528381526048902060081b6001176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff1683156108555773ffffffffffffffffffffffffffffffffffffffff81166107eb57336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8b16808552600283529084208054808501825590855291909320018690559184559083015584156107e6576107e682600287910155565b61089c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff8216016107e65781547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317825561089c565b3373ffffffffffffffffffffffffffffffffffffffff82160361089c5781547fffffffffffffffffffffffff00000000000000000000000000000000000000001660011782555b60408051868152851515602082015273ffffffffffffffffffffffffffffffffffffffff88169133917fda3ef6410e30373a9137f83f9781a8129962b6882532b7c229de2e39de423227910160405180910390a350509392505050565b6000806000804770de1e80ea5a234fb5488fee2584251bc7e85af150565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020526040902060609061066890611d41565b60608167ffffffffffffffff8111156109635761096361265e565b6040519080825280602002602001820160405280156109e857816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816109815790505b50905060005b82811015610be9576000610a25858584818110610a0d57610a0d61268d565b90506020020135600090815260208190526040902090565b90506000610a47825473ffffffffffffffffffffffffffffffffffffffff1690565b9050610a528161200f565b15610ab6576040805160e08101909152806000815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0909101528451859085908110610aa657610aa661268d565b6020026020010181905250610bdf565b815460018301546040805160e08101825273ffffffffffffffffffffffffffffffffffffffff83169360a09390931c9290911c73ffffffffffffffff00000000000000000000000016919091179080610b278a8a89818110610b1a57610b1a61268d565b9050602002013560ff1690565b6005811115610b3857610b386121ea565b81526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001610b80866002015490565b81526020018273ffffffffffffffffffffffffffffffffffffffff168152602001610bac866003015490565b8152602001610bbc866004015490565b815250868681518110610bd157610bd161268d565b602002602001018190525050505b50506001016109ee565b5092915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260016020526040902060609061066890611d41565b6060818067ffffffffffffffff811115610c3d57610c3d61265e565b604051908082528060200260200182016040528015610c66578160200160208202803683370190505b50915060008060005b83811015610cbc57868682818110610c8957610c8961268d565b9050602002013592508254915081858281518110610ca957610ca961268d565b6020908102919091010152600101610c6f565b5050505092915050565b6000610cd18461200f565b610dcc576040805160288101879052601481018690526000808252604890912060081b6001178152602081905220610d0a905b85612035565b80610d4a575060408051603c810185905260288101879052601481018690526000808252605c90912060081b6002178152602081905220610d4a90610d04565b9050801515821517610dcc576040805160288101879052601481018690528381526048902060081b6001176000908152602081905220610d8990610d04565b80610dc9575060408051603c81018590526028810187905260148101869052838152605c902060081b6002176000908152602081905220610dc990610d04565b90505b80151560005260206000f35b60408051605c8101859052603c810186905260288101879052336014820152838152607c902060081b6005176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff168315610f9c5773ffffffffffffffffffffffffffffffffffffffff8116610f0257336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8d168085526002835281852080548086018255908652929094209091018790558a901b7bffffffffffffffff000000000000000000000000000000000000000016909217845560a089901b1790830155610edf82600388910155565b610eeb82600486910155565b8415610efd57610efd82600287910155565b610fea565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff821601610f735781547fffffffffffffffffffffffff00000000000000000000000000000000000000001633178255610efd82600486910155565b3373ffffffffffffffffffffffffffffffffffffffff821603610efd57610efd82600486910155565b3373ffffffffffffffffffffffffffffffffffffffff821603610fea5781547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001178255600060048301555b604080518781526020810187905290810185905273ffffffffffffffffffffffffffffffffffffffff80891691908a169033907f27ab1adc9bca76301ed7a691320766dfa4b4b1aa32c9e05cf789611be7f8c75f906060015b60405180910390a4505095945050505050565b60608167ffffffffffffffff8111156110715761107161265e565b6040519080825280602002602001820160405280156110a457816020015b606081526020019060019003908161108f5790505b5090506000805b8381101561118557308585838181106110c6576110c661268d565b90506020028101906110d891906126bc565b6040516110e6929190612721565b600060405180830381855af49150503d8060008114611121576040519150601f19603f3d011682016040523d82523d6000602084013e611126565b606091505b508483815181106111395761113961268d565b602090810291909101015291508161117d576040517f4d6a232800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001016110ab565b505092915050565b60408051605c8101859052603c810186905260288101879052336014820152838152607c902060081b6003176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff1683156113155773ffffffffffffffffffffffffffffffffffffffff81166112ab57336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8d168085526002835281852080548086018255908652929094209091018790558a901b7bffffffffffffffff000000000000000000000000000000000000000016909217845560a089901b179083015561129482600388910155565b84156112a6576112a682600287910155565b61135c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff8216016112a65781547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317825561135c565b3373ffffffffffffffffffffffffffffffffffffffff82160361135c5781547fffffffffffffffffffffffff00000000000000000000000000000000000000001660011782555b60408051878152602081018790528515159181019190915273ffffffffffffffffffffffffffffffffffffffff80891691908a169033907f15e7a1bdcd507dd632d797d38e60cc5a9c0749b9a63097a215c4d006126825c690606001611043565b60006113c88561200f565b6115ce576040805160288101889052601481018790526000808252604890912060081b6001178152602081905220611401905b86612035565b80611441575060408051603c810186905260288101889052601481018790526000808252605c90912060081b6002178152602081905220611441906113fb565b61148e5760408051605c8101859052603c810186905260288101889052601481018790526000808252607c90912060081b6005178152602081905220611489905b6004015490565b6114b0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81148215176115ce576040805160288101889052601481018790528381526048902060081b60011760009081526020819052908120611513905b87612035565b80611553575060408051603c81018790526028810189905260148101889052848152605c902060081b60021760009081526020819052206115539061150d565b61159d5760408051605c8101869052603c81018790526028810189905260148101889052848152607c902060081b600517600090815260208190522061159890611482565b6115bf565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b90508181108282180281189150505b8060005260206000f35b60006115e38561200f565b610dcc576040805160288101889052601481018790526000808252604890912060081b600117815260208190522061161a906113fb565b8061165a575060408051603c810186905260288101889052601481018790526000808252605c90912060081b600217815260208190522061165a906113fb565b806116a1575060408051605c8101859052603c810186905260288101889052601481018790526000808252607c90912060081b60031781526020819052206116a1906113fb565b9050801515821517610dcc576040805160288101889052601481018790528381526048902060081b60011760009081526020819052206116e0906113fb565b80611720575060408051603c81018690526028810188905260148101879052838152605c902060081b6002176000908152602081905220611720906113fb565b80610dc9575060408051605c8101859052603c81018690526028810188905260148101879052838152607c902060081b6003176000908152602081905220610dc9906113fb565b60006117728461200f565b6115ce576040805160288101879052601481018690526000808252604890912060081b60011781526020819052206117a990610d04565b806117e9575060408051603c810185905260288101879052601481018690526000808252605c90912060081b60021781526020819052206117e990610d04565b61182c5760408051603c810185905260288101879052601481018690526000808252605c90912060081b600417815260208190522061182790611482565b61184e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81148215176115ce576040805160288101879052601481018690528381526048902060081b600117600090815260208190529081206118af906113fb565b806118ef575060408051603c81018690526028810188905260148101879052848152605c902060081b60021760009081526020819052206118ef906113fb565b61159d5760408051603c81018690526028810188905260148101879052848152605c902060081b600417600090815260208190522061159890611482565b60408051603c810185905260288101869052336014820152838152605c902060081b6002176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff168315611aa25773ffffffffffffffffffffffffffffffffffffffff8116611a3857336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8c1680855260028352818520805480860182559086529290942090910187905589901b7bffffffffffffffff000000000000000000000000000000000000000016909217845560a088901b17908301558415611a3357611a3382600287910155565b611ae9565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff821601611a335781547fffffffffffffffffffffffff00000000000000000000000000000000000000001633178255611ae9565b3373ffffffffffffffffffffffffffffffffffffffff821603611ae95781547fffffffffffffffffffffffff00000000000000000000000000000000000000001660011782555b60408051868152851515602082015273ffffffffffffffffffffffffffffffffffffffff80891692908a169133917f021be15e24de4afc43cfb5d0ba95ca38e0783571e05c12bbe6aece8842ae82df9101610625565b6000611b4a8361200f565b610dcc576040805160288101869052601481018590526000808252604890912060081b6001178152602081905220611b83905b84612035565b9050801515821517610dcc576040805160288101869052601481018590528381526048902060081b6001176000908152602081905220610dc990611b7d565b805460609060009081808267ffffffffffffffff811115611be557611be561265e565b604051908082528060200260200182016040528015611c0e578160200160208202803683370190505b50905060005b83811015611ca757868181548110611c2e57611c2e61268d565b90600052602060002001549250611c75611c70611c5685600090815260208190526040902090565b5473ffffffffffffffffffffffffffffffffffffffff1690565b61200f565b611c9f5782828680600101975081518110611c9257611c9261268d565b6020026020010181815250505b600101611c14565b508367ffffffffffffffff811115611cc157611cc161265e565b604051908082528060200260200182016040528015611cea578160200160208202803683370190505b50945060005b84811015611d3757818181518110611d0a57611d0a61268d565b6020026020010151868281518110611d2457611d2461268d565b6020908102919091010152600101611cf0565b5050505050919050565b805460609060009081808267ffffffffffffffff811115611d6457611d6461265e565b604051908082528060200260200182016040528015611d8d578160200160208202803683370190505b50905060005b83811015611e0757868181548110611dad57611dad61268d565b90600052602060002001549250611dd5611c70611c5685600090815260208190526040902090565b611dff5782828680600101975081518110611df257611df261268d565b6020026020010181815250505b600101611d93565b508367ffffffffffffffff811115611e2157611e2161265e565b604051908082528060200260200182016040528015611ea657816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181611e3f5790505b5094506000805b8581101561200457828181518110611ec757611ec761268d565b60200260200101519350611ee684600090815260208190526040902090565b805460018201546040805160e08101825293955073ffffffffffffffffffffffffffffffffffffffff808416949083169360a09390931c9290911c73ffffffffffffffff0000000000000000000000001691909117908060ff89166005811115611f5257611f526121ea565b81526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001611f9a876002015490565b81526020018273ffffffffffffffffffffffffffffffffffffffff168152602001611fc6876003015490565b8152602001611fd6876004015490565b8152508a8581518110611feb57611feb61268d565b6020026020010181905250505050806001019050611ead565b505050505050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff8316908114901517610668565b6000612055835473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614905092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146120af57600080fd5b919050565b600080600080608085870312156120ca57600080fd5b6120d38561208b565b93506120e16020860161208b565b93969395505050506040820135916060013590565b60006020828403121561210857600080fd5b6121118261208b565b9392505050565b6020808252825182820181905260009190848201906040850190845b8181101561215057835183529284019291840191600101612134565b50909695505050505050565b60006020828403121561216e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461211157600080fd5b803580151581146120af57600080fd5b6000806000606084860312156121c357600080fd5b6121cc8461208b565b9250602084013591506121e16040850161219e565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208082528251828201819052600091906040908185019086840185805b8381101561230e578251805160068110612278577f4e487b710000000000000000000000000000000000000000000000000000000084526021600452602484fd5b86528088015173ffffffffffffffffffffffffffffffffffffffff1688870152868101516122bd8888018273ffffffffffffffffffffffffffffffffffffffff169052565b506060818101519087015260808082015173ffffffffffffffffffffffffffffffffffffffff169087015260a0808201519087015260c0908101519086015260e09094019391860191600101612237565b509298975050505050505050565b60008083601f84011261232e57600080fd5b50813567ffffffffffffffff81111561234657600080fd5b6020830191508360208260051b850101111561236157600080fd5b9250929050565b6000806020838503121561237b57600080fd5b823567ffffffffffffffff81111561239257600080fd5b61239e8582860161231c565b90969095509350505050565b600080600080608085870312156123c057600080fd5b6123c98561208b565b93506123d76020860161208b565b92506123e56040860161208b565b9396929550929360600135925050565b600080600080600060a0868803121561240d57600080fd5b6124168661208b565b94506124246020870161208b565b94979496505050506040830135926060810135926080909101359150565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b83811015612502577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc089870301855282518051808852835b818110156124bd578281018a01518982018b015289016124a2565b508781018901849052601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690960187019550938601939186019160010161246a565b509398975050505050505050565b600080600080600060a0868803121561252857600080fd5b6125318661208b565b945061253f6020870161208b565b9350604086013592506060860135915061255b6080870161219e565b90509295509295909350565b600080600080600060a0868803121561257f57600080fd5b6125888661208b565b94506125966020870161208b565b93506125a46040870161208b565b94979396509394606081013594506080013592915050565b600080600080608085870312156125d257600080fd5b6125db8561208b565b93506125e96020860161208b565b9250604085013591506125fe6060860161219e565b905092959194509250565b60008060006060848603121561261e57600080fd5b6126278461208b565b92506126356020850161208b565b9150604084013590509250925092565b60006020828403121561265757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126126f157600080fd5b83018035915067ffffffffffffffff82111561270c57600080fd5b60200191503681900382131561236157600080fd5b818382376000910190815291905056fea164736f6c6343000815000a
Deployed Bytecode
0x60806040526004361061015e5760003560e01c80638988eea9116100c0578063b9f3687411610074578063d90e73ab11610059578063d90e73ab14610383578063e839bd5314610396578063e8e834a9146103b657600080fd5b8063b9f3687414610343578063ba63c8171461036357600080fd5b8063ac9650d8116100a5578063ac9650d8146102f0578063b18e2bbb14610310578063b87058751461032357600080fd5b80638988eea9146102bd578063ab764683146102dd57600080fd5b806335faa416116101175780634705ed38116100fc5780634705ed381461025d57806351525e9a1461027d57806361451a301461029d57600080fd5b806335faa4161461021957806342f87c251461023057600080fd5b806301ffc9a71161014857806301ffc9a7146101b6578063063182a5146101e657806330ff31401461020657600080fd5b80623c2ba61461016357806301a920a014610189575b600080fd5b6101766101713660046120b4565b6103d5565b6040519081526020015b60405180910390f35b34801561019557600080fd5b506101a96101a43660046120f6565b610637565b6040516101809190612118565b3480156101c257600080fd5b506101d66101d136600461215c565b61066e565b6040519015158152602001610180565b3480156101f257600080fd5b506101a96102013660046120f6565b6106e1565b6101766102143660046121ae565b610712565b34801561022557600080fd5b5061022e6108f9565b005b34801561023c57600080fd5b5061025061024b3660046120f6565b610917565b6040516101809190612219565b34801561026957600080fd5b50610250610278366004612368565b610948565b34801561028957600080fd5b506102506102983660046120f6565b610bf0565b3480156102a957600080fd5b506101a96102b8366004612368565b610c21565b3480156102c957600080fd5b506101d66102d83660046123aa565b610cc6565b6101766102eb3660046123f5565b610dd8565b6103036102fe366004612368565b611056565b6040516101809190612442565b61017661031e366004612510565b61118d565b34801561032f57600080fd5b5061017661033e366004612567565b6113bd565b34801561034f57600080fd5b506101d661035e366004612567565b6115d8565b34801561036f57600080fd5b5061017661037e3660046123aa565b611767565b6101766103913660046125bc565b61192d565b3480156103a257600080fd5b506101d66103b1366004612609565b611b3f565b3480156103c257600080fd5b506101766103d1366004612645565b5490565b60408051603c810185905260288101869052336014820152838152605c902060081b6004176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff1683156105865773ffffffffffffffffffffffffffffffffffffffff81166104ec57336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8c1680855260028352818520805480860182559086529290942090910187905589901b7bffffffffffffffff000000000000000000000000000000000000000016909217845560a088901b17908301556104d582600486910155565b84156104e7576104e782600287910155565b6105d4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff82160161055d5781547fffffffffffffffffffffffff000000000000000000000000000000000000000016331782556104e782600486910155565b3373ffffffffffffffffffffffffffffffffffffffff8216036104e7576104e782600486910155565b3373ffffffffffffffffffffffffffffffffffffffff8216036105d45781547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001178255600060048301555b604080518681526020810186905273ffffffffffffffffffffffffffffffffffffffff80891692908a169133917f6ebd000dfc4dc9df04f723f827bae7694230795e8f22ed4af438e074cc982d1891015b60405180910390a45050949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260016020526040902060609061066890611bc2565b92915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083169081147f5f68bc5a0000000000000000000000000000000000000000000000000000000090911417610668565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020526040902060609061066890611bc2565b60408051602881018590523360148201528381526048902060081b6001176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff1683156108555773ffffffffffffffffffffffffffffffffffffffff81166107eb57336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8b16808552600283529084208054808501825590855291909320018690559184559083015584156107e6576107e682600287910155565b61089c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff8216016107e65781547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317825561089c565b3373ffffffffffffffffffffffffffffffffffffffff82160361089c5781547fffffffffffffffffffffffff00000000000000000000000000000000000000001660011782555b60408051868152851515602082015273ffffffffffffffffffffffffffffffffffffffff88169133917fda3ef6410e30373a9137f83f9781a8129962b6882532b7c229de2e39de423227910160405180910390a350509392505050565b6000806000804770de1e80ea5a234fb5488fee2584251bc7e85af150565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020526040902060609061066890611d41565b60608167ffffffffffffffff8111156109635761096361265e565b6040519080825280602002602001820160405280156109e857816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816109815790505b50905060005b82811015610be9576000610a25858584818110610a0d57610a0d61268d565b90506020020135600090815260208190526040902090565b90506000610a47825473ffffffffffffffffffffffffffffffffffffffff1690565b9050610a528161200f565b15610ab6576040805160e08101909152806000815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0909101528451859085908110610aa657610aa661268d565b6020026020010181905250610bdf565b815460018301546040805160e08101825273ffffffffffffffffffffffffffffffffffffffff83169360a09390931c9290911c73ffffffffffffffff00000000000000000000000016919091179080610b278a8a89818110610b1a57610b1a61268d565b9050602002013560ff1690565b6005811115610b3857610b386121ea565b81526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001610b80866002015490565b81526020018273ffffffffffffffffffffffffffffffffffffffff168152602001610bac866003015490565b8152602001610bbc866004015490565b815250868681518110610bd157610bd161268d565b602002602001018190525050505b50506001016109ee565b5092915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260016020526040902060609061066890611d41565b6060818067ffffffffffffffff811115610c3d57610c3d61265e565b604051908082528060200260200182016040528015610c66578160200160208202803683370190505b50915060008060005b83811015610cbc57868682818110610c8957610c8961268d565b9050602002013592508254915081858281518110610ca957610ca961268d565b6020908102919091010152600101610c6f565b5050505092915050565b6000610cd18461200f565b610dcc576040805160288101879052601481018690526000808252604890912060081b6001178152602081905220610d0a905b85612035565b80610d4a575060408051603c810185905260288101879052601481018690526000808252605c90912060081b6002178152602081905220610d4a90610d04565b9050801515821517610dcc576040805160288101879052601481018690528381526048902060081b6001176000908152602081905220610d8990610d04565b80610dc9575060408051603c81018590526028810187905260148101869052838152605c902060081b6002176000908152602081905220610dc990610d04565b90505b80151560005260206000f35b60408051605c8101859052603c810186905260288101879052336014820152838152607c902060081b6005176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff168315610f9c5773ffffffffffffffffffffffffffffffffffffffff8116610f0257336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8d168085526002835281852080548086018255908652929094209091018790558a901b7bffffffffffffffff000000000000000000000000000000000000000016909217845560a089901b1790830155610edf82600388910155565b610eeb82600486910155565b8415610efd57610efd82600287910155565b610fea565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff821601610f735781547fffffffffffffffffffffffff00000000000000000000000000000000000000001633178255610efd82600486910155565b3373ffffffffffffffffffffffffffffffffffffffff821603610efd57610efd82600486910155565b3373ffffffffffffffffffffffffffffffffffffffff821603610fea5781547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001178255600060048301555b604080518781526020810187905290810185905273ffffffffffffffffffffffffffffffffffffffff80891691908a169033907f27ab1adc9bca76301ed7a691320766dfa4b4b1aa32c9e05cf789611be7f8c75f906060015b60405180910390a4505095945050505050565b60608167ffffffffffffffff8111156110715761107161265e565b6040519080825280602002602001820160405280156110a457816020015b606081526020019060019003908161108f5790505b5090506000805b8381101561118557308585838181106110c6576110c661268d565b90506020028101906110d891906126bc565b6040516110e6929190612721565b600060405180830381855af49150503d8060008114611121576040519150601f19603f3d011682016040523d82523d6000602084013e611126565b606091505b508483815181106111395761113961268d565b602090810291909101015291508161117d576040517f4d6a232800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001016110ab565b505092915050565b60408051605c8101859052603c810186905260288101879052336014820152838152607c902060081b6003176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff1683156113155773ffffffffffffffffffffffffffffffffffffffff81166112ab57336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8d168085526002835281852080548086018255908652929094209091018790558a901b7bffffffffffffffff000000000000000000000000000000000000000016909217845560a089901b179083015561129482600388910155565b84156112a6576112a682600287910155565b61135c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff8216016112a65781547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317825561135c565b3373ffffffffffffffffffffffffffffffffffffffff82160361135c5781547fffffffffffffffffffffffff00000000000000000000000000000000000000001660011782555b60408051878152602081018790528515159181019190915273ffffffffffffffffffffffffffffffffffffffff80891691908a169033907f15e7a1bdcd507dd632d797d38e60cc5a9c0749b9a63097a215c4d006126825c690606001611043565b60006113c88561200f565b6115ce576040805160288101889052601481018790526000808252604890912060081b6001178152602081905220611401905b86612035565b80611441575060408051603c810186905260288101889052601481018790526000808252605c90912060081b6002178152602081905220611441906113fb565b61148e5760408051605c8101859052603c810186905260288101889052601481018790526000808252607c90912060081b6005178152602081905220611489905b6004015490565b6114b0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81148215176115ce576040805160288101889052601481018790528381526048902060081b60011760009081526020819052908120611513905b87612035565b80611553575060408051603c81018790526028810189905260148101889052848152605c902060081b60021760009081526020819052206115539061150d565b61159d5760408051605c8101869052603c81018790526028810189905260148101889052848152607c902060081b600517600090815260208190522061159890611482565b6115bf565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b90508181108282180281189150505b8060005260206000f35b60006115e38561200f565b610dcc576040805160288101889052601481018790526000808252604890912060081b600117815260208190522061161a906113fb565b8061165a575060408051603c810186905260288101889052601481018790526000808252605c90912060081b600217815260208190522061165a906113fb565b806116a1575060408051605c8101859052603c810186905260288101889052601481018790526000808252607c90912060081b60031781526020819052206116a1906113fb565b9050801515821517610dcc576040805160288101889052601481018790528381526048902060081b60011760009081526020819052206116e0906113fb565b80611720575060408051603c81018690526028810188905260148101879052838152605c902060081b6002176000908152602081905220611720906113fb565b80610dc9575060408051605c8101859052603c81018690526028810188905260148101879052838152607c902060081b6003176000908152602081905220610dc9906113fb565b60006117728461200f565b6115ce576040805160288101879052601481018690526000808252604890912060081b60011781526020819052206117a990610d04565b806117e9575060408051603c810185905260288101879052601481018690526000808252605c90912060081b60021781526020819052206117e990610d04565b61182c5760408051603c810185905260288101879052601481018690526000808252605c90912060081b600417815260208190522061182790611482565b61184e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81148215176115ce576040805160288101879052601481018690528381526048902060081b600117600090815260208190529081206118af906113fb565b806118ef575060408051603c81018690526028810188905260148101879052848152605c902060081b60021760009081526020819052206118ef906113fb565b61159d5760408051603c81018690526028810188905260148101879052848152605c902060081b600417600090815260208190522061159890611482565b60408051603c810185905260288101869052336014820152838152605c902060081b6002176000818152602081905291909120805473ffffffffffffffffffffffffffffffffffffffff168315611aa25773ffffffffffffffffffffffffffffffffffffffff8116611a3857336000818152600160208181526040808420805480850182559085528285200188905573ffffffffffffffffffffffffffffffffffffffff8c1680855260028352818520805480860182559086529290942090910187905589901b7bffffffffffffffff000000000000000000000000000000000000000016909217845560a088901b17908301558415611a3357611a3382600287910155565b611ae9565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff821601611a335781547fffffffffffffffffffffffff00000000000000000000000000000000000000001633178255611ae9565b3373ffffffffffffffffffffffffffffffffffffffff821603611ae95781547fffffffffffffffffffffffff00000000000000000000000000000000000000001660011782555b60408051868152851515602082015273ffffffffffffffffffffffffffffffffffffffff80891692908a169133917f021be15e24de4afc43cfb5d0ba95ca38e0783571e05c12bbe6aece8842ae82df9101610625565b6000611b4a8361200f565b610dcc576040805160288101869052601481018590526000808252604890912060081b6001178152602081905220611b83905b84612035565b9050801515821517610dcc576040805160288101869052601481018590528381526048902060081b6001176000908152602081905220610dc990611b7d565b805460609060009081808267ffffffffffffffff811115611be557611be561265e565b604051908082528060200260200182016040528015611c0e578160200160208202803683370190505b50905060005b83811015611ca757868181548110611c2e57611c2e61268d565b90600052602060002001549250611c75611c70611c5685600090815260208190526040902090565b5473ffffffffffffffffffffffffffffffffffffffff1690565b61200f565b611c9f5782828680600101975081518110611c9257611c9261268d565b6020026020010181815250505b600101611c14565b508367ffffffffffffffff811115611cc157611cc161265e565b604051908082528060200260200182016040528015611cea578160200160208202803683370190505b50945060005b84811015611d3757818181518110611d0a57611d0a61268d565b6020026020010151868281518110611d2457611d2461268d565b6020908102919091010152600101611cf0565b5050505050919050565b805460609060009081808267ffffffffffffffff811115611d6457611d6461265e565b604051908082528060200260200182016040528015611d8d578160200160208202803683370190505b50905060005b83811015611e0757868181548110611dad57611dad61268d565b90600052602060002001549250611dd5611c70611c5685600090815260208190526040902090565b611dff5782828680600101975081518110611df257611df261268d565b6020026020010181815250505b600101611d93565b508367ffffffffffffffff811115611e2157611e2161265e565b604051908082528060200260200182016040528015611ea657816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181611e3f5790505b5094506000805b8581101561200457828181518110611ec757611ec761268d565b60200260200101519350611ee684600090815260208190526040902090565b805460018201546040805160e08101825293955073ffffffffffffffffffffffffffffffffffffffff808416949083169360a09390931c9290911c73ffffffffffffffff0000000000000000000000001691909117908060ff89166005811115611f5257611f526121ea565b81526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152602001611f9a876002015490565b81526020018273ffffffffffffffffffffffffffffffffffffffff168152602001611fc6876003015490565b8152602001611fd6876004015490565b8152508a8581518110611feb57611feb61268d565b6020026020010181905250505050806001019050611ead565b505050505050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff8316908114901517610668565b6000612055835473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614905092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146120af57600080fd5b919050565b600080600080608085870312156120ca57600080fd5b6120d38561208b565b93506120e16020860161208b565b93969395505050506040820135916060013590565b60006020828403121561210857600080fd5b6121118261208b565b9392505050565b6020808252825182820181905260009190848201906040850190845b8181101561215057835183529284019291840191600101612134565b50909695505050505050565b60006020828403121561216e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461211157600080fd5b803580151581146120af57600080fd5b6000806000606084860312156121c357600080fd5b6121cc8461208b565b9250602084013591506121e16040850161219e565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208082528251828201819052600091906040908185019086840185805b8381101561230e578251805160068110612278577f4e487b710000000000000000000000000000000000000000000000000000000084526021600452602484fd5b86528088015173ffffffffffffffffffffffffffffffffffffffff1688870152868101516122bd8888018273ffffffffffffffffffffffffffffffffffffffff169052565b506060818101519087015260808082015173ffffffffffffffffffffffffffffffffffffffff169087015260a0808201519087015260c0908101519086015260e09094019391860191600101612237565b509298975050505050505050565b60008083601f84011261232e57600080fd5b50813567ffffffffffffffff81111561234657600080fd5b6020830191508360208260051b850101111561236157600080fd5b9250929050565b6000806020838503121561237b57600080fd5b823567ffffffffffffffff81111561239257600080fd5b61239e8582860161231c565b90969095509350505050565b600080600080608085870312156123c057600080fd5b6123c98561208b565b93506123d76020860161208b565b92506123e56040860161208b565b9396929550929360600135925050565b600080600080600060a0868803121561240d57600080fd5b6124168661208b565b94506124246020870161208b565b94979496505050506040830135926060810135926080909101359150565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b83811015612502577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc089870301855282518051808852835b818110156124bd578281018a01518982018b015289016124a2565b508781018901849052601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690960187019550938601939186019160010161246a565b509398975050505050505050565b600080600080600060a0868803121561252857600080fd5b6125318661208b565b945061253f6020870161208b565b9350604086013592506060860135915061255b6080870161219e565b90509295509295909350565b600080600080600060a0868803121561257f57600080fd5b6125888661208b565b94506125966020870161208b565b93506125a46040870161208b565b94979396509394606081013594506080013592915050565b600080600080608085870312156125d257600080fd5b6125db8561208b565b93506125e96020860161208b565b9250604085013591506125fe6060860161219e565b905092959194509250565b60008060006060848603121561261e57600080fd5b6126278461208b565b92506126356020850161208b565b9150604084013590509250925092565b60006020828403121561265757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126126f157600080fd5b83018035915067ffffffffffffffff82111561270c57600080fd5b60200191503681900382131561236157600080fd5b818382376000910190815291905056fea164736f6c6343000815000a
Loading...
Loading
Loading...
Loading
Net Worth in USD
$1,013.16
Net Worth in ETH
0.514358
Token Allocations
ETH
60.39%
BNB
39.07%
POL
0.45%
Others
0.10%
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 57.35% | $1,969.75 | 0.295 | $581.08 | |
| BSC | 39.07% | $621.99 | 0.6363 | $395.79 | |
| LINEA | 1.61% | $1,967.62 | 0.00831 | $16.35 | |
| BASE | 1.22% | $1,969.51 | 0.0063 | $12.41 | |
| BASE | 0.02% | $0.000591 | 357.9 | $0.2115 | |
| POL | 0.45% | $0.107394 | 42 | $4.51 | |
| OP | 0.11% | $1,968.78 | 0.00058 | $1.14 | |
| SCROLL | 0.08% | $1,967.62 | 0.00041 | $0.806725 | |
| AVAX | 0.06% | $9.11 | 0.0717 | $0.653394 | |
| APE | 0.01% | $0.102477 | 1.1103 | $0.113782 | |
| TAIKO | <0.01% | $1,967.62 | 0.00002 | $0.039352 | |
| BLAST | <0.01% | $1,967.54 | 0.00002 | $0.039351 | |
| MANTLE | <0.01% | $0.641244 | 0.015 | $0.009612 | |
| GNO | <0.01% | $0.999986 | 0.00323 | $0.00323 | |
| CELO | <0.01% | $0.077473 | 0.00511 | $0.000396 | |
| MOVR | <0.01% | $1.22 | 0.00012 | $0.000147 | |
| GLMR | <0.01% | $0.012118 | 0.00691 | $0.000084 | |
| BERA | <0.01% | $0.602739 | 0.00003 | $0.000018 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.