Transaction Hash:
Block:
19182637 at Feb-08-2024 09:45:11 AM +UTC
Transaction Fee:
0.013505844607006752 ETH
$33.89
Gas Used:
261,023 Gas / 51.741971424 Gwei
Emitted Events:
160 |
DelegationManagementContract.RegisterDelegation( from=[Sender] 0xf04f266d51563c2043ed8f51744572793c4d5793, collectionAddress=0x88888888...888888888, delegationAddress=0xf5012357...81F9e0EdD, useCase=1, allTokens=True, _tokenId=0 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x2202CB9c...2e709f43d | |||||
0x388C818C...7ccB19297
Miner
| (Lido: Execution Layer Rewards Vault) | 299.367051413701009093 Eth | 299.367054778387972948 Eth | 0.000003364686963855 | |
0xF04f266d...93c4d5793 |
0.22 Eth
Nonce: 0
|
0.206494155392993248 Eth
Nonce: 1
| 0.013505844607006752 |
Execution Trace
DelegationManagementContract.registerDelegationAddress( _collectionAddress=0x8888888888888888888888888888888888888888, _delegationAddress=0xf50123573C02ABb33Aa100D0AC1A49481F9e0EdD, _expiryDate=64060588800, _useCase=1, _allTokens=True, _tokenId=0 )
registerDelegationAddress[DelegationManagementContract (ln:75)]
push[DelegationManagementContract (ln:96)]
push[DelegationManagementContract (ln:98)]
GlobalData[DelegationManagementContract (ln:101)]
push[DelegationManagementContract (ln:102)]
GlobalData[DelegationManagementContract (ln:104)]
push[DelegationManagementContract (ln:105)]
RegisterDelegation[DelegationManagementContract (ln:107)]
// SPDX-License-Identifier: MIT // _ ______________ // / | / / ____/_ __/ // / |/ / /_ / / // / /| / __/ / / // /_/ |_/_/ ____/_/_ _______________ ______________ _ __ // / __ \/ ____/ / / ____/ ____/ |/_ __/ _/ __ \/ | / / // / / / / __/ / / / __/ / / __/ /| | / / / // / / / |/ / // / /_/ / /___/ /___/ /___/ /_/ / ___ |/ / _/ // /_/ / /| / // /_____/_____/_____/_____/\____/_/ |_/_/ /___/\____/_/ |_/ /** * * @title: NFTDelegation.com Management Contract * @date: 20-Apr-2023 - 16:27 * @version: 5.20.15 * @notes: An advanced open-source trustless delegation and consolidation management contract. * @author: 6529 team * @contributors: https://github.com/6529-Collections/nftdelegation/graphs/contributors * */ pragma solidity ^0.8.18; contract DelegationManagementContract { // Constant declarations address constant ALL_COLLECTIONS = 0x8888888888888888888888888888888888888888; uint256 constant USE_CASE_SUB_DELEGATION = 998; uint256 constant USE_CASE_CONSOLIDATION = 999; // Variable declarations uint256 public useCaseCounter; // Mapping declarations mapping(bytes32 => address[]) public delegatorHashes; mapping(bytes32 => address[]) public delegationAddressHashes; struct GlobalData { address delegatorAddress; address delegationAddress; uint256 registeredDate; uint256 expiryDate; bool allTokens; uint256 tokens; } // Mapping of GlobalData struct declaration mapping(bytes32 => GlobalData[]) public globalDelegationHashes; // Events declaration event RegisterDelegation(address indexed from, address indexed collectionAddress, address indexed delegationAddress, uint256 useCase, bool allTokens, uint256 _tokenId); event RegisterDelegationUsingSubDelegation(address indexed delegator, address from, address indexed collectionAddress, address indexed delegationAddress, uint256 useCase, bool allTokens, uint256 _tokenId); event RevokeDelegation(address indexed from, address indexed collectionAddress, address indexed delegationAddress, uint256 useCase); event RevokeDelegationUsingSubDelegation(address indexed delegator, address from, address indexed collectionAddress, address indexed delegationAddress, uint256 useCase); event UpdateDelegation(address indexed from, address indexed collectionAddress, address olddelegationAddress, address indexed newdelegationAddress, uint256 useCase, bool allTokens, uint256 _tokenId); // Locks declarations mapping(address => bool) public globalLock; mapping(bytes32 => bool) public collectionLock; mapping(bytes32 => bool) public collectionUsecaseLock; // Constructor constructor() { useCaseCounter = 999; } /** * @notice Delegator assigns a delegation address for a specific use case on a specific NFT collection for a certain duration * @notice _collectionAddress --> ALL_COLLECTIONS = Applies to all collections * @notice For all Tokens-- > _allTokens needs to be true, _tokenId does not matter */ function registerDelegationAddress(address _collectionAddress, address _delegationAddress, uint256 _expiryDate, uint256 _useCase, bool _allTokens, uint256 _tokenId) public { require((_useCase > 0 && _useCase <= useCaseCounter)); bytes32 delegatorHash; bytes32 delegationAddressHash; bytes32 globalHash; bytes32 collectionLockHash; bytes32 collectionUsecaseLockHash; bytes32 collectionUsecaseLockHashAll; // Locks collectionLockHash = keccak256(abi.encodePacked(_collectionAddress, _delegationAddress)); collectionUsecaseLockHash = keccak256(abi.encodePacked(_collectionAddress, _delegationAddress, _useCase)); collectionUsecaseLockHashAll = keccak256(abi.encodePacked(ALL_COLLECTIONS, _delegationAddress, _useCase)); require(globalLock[_delegationAddress] == false); require(collectionLock[collectionLockHash] == false); require(collectionUsecaseLock[collectionUsecaseLockHash] == false); require(collectionUsecaseLock[collectionUsecaseLockHashAll] == false); // Push data to mappings globalHash = keccak256(abi.encodePacked(msg.sender, _collectionAddress, _delegationAddress, _useCase)); delegatorHash = keccak256(abi.encodePacked(msg.sender, _collectionAddress, _useCase)); // Stores delegation addresses on a delegator hash delegationAddressHash = keccak256(abi.encodePacked(_delegationAddress, _collectionAddress, _useCase)); delegatorHashes[delegatorHash].push(_delegationAddress); // Stores delegators addresses on a delegation address hash delegationAddressHashes[delegationAddressHash].push(msg.sender); // Push additional data to the globalDelegationHashes mapping if (_allTokens == true) { GlobalData memory newdelegationGlobalData = GlobalData(msg.sender, _delegationAddress, block.timestamp, _expiryDate, true, 0); globalDelegationHashes[globalHash].push(newdelegationGlobalData); } else { GlobalData memory newdelegationGlobalData = GlobalData(msg.sender, _delegationAddress, block.timestamp, _expiryDate, false, _tokenId); globalDelegationHashes[globalHash].push(newdelegationGlobalData); } emit RegisterDelegation(msg.sender, _collectionAddress, _delegationAddress, _useCase, _allTokens, _tokenId); } /** * @notice Function to support subDelegation rights * @notice A delegation Address that has subDelegation rights given by a Delegator can register Delegations on behalf of Delegator */ function registerDelegationAddressUsingSubDelegation(address _delegatorAddress, address _collectionAddress, address _delegationAddress, uint256 _expiryDate, uint256 _useCase, bool _allTokens, uint256 _tokenId) public { // Check subdelegation rights for the specific collection { bool subdelegationRightsCol; address[] memory allDelegators = retrieveDelegators(msg.sender, _collectionAddress, USE_CASE_SUB_DELEGATION); if (allDelegators.length > 0) { for (uint i = 0; i < allDelegators.length; ) { if (_delegatorAddress == allDelegators[i]) { subdelegationRightsCol = true; break; } unchecked { ++i; } } } // Check subdelegation rights for All collections allDelegators = retrieveDelegators(msg.sender, ALL_COLLECTIONS, USE_CASE_SUB_DELEGATION); if (allDelegators.length > 0) { if (subdelegationRightsCol != true) { for (uint i = 0; i < allDelegators.length; ) { if (_delegatorAddress == allDelegators[i]) { subdelegationRightsCol = true; break; } unchecked { ++i; } } } } // Allow to register require((subdelegationRightsCol == true)); } // If check passed then register delegation address for Delegator require((_useCase > 0 && _useCase <= useCaseCounter)); bytes32 delegatorHash; bytes32 delegationAddressHash; bytes32 globalHash; bytes32 collectionLockHash; bytes32 collectionUsecaseLockHash; bytes32 collectionUsecaseLockHashAll; // Locks collectionLockHash = keccak256(abi.encodePacked(_collectionAddress, _delegationAddress)); collectionUsecaseLockHash = keccak256(abi.encodePacked(_collectionAddress, _delegationAddress, _useCase)); collectionUsecaseLockHashAll = keccak256(abi.encodePacked(ALL_COLLECTIONS, _delegationAddress, _useCase)); require(globalLock[_delegationAddress] == false); require(collectionLock[collectionLockHash] == false); require(collectionUsecaseLock[collectionUsecaseLockHash] == false); require(collectionUsecaseLock[collectionUsecaseLockHashAll] == false); // Push data to mappings globalHash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, _delegationAddress, _useCase)); delegatorHash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, _useCase)); // Stores delegation addresses on a delegator hash delegationAddressHash = keccak256(abi.encodePacked(_delegationAddress, _collectionAddress, _useCase)); delegatorHashes[delegatorHash].push(_delegationAddress); // Stores delegators addresses on a delegation address hash delegationAddressHashes[delegationAddressHash].push(_delegatorAddress); // Push additional data to the globalDelegationHashes mapping if (_allTokens == true) { GlobalData memory newdelegationGlobalData = GlobalData(_delegatorAddress, _delegationAddress, block.timestamp, _expiryDate, true, 0); globalDelegationHashes[globalHash].push(newdelegationGlobalData); } else { GlobalData memory newdelegationGlobalData = GlobalData(_delegatorAddress, _delegationAddress, block.timestamp, _expiryDate, false, _tokenId); globalDelegationHashes[globalHash].push(newdelegationGlobalData); } emit RegisterDelegationUsingSubDelegation(_delegatorAddress, msg.sender, _collectionAddress, _delegationAddress, _useCase, _allTokens, _tokenId); } /** * @notice Delegator revokes delegation rights given to a delegation address on a specific use case on a specific NFT collection * @notice This function does not remove the delegation from the collectionsRegistered or useCaseRegistered as we want to track delegations history */ function revokeDelegationAddress(address _collectionAddress, address _delegationAddress, uint256 _useCase) public { bytes32 delegatorHash; bytes32 delegationAddressHash; bytes32 globalHash; uint256 count; globalHash = keccak256(abi.encodePacked(msg.sender, _collectionAddress, _delegationAddress, _useCase)); delegatorHash = keccak256(abi.encodePacked(msg.sender, _collectionAddress, _useCase)); delegationAddressHash = keccak256(abi.encodePacked(_delegationAddress, _collectionAddress, _useCase)); // Revoke delegation Address from the delegatorHashes mapping count = 0; if (delegatorHashes[delegatorHash].length > 0) { for (uint256 i = 0; i < delegatorHashes[delegatorHash].length; ) { if (_delegationAddress == delegatorHashes[delegatorHash][i]) { count = count + 1; } unchecked { ++i; } } uint256[] memory delegationsPerUser = new uint256[](count); uint256 count1 = 0; for (uint256 i = 0; i < delegatorHashes[delegatorHash].length; ) { if (_delegationAddress == delegatorHashes[delegatorHash][i]) { delegationsPerUser[count1] = i; count1 = count1 + 1; } unchecked { ++i; } } if (count1 > 0) { for (uint256 j = 0; j < delegationsPerUser.length; ) { uint256 temp1; uint256 temp2; temp1 = delegationsPerUser[delegationsPerUser.length - 1 - j]; temp2 = delegatorHashes[delegatorHash].length - 1; delegatorHashes[delegatorHash][temp1] = delegatorHashes[delegatorHash][temp2]; delegatorHashes[delegatorHash].pop(); unchecked { ++j; } } } // Revoke delegator Address from the delegationAddressHashes mapping uint256 countDA = 0; for (uint256 i = 0; i < delegationAddressHashes[delegationAddressHash].length; ) { if (msg.sender == delegationAddressHashes[delegationAddressHash][i]) { countDA = countDA + 1; } unchecked { ++i; } } uint256[] memory delegatorsPerUser = new uint256[](countDA); uint256 countDA1 = 0; for (uint256 i = 0; i < delegationAddressHashes[delegationAddressHash].length; ) { if (msg.sender == delegationAddressHashes[delegationAddressHash][i]) { delegatorsPerUser[countDA1] = i; countDA1 = countDA1 + 1; } unchecked { ++i; } } if (countDA1 > 0) { for (uint256 j = 0; j < delegatorsPerUser.length; ) { uint256 temp1; uint256 temp2; temp1 = delegatorsPerUser[delegatorsPerUser.length - 1 - j]; temp2 = delegationAddressHashes[delegationAddressHash].length - 1; delegationAddressHashes[delegationAddressHash][temp1] = delegationAddressHashes[delegationAddressHash][temp2]; delegationAddressHashes[delegationAddressHash].pop(); unchecked { ++j; } } } // Delete global delegation data and emit event delete globalDelegationHashes[globalHash]; emit RevokeDelegation(msg.sender, _collectionAddress, _delegationAddress, _useCase); } } /** * @notice This function supports the revoking of a Delegation Address using an address with Subdelegation rights */ function revokeDelegationAddressUsingSubdelegation(address _delegatorAddress, address _collectionAddress, address _delegationAddress, uint256 _useCase) public { // Check subdelegation rights for the specific collection { bool subdelegationRightsCol; address[] memory allDelegators = retrieveDelegators(msg.sender, _collectionAddress, USE_CASE_SUB_DELEGATION); if (allDelegators.length > 0) { for (uint i = 0; i < allDelegators.length; ) { if (_delegatorAddress == allDelegators[i]) { subdelegationRightsCol = true; break; } unchecked { ++i; } } } // Check subdelegation rights for All collections allDelegators = retrieveDelegators(msg.sender, ALL_COLLECTIONS, USE_CASE_SUB_DELEGATION); if (allDelegators.length > 0) { if (subdelegationRightsCol != true) { for (uint i = 0; i < allDelegators.length; ) { if (_delegatorAddress == allDelegators[i]) { subdelegationRightsCol = true; break; } unchecked { ++i; } } } } // Allow to revoke require((subdelegationRightsCol == true)); } // If check passed then revoke delegation address for Delegator bytes32 delegatorHash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, _useCase)); bytes32 delegationAddressHash = keccak256(abi.encodePacked(_delegationAddress, _collectionAddress, _useCase)); bytes32 globalHash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, _delegationAddress, _useCase)); uint256 count; count = 0; if (delegatorHashes[delegatorHash].length > 0) { for (uint256 i = 0; i < delegatorHashes[delegatorHash].length; ) { if (_delegationAddress == delegatorHashes[delegatorHash][i]) { count = count + 1; } unchecked { ++i; } } uint256[] memory delegationsPerUser = new uint256[](count); uint256 count1 = 0; for (uint256 i = 0; i < delegatorHashes[delegatorHash].length; ) { if (_delegationAddress == delegatorHashes[delegatorHash][i]) { delegationsPerUser[count1] = i; count1 = count1 + 1; } unchecked { ++i; } } if (count1 > 0) { for (uint256 j = 0; j < delegationsPerUser.length; ) { uint256 temp1; uint256 temp2; temp1 = delegationsPerUser[delegationsPerUser.length - 1 - j]; temp2 = delegatorHashes[delegatorHash].length - 1; delegatorHashes[delegatorHash][temp1] = delegatorHashes[delegatorHash][temp2]; delegatorHashes[delegatorHash].pop(); unchecked { ++j; } } } // Revoke delegator Address from the delegationAddressHashes mapping uint256 countDA = 0; for (uint256 i = 0; i < delegationAddressHashes[delegationAddressHash].length; ) { if (_delegatorAddress == delegationAddressHashes[delegationAddressHash][i]) { countDA = countDA + 1; } unchecked { ++i; } } uint256[] memory delegatorsPerUser = new uint256[](countDA); uint256 countDA1 = 0; for (uint256 i = 0; i < delegationAddressHashes[delegationAddressHash].length; ) { if (_delegatorAddress == delegationAddressHashes[delegationAddressHash][i]) { delegatorsPerUser[countDA1] = i; countDA1 = countDA1 + 1; } unchecked { ++i; } } if (countDA1 > 0) { for (uint256 j = 0; j < delegatorsPerUser.length; ) { uint256 temp1; uint256 temp2; temp1 = delegatorsPerUser[delegatorsPerUser.length - 1 - j]; temp2 = delegationAddressHashes[delegationAddressHash].length - 1; delegationAddressHashes[delegationAddressHash][temp1] = delegationAddressHashes[delegationAddressHash][temp2]; delegationAddressHashes[delegationAddressHash].pop(); unchecked { ++j; } } } // Delete global delegation data and emit event delete globalDelegationHashes[globalHash]; emit RevokeDelegationUsingSubDelegation(_delegatorAddress, msg.sender, _collectionAddress, _delegationAddress, _useCase); } } /** * @notice Batch revoking (up to 5 delegation addresses) */ function batchRevocations(address[] memory _collectionAddresses, address[] memory _delegationAddresses, uint256[] memory _useCases) public { require(_collectionAddresses.length < 6); for (uint256 i = 0; i < _collectionAddresses.length; ) { revokeDelegationAddress(_collectionAddresses[i], _delegationAddresses[i], _useCases[i]); unchecked { ++i; } } } /** * @notice Delegator updates a delegation address for a specific use case on a specific NFT collection for a certain duration */ function updateDelegationAddress(address _collectionAddress, address _olddelegationAddress, address _newdelegationAddress, uint256 _expiryDate, uint256 _useCase, bool _allTokens, uint256 _tokenId) public { revokeDelegationAddress(_collectionAddress, _olddelegationAddress, _useCase); registerDelegationAddress(_collectionAddress, _newdelegationAddress, _expiryDate, _useCase, _allTokens, _tokenId); emit UpdateDelegation(msg.sender, _collectionAddress, _olddelegationAddress, _newdelegationAddress, _useCase, _allTokens, _tokenId); } /** * @notice Batch registrations function (up to 5 delegation addresses) */ function batchDelegations(address[] memory _collectionAddresses, address[] memory _delegationAddresses, uint256[] memory _expiryDates, uint256[] memory _useCases, bool[] memory _allTokens, uint256[] memory _tokenIds) public { require(_collectionAddresses.length < 6); for (uint256 i = 0; i < _collectionAddresses.length; ) { registerDelegationAddress(_collectionAddresses[i], _delegationAddresses[i], _expiryDates[i], _useCases[i], _allTokens[i], _tokenIds[i]); unchecked { ++i; } } } /** * @notice Set global Lock status (hot wallet) */ function setGlobalLock(bool _status) public { globalLock[msg.sender] = _status; } /** * @notice Set collection Lock status (hot wallet) */ function setCollectionLock(address _collectionAddress, bool _status) public { if (_collectionAddress == ALL_COLLECTIONS) { setGlobalLock(_status); } else { bytes32 collectionLockHash = keccak256(abi.encodePacked(_collectionAddress, msg.sender)); collectionLock[collectionLockHash] = _status; } } /** * @notice Set collection usecase Lock status (hot wallet) */ function setCollectionUsecaseLock(address _collectionAddress, uint256 _useCase, bool _status) public { if (_useCase==1) { setCollectionLock(_collectionAddress, _status); } else { bytes32 collectionUsecaseLockHash = keccak256(abi.encodePacked(_collectionAddress, msg.sender, _useCase)); collectionUsecaseLock[collectionUsecaseLockHash] = _status; } } /** * @notice This function updates the number of Use Cases in case more usecases are needed */ function updateUseCaseCounter() public { useCaseCounter = useCaseCounter + 1; } // A full list of Available Getter functions /** * @notice Retrieve Global Lock Status */ function retrieveGlobalLockStatus(address _delegationAddress) public view returns (bool) { return globalLock[_delegationAddress]; } /** * @notice Retrieve Collection Lock Status */ function retrieveCollectionLockStatus(address _collectionAddress, address _delegationAddress) public view returns (bool) { if (_collectionAddress == ALL_COLLECTIONS) { return retrieveGlobalLockStatus(_delegationAddress); } else { bytes32 collectionLockHash; collectionLockHash = keccak256(abi.encodePacked(_collectionAddress, _delegationAddress)); return collectionLock[collectionLockHash]; } } /** * @notice Retrieve Collection Use Case Lock Status */ function retrieveCollectionUseCaseLockStatus(address _collectionAddress, address _delegationAddress, uint256 _useCase) public view returns (bool) { if (_useCase == 1) { return retrieveCollectionLockStatus(_collectionAddress, _delegationAddress); } else { bytes32 collectionUsecaseLockHash; collectionUsecaseLockHash = keccak256(abi.encodePacked(_collectionAddress, _delegationAddress, _useCase)); return collectionUsecaseLock[collectionUsecaseLockHash]; } } /** * @notice Retrieve Collection Use Case Lock Status for both specific colleciton and ALL_COLLECTIONS */ function retrieveCollectionUseCaseLockStatusOneCall(address _collectionAddress, address _delegationAddress, uint256 _useCase) public view returns (bool) { if (_useCase == 1) { return retrieveCollectionLockStatus(_collectionAddress, _delegationAddress); } else { return retrieveCollectionUseCaseLockStatus(_collectionAddress, _delegationAddress, _useCase) || retrieveCollectionUseCaseLockStatus(ALL_COLLECTIONS, _delegationAddress, _useCase); } } /** * @notice Support function to retrieve the hash given specific parameters */ function retrieveLocalHash(address _walletAddress, address _collectionAddress, uint256 _useCase) public pure returns (bytes32) { bytes32 hash; hash = keccak256(abi.encodePacked(_walletAddress, _collectionAddress, _useCase)); return (hash); } /** * @notice Support function to retrieve the global hash given specific parameters */ function retrieveGlobalHash(address _delegatorAddress, address _collectionAddress, address _delegationAddress, uint256 _useCase) public pure returns (bytes32) { bytes32 globalHash; globalHash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, _delegationAddress, _useCase)); return (globalHash); } /** * @notice Returns an array of all delegation addresses (active AND inactive) assigned by a delegator for a specific use case on a specific NFT collection */ function retrieveDelegationAddresses(address _delegatorAddress, address _collectionAddress, uint256 _useCase) public view returns (address[] memory) { bytes32 hash; hash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, _useCase)); return (delegatorHashes[hash]); } /** * @notice Returns an array of all delegators (active AND inactive) that delegated to a delegationAddress for a specific use case on a specific NFT collection */ function retrieveDelegators(address _delegationAddress, address _collectionAddress, uint256 _useCase) public view returns (address[] memory) { bytes32 hash; hash = keccak256(abi.encodePacked(_delegationAddress, _collectionAddress, _useCase)); return (delegationAddressHashes[hash]); } /** * @notice Returns the status of a collection/delegation for a delegator (cold wallet) * @notice false means that the cold wallet did not register a delegation or the delegation was revoked from the delegatorHashes mapping */ function retrieveDelegatorStatusOfDelegation(address _delegatorAddress, address _collectionAddress, uint256 _useCase) public view returns (bool) { bytes32 hash; hash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, _useCase)); return delegatorHashes[hash].length > 0; } /** * @notice Returns the status of a collection/delegation given a delegation address (hot wallet) * @notice false means that a delegation address is not registered or it was revoked from the delegationAddressHashes mapping */ function retrieveDelegationAddressStatusOfDelegation(address _delegationAddress, address _collectionAddress, uint256 _useCase) public view returns (bool) { bytes32 hash; hash = keccak256(abi.encodePacked(_delegationAddress, _collectionAddress, _useCase)); return delegationAddressHashes[hash].length > 0; } /** * @notice Returns the status of a delegation given the delegator address as well as the delegation address */ function retrieveGlobalStatusOfDelegation(address _delegatorAddress, address _collectionAddress, address _delegationAddress, uint256 _useCase) public view returns (bool) { bytes32 hash; hash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, _delegationAddress, _useCase)); return globalDelegationHashes[hash].length > 0; } /** * @notice Returns the status of a delegation given the delegator address, the collection address, the delegation address as well as a specific token id */ function retrieveTokenStatus(address _delegatorAddress, address _collectionAddress, address _delegationAddress, uint256 _useCase, uint256 _tokenId) public view returns (bool) { bytes32 hash; hash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, _delegationAddress, _useCase)); bool status; if (globalDelegationHashes[hash].length > 0) { for (uint256 i = 0; i < globalDelegationHashes[hash].length; ) { if ((globalDelegationHashes[hash][i].allTokens == false) && (globalDelegationHashes[hash][i].tokens == _tokenId)) { status = true; break; } else { status = false; } unchecked { ++i; } } return status; } else { return false; } } /** * @notice Checks if the delegation address performing actions is the most recent delegated by the specific delegator */ function retrieveStatusOfMostRecentDelegation(address _delegatorAddress, address _collectionAddress, address _delegationAddress, uint256 _useCase) public view returns (bool) { return _delegationAddress == retrieveMostRecentDelegation(_delegatorAddress, _collectionAddress, _useCase); } /** * @notice Checks if a delegator granted subdelegation status to an Address */ function retrieveSubDelegationStatus(address _delegatorAddress, address _collectionAddress, address _delegationAddress) public view returns (bool) { bool subdelegationRights; address[] memory allDelegators = retrieveDelegators(_delegationAddress, _collectionAddress, USE_CASE_SUB_DELEGATION); if (allDelegators.length > 0) { for (uint i = 0; i < allDelegators.length; ) { if (_delegatorAddress == allDelegators[i]) { subdelegationRights = true; break; } unchecked { ++i; } } } if (subdelegationRights == true) { return (true); } else { return (false); } } /** * @notice Checks the status of an active delegator for a delegation Address */ function retrieveStatusOfActiveDelegator(address _delegatorAddress, address _collectionAddress, address _delegationAddress, uint256 _date, uint256 _useCase) public view returns (bool) { address[] memory allActiveDelegators = retrieveActiveDelegators(_delegationAddress, _collectionAddress, _date, _useCase); bool status; if (allActiveDelegators.length > 0) { for (uint256 i = 0; i < allActiveDelegators.length; ) { if (_delegatorAddress == allActiveDelegators[i]) { status = true; break; } else { status = false; } unchecked { ++i; } } return status; } else { return false; } } // Retrieve Delegations delegated by a Delegator // This set of functions is used to retrieve info for a Delegator (cold address) function retrieveDelegationAddressesTokensIDsandExpiredDates(address _delegatorAddress, address _collectionAddress, uint256 _useCase) public view returns (address[] memory, uint256[] memory, bool[] memory, uint256[] memory) { address[] memory allDelegations = retrieveDelegationAddresses(_delegatorAddress, _collectionAddress, _useCase); bytes32 globalHash; bytes32[] memory allGlobalHashes = new bytes32[](allDelegations.length); uint256 count1 = 0; uint256 count2 = 0; uint256 k = 0; if (allDelegations.length > 0) { for (uint256 i = 0; i < allDelegations.length; ) { globalHash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, allDelegations[i], _useCase)); allGlobalHashes[count1] = globalHash; count1 = count1 + 1; unchecked { ++i; } } //Removes duplicates for (uint256 i = 0; i < allGlobalHashes.length - 1; ) { for (uint256 j = i + 1; j < allGlobalHashes.length; ) { if (allGlobalHashes[i] == allGlobalHashes[j]) { delete allGlobalHashes[i]; } unchecked { ++j; } } unchecked { ++i; } } for (uint256 i = 0; i < allGlobalHashes.length; ) { k = globalDelegationHashes[allGlobalHashes[i]].length + k; unchecked { ++i; } } //Declare local arrays address[] memory allDelegationAddresses = new address[](k); uint256[] memory tokensIDs = new uint256[](k); bool[] memory allTokens = new bool[](k); uint256[] memory allExpirations = new uint256[](k); for (uint256 y = 0; y < k; ) { if (globalDelegationHashes[allGlobalHashes[y]].length > 0) { for (uint256 w = 0; w < globalDelegationHashes[allGlobalHashes[y]].length; ) { allDelegationAddresses[count2] = globalDelegationHashes[allGlobalHashes[y]][w].delegationAddress; allExpirations[count2] = globalDelegationHashes[allGlobalHashes[y]][w].expiryDate; allTokens[count2] = globalDelegationHashes[allGlobalHashes[y]][w].allTokens; tokensIDs[count2] = globalDelegationHashes[allGlobalHashes[y]][w].tokens; count2 = count2 + 1; unchecked { ++w; } } } unchecked { ++y; } } return (allDelegationAddresses, allExpirations, allTokens, tokensIDs); } else { address[] memory allDelegations1 = new address[](0); uint256[] memory tokensIDs = new uint256[](0); bool[] memory allTokens = new bool[](0); uint256[] memory allExpirations = new uint256[](0); return (allDelegations1, allExpirations, allTokens, tokensIDs); } } /** * @notice Returns an array of all active delegation addresses on a certain date for a specific use case on a specific NFT collection given a delegation Address */ function retrieveActiveDelegations(address _delegatorAddress, address _collectionAddress, uint256 _date, uint256 _useCase) public view returns (address[] memory) { address[] memory allDelegations = retrieveDelegationAddresses(_delegatorAddress, _collectionAddress, _useCase); bytes32 globalHash; bytes32[] memory allGlobalHashes = new bytes32[](allDelegations.length); uint256 count1 = 0; uint256 count2 = 0; uint256 count3 = 0; uint256 k = 0; if (allDelegations.length > 0) { for (uint256 i = 0; i < allDelegations.length; ) { globalHash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, allDelegations[i], _useCase)); allGlobalHashes[count1] = globalHash; count1 = count1 + 1; unchecked { ++i; } } //Remove duplicates for (uint256 i = 0; i < allGlobalHashes.length - 1; ) { for (uint256 j = i + 1; j < allGlobalHashes.length; ) { if (allGlobalHashes[i] == allGlobalHashes[j]) { delete allGlobalHashes[i]; } unchecked { ++j; } } unchecked { ++i; } } for (uint256 i = 0; i < allGlobalHashes.length; ) { k = globalDelegationHashes[allGlobalHashes[i]].length + k; unchecked { ++i; } } //Declare local arrays address[] memory allDelegationAddresses = new address[](k); uint256[] memory allExpirations = new uint256[](k); for (uint256 y = 0; y < k; ) { if (globalDelegationHashes[allGlobalHashes[y]].length > 0) { for (uint256 w = 0; w < globalDelegationHashes[allGlobalHashes[y]].length; ) { allDelegationAddresses[count2] = globalDelegationHashes[allGlobalHashes[y]][w].delegationAddress; allExpirations[count2] = globalDelegationHashes[allGlobalHashes[y]][w].expiryDate; count2 = count2 + 1; unchecked { ++w; } } } unchecked { ++y; } } address[] memory allActive = new address[](allExpirations.length); for (uint256 y = 0; y < k; ) { if (allExpirations[y] > _date) { allActive[count3] = allDelegationAddresses[y]; count3 = count3 + 1; } unchecked { ++y; } } return (allActive); } else { address[] memory allActive = new address[](0); return (allActive); } } /** * @notice Returns the most recent delegation address delegated for a specific use case on a specific NFT collection */ function retrieveMostRecentDelegation(address _delegatorAddress, address _collectionAddress, uint256 _useCase) public view returns (address) { address[] memory allDelegations = retrieveDelegationAddresses(_delegatorAddress, _collectionAddress, _useCase); bytes32 globalHash; bytes32[] memory allGlobalHashes = new bytes32[](allDelegations.length); uint256 count1 = 0; uint256 count2 = 0; uint256 k = 0; if (allDelegations.length > 0) { for (uint256 i = 0; i < allDelegations.length; ) { globalHash = keccak256(abi.encodePacked(_delegatorAddress, _collectionAddress, allDelegations[i], _useCase)); allGlobalHashes[count1] = globalHash; count1 = count1 + 1; unchecked { ++i; } } //Removes duplicates for (uint256 i = 0; i < allGlobalHashes.length - 1; ) { for (uint256 j = i + 1; j < allGlobalHashes.length; ) { if (allGlobalHashes[i] == allGlobalHashes[j]) { delete allGlobalHashes[i]; } unchecked { ++j; } } unchecked { ++i; } } for (uint256 i = 0; i < allGlobalHashes.length; ) { k = globalDelegationHashes[allGlobalHashes[i]].length + k; unchecked { ++i; } } //Declare local arrays address[] memory allDelegationAddresses = new address[](k); uint256[] memory allRegistrations = new uint256[](k); for (uint256 y = 0; y < k; ) { if (globalDelegationHashes[allGlobalHashes[y]].length > 0) { for (uint256 w = 0; w < globalDelegationHashes[allGlobalHashes[y]].length; ) { allDelegationAddresses[count2] = globalDelegationHashes[allGlobalHashes[y]][w].delegationAddress; allRegistrations[count2] = globalDelegationHashes[allGlobalHashes[y]][w].registeredDate; count2 = count2 + 1; unchecked { ++w; } } } unchecked { ++y; } } address recentDelegationAddress = allDelegationAddresses[0]; uint256 time = allRegistrations[0]; for (uint256 i = 0; i < allDelegationAddresses.length; ) { if (allRegistrations[i] >= time) { time = allRegistrations[i]; recentDelegationAddress = allDelegationAddresses[i]; } unchecked { ++i; } } return (recentDelegationAddress); } else { return (0x0000000000000000000000000000000000000000); } } // Retrieve Delegators delegated to a hot wallet // This set of functions is used to retrieve info for a hot wallet /** * @notice Returns an array of all token ids delegated by a Delegator for a specific usecase on specific collection given a delegation Address */ function retrieveDelegatorsTokensIDsandExpiredDates(address _delegationAddress, address _collectionAddress, uint256 _useCase) public view returns (address[] memory, uint256[] memory, bool[] memory, uint256[] memory) { address[] memory allDelegators = retrieveDelegators(_delegationAddress, _collectionAddress, _useCase); bytes32 globalHash; bytes32[] memory allGlobalHashes = new bytes32[](allDelegators.length); uint256 count1 = 0; uint256 count2 = 0; uint256 k = 0; if (allDelegators.length > 0) { for (uint256 i = 0; i < allDelegators.length; ) { globalHash = keccak256(abi.encodePacked(allDelegators[i], _collectionAddress, _delegationAddress, _useCase)); allGlobalHashes[count1] = globalHash; count1 = count1 + 1; unchecked { ++i; } } //Removes duplicates for (uint256 i = 0; i < allGlobalHashes.length - 1; ) { for (uint256 j = i + 1; j < allGlobalHashes.length; ) { if (allGlobalHashes[i] == allGlobalHashes[j]) { delete allGlobalHashes[i]; } unchecked { ++j; } } unchecked { ++i; } } for (uint256 i = 0; i < allGlobalHashes.length; ) { k = globalDelegationHashes[allGlobalHashes[i]].length + k; unchecked { ++i; } } //Declare local arrays address[] memory allDelegatorsAddresses = new address[](k); uint256[] memory tokensIDs = new uint256[](k); bool[] memory allTokens = new bool[](k); uint256[] memory allExpirations = new uint256[](k); for (uint256 y = 0; y < k; ) { if (globalDelegationHashes[allGlobalHashes[y]].length > 0) { for (uint256 w = 0; w < globalDelegationHashes[allGlobalHashes[y]].length; ) { allDelegatorsAddresses[count2] = globalDelegationHashes[allGlobalHashes[y]][w].delegatorAddress; allExpirations[count2] = globalDelegationHashes[allGlobalHashes[y]][w].expiryDate; allTokens[count2] = globalDelegationHashes[allGlobalHashes[y]][w].allTokens; tokensIDs[count2] = globalDelegationHashes[allGlobalHashes[y]][w].tokens; count2 = count2 + 1; unchecked { ++w; } } } unchecked { ++y; } } return (allDelegatorsAddresses, allExpirations, allTokens, tokensIDs); } else { address[] memory allDelegations1 = new address[](0); uint256[] memory tokensIDs = new uint256[](0); bool[] memory allTokens = new bool[](0); uint256[] memory allExpirations = new uint256[](0); return (allDelegations1, allExpirations, allTokens, tokensIDs); } } /** * @notice Returns an array of all active delegators on a certain date for a specific use case on a specific NFT collection given a delegation Address */ function retrieveActiveDelegators(address _delegationAddress, address _collectionAddress, uint256 _date, uint256 _useCase) public view returns (address[] memory) { address[] memory allDelegators = retrieveDelegators(_delegationAddress, _collectionAddress, _useCase); bytes32 globalHash; bytes32[] memory allGlobalHashes = new bytes32[](allDelegators.length); uint256 count1 = 0; uint256 count2 = 0; uint256 count3 = 0; uint256 k = 0; if (allDelegators.length > 0) { for (uint256 i = 0; i < allDelegators.length; ) { globalHash = keccak256(abi.encodePacked(allDelegators[i], _collectionAddress, _delegationAddress, _useCase)); allGlobalHashes[count1] = globalHash; count1 = count1 + 1; unchecked { ++i; } } //Remove duplicates for (uint256 i = 0; i < allGlobalHashes.length - 1; ) { for (uint256 j = i + 1; j < allGlobalHashes.length; ) { if (allGlobalHashes[i] == allGlobalHashes[j]) { delete allGlobalHashes[i]; } unchecked { ++j; } } unchecked { ++i; } } for (uint256 i = 0; i < allGlobalHashes.length; ) { k = globalDelegationHashes[allGlobalHashes[i]].length + k; unchecked { ++i; } } //Declare local arrays address[] memory allDelegatorsAddresses = new address[](k); uint256[] memory allExpirations = new uint256[](k); for (uint256 y = 0; y < k; ) { if (globalDelegationHashes[allGlobalHashes[y]].length > 0) { for (uint256 w = 0; w < globalDelegationHashes[allGlobalHashes[y]].length; ) { allDelegatorsAddresses[count2] = globalDelegationHashes[allGlobalHashes[y]][w].delegatorAddress; allExpirations[count2] = globalDelegationHashes[allGlobalHashes[y]][w].expiryDate; count2 = count2 + 1; unchecked { ++w; } } } unchecked { ++y; } } address[] memory allActive = new address[](allExpirations.length); for (uint256 y = 0; y < k; ) { if (allExpirations[y] > _date) { allActive[count3] = allDelegatorsAddresses[y]; count3 = count3 + 1; } unchecked { ++y; } } return (allActive); } else { address[] memory allActive = new address[](0); return (allActive); } } /** * @notice Returns the most recent delegator for a specific use case on a specific NFT collection given a delegation Address */ function retrieveMostRecentDelegator(address _delegationAddress, address _collectionAddress, uint256 _useCase) public view returns (address) { address[] memory allDelegators = retrieveDelegators(_delegationAddress, _collectionAddress, _useCase); bytes32 globalHash; bytes32[] memory allGlobalHashes = new bytes32[](allDelegators.length); uint256 count1 = 0; uint256 count2 = 0; uint256 k = 0; if (allDelegators.length > 0) { for (uint256 i = 0; i < allDelegators.length; ) { globalHash = keccak256(abi.encodePacked(allDelegators[i], _collectionAddress, _delegationAddress, _useCase)); allGlobalHashes[count1] = globalHash; count1 = count1 + 1; unchecked { ++i; } } //Removes duplicates for (uint256 i = 0; i < allGlobalHashes.length - 1; ) { for (uint256 j = i + 1; j < allGlobalHashes.length; ) { if (allGlobalHashes[i] == allGlobalHashes[j]) { delete allGlobalHashes[i]; } unchecked { ++j; } } unchecked { ++i; } } for (uint256 i = 0; i < allGlobalHashes.length; ) { k = globalDelegationHashes[allGlobalHashes[i]].length + k; unchecked { ++i; } } //Declare local arrays address[] memory allDelegatorsAddresses = new address[](k); uint256[] memory allRegistrations = new uint256[](k); for (uint256 y = 0; y < k; ) { if (globalDelegationHashes[allGlobalHashes[y]].length > 0) { for (uint256 w = 0; w < globalDelegationHashes[allGlobalHashes[y]].length; ) { allDelegatorsAddresses[count2] = globalDelegationHashes[allGlobalHashes[y]][w].delegatorAddress; allRegistrations[count2] = globalDelegationHashes[allGlobalHashes[y]][w].registeredDate; count2 = count2 + 1; unchecked { ++w; } } } unchecked { ++y; } } address recentDelegatorAddress = allDelegatorsAddresses[0]; uint256 time = allRegistrations[0]; for (uint256 i = 0; i < allDelegatorsAddresses.length; ) { if (allRegistrations[i] >= time) { time = allRegistrations[i]; recentDelegatorAddress = allDelegatorsAddresses[i]; } unchecked { ++i; } } return (recentDelegatorAddress); } else { return (0x0000000000000000000000000000000000000000); } } /** * @notice This function checks the Consolidation status between 2 addresses */ function checkConsolidationStatus(address _wallet1, address _wallet2, address _collectionAddress) public view returns (bool) { bool wallet1HasWallet2Consolidation = retrieveGlobalStatusOfDelegation(_wallet1, _collectionAddress, _wallet2, USE_CASE_CONSOLIDATION); bool wallet2HasWallet1Consolidation = retrieveGlobalStatusOfDelegation(_wallet2, _collectionAddress, _wallet1, USE_CASE_CONSOLIDATION); bool wallet1HasWallet2ConsolidationAll = retrieveGlobalStatusOfDelegation(_wallet1, ALL_COLLECTIONS, _wallet2, USE_CASE_CONSOLIDATION); bool wallet2HasWallet1ConsolidationAll = retrieveGlobalStatusOfDelegation(_wallet2, ALL_COLLECTIONS, _wallet1, USE_CASE_CONSOLIDATION); if (wallet1HasWallet2Consolidation == true && wallet2HasWallet1Consolidation == true) { return true; } else if (wallet1HasWallet2Consolidation == true && wallet2HasWallet1ConsolidationAll == true) { return true; } else if (wallet2HasWallet1Consolidation == true && wallet1HasWallet2ConsolidationAll == true) { return true; } else if (wallet1HasWallet2ConsolidationAll == true && wallet2HasWallet1ConsolidationAll == true) { return true; } else { return false; } } }