Last active
August 17, 2023 11:06
-
-
Save CJ42/68e263f103b8ba9dff60f3401ca28a2d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: GPL-2.0-or-later | |
pragma solidity ^0.8.4; | |
// interfaces | |
import { | |
IERC725Y | |
} from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol"; | |
import {ILSP1UniversalReceiver} from "../ILSP1UniversalReceiver.sol"; | |
import {ILSP7DigitalAsset} from "../../LSP7DigitalAsset/ILSP7DigitalAsset.sol"; | |
// librairies | |
import {LSP2Utils} from "../../LSP2ERC725YJSONSchema/LSP2Utils.sol"; | |
import {LSP5Utils} from "../../LSP5ReceivedAssets/LSP5Utils.sol"; | |
import {LSP10Utils} from "../../LSP10ReceivedVaults/LSP10Utils.sol"; | |
// errors | |
import { | |
CannotRegisterEOAsAsAssets | |
} from "../../LSP1UniversalReceiver//LSP1Errors.sol"; | |
import "hardhat/console.sol"; | |
// constants | |
import { | |
_INTERFACEID_LSP7, | |
_TYPEID_LSP7_TOKENSSENDER, | |
_TYPEID_LSP7_TOKENSRECIPIENT | |
} from "../../LSP7DigitalAsset/LSP7Constants.sol"; | |
import { | |
_INTERFACEID_LSP8, | |
_TYPEID_LSP8_TOKENSSENDER, | |
_TYPEID_LSP8_TOKENSRECIPIENT | |
} from "../../LSP8IdentifiableDigitalAsset/LSP8Constants.sol"; | |
import { | |
_INTERFACEID_LSP9, | |
_TYPEID_LSP9_OwnershipTransferred_SenderNotification, | |
_TYPEID_LSP9_OwnershipTransferred_RecipientNotification | |
} from "../../LSP9Vault/LSP9Constants.sol"; | |
import { | |
_LSP5_RECEIVED_ASSETS_ARRAY_KEY, | |
_LSP5_RECEIVED_ASSETS_MAP_KEY_PREFIX | |
} from "../../LSP5ReceivedAssets/LSP5Constants.sol"; | |
import { | |
_LSP10_VAULTS_ARRAY_KEY, | |
_LSP10_VAULTS_MAP_KEY_PREFIX | |
} from "../../LSP10ReceivedVaults/LSP10Constants.sol"; | |
// refactored using function types | |
contract LSP1UniversalReceiverDelegateUPRefactored is ILSP1UniversalReceiver { | |
mapping(bytes32 => function(address) internal returns (bytes memory)) | |
internal _typeIdToHandler; | |
constructor() { | |
// Register handlers to react to LSP7 Tokens & LSP8 NFT the were transferred | |
_typeIdToHandler[_TYPEID_LSP7_TOKENSSENDER] = _handleLSP7TokensSent; | |
_typeIdToHandler[_TYPEID_LSP8_TOKENSSENDER] = _handleLSP7TokensReceived; | |
// Register handlers to react to LSP7 Tokens & LSP8 NFTs that were received | |
_typeIdToHandler[_TYPEID_LSP7_TOKENSRECIPIENT] = _handleLSP8NFTSent; | |
_typeIdToHandler[_TYPEID_LSP8_TOKENSRECIPIENT] = _handleLSP8NFTReceived; | |
// Register handlers to react to Vaults transfers | |
_typeIdToHandler[ | |
_TYPEID_LSP9_OwnershipTransferred_SenderNotification | |
] = _handleLSP9VaultsSent; | |
_typeIdToHandler[ | |
_TYPEID_LSP9_OwnershipTransferred_RecipientNotification | |
] = _handleLSP9VaultsReceived; | |
} | |
function universalReceiver( | |
bytes32 typeId, | |
bytes memory /* data */ | |
) public payable virtual returns (bytes memory result) { | |
address notifier = address(bytes20(msg.data[msg.data.length - 52:])); | |
// TODO: perform all the necessary validation in LSP1 | |
if (notifier == tx.origin) revert CannotRegisterEOAsAsAssets(notifier); | |
function(address) | |
internal | |
returns (bytes memory) functionToRun = _typeIdToHandler[typeId]; | |
bytes8 handlerFunction; | |
// Equality operators are not available for function types. | |
// We cannot do `functionToRun == bytes8(0)`, so we need to use assembly. | |
assembly { | |
handlerFunction := functionToRun | |
} | |
bool isHandlerRegistered = handlerFunction == bytes8(0); | |
// If it's a typeId different than LSP7/LSP8/LSP9 typeIds | |
if (!isHandlerRegistered) { | |
return "LSP1: typeId out of scope"; | |
} | |
return functionToRun(notifier); | |
} | |
// TODO put these functions in a separate LSP1 extension contract and inherit from it | |
function _handleLSP7TokensSent( | |
address notifier | |
) internal returns (bytes memory) { | |
// Generate the LSP5ReceivedAssetsMap data key of the notifier | |
bytes32 notifierMapKey = LSP2Utils.generateMappingKey( | |
_LSP5_RECEIVED_ASSETS_MAP_KEY_PREFIX, | |
bytes20(notifier) | |
); | |
// Query the value under this data key in the ERC725Y storage | |
bytes memory notifierMapValue = IERC725Y(msg.sender).getData( | |
notifierMapKey | |
); | |
bool isMapValueSet = bytes20(notifierMapValue) != bytes20(0); | |
if (!isMapValueSet) return "LSP1: asset sent is not registered"; | |
if (notifierMapValue.length < 20) return "LSP1: asset data corrupted"; | |
uint128 arrayIndex = uint128(uint160(bytes20(notifierMapValue))); | |
// if the amount sent is not the full balance, then do not update the keys | |
uint256 balance = ILSP7DigitalAsset(notifier).balanceOf(msg.sender); | |
if (balance != 0) return "LSP1: full balance is not sent"; | |
(bytes32[] memory dataKeys, bytes[] memory dataValues) = LSP5Utils | |
.generateSentAssetKeys(msg.sender, notifierMapKey, arrayIndex); | |
/** | |
* `generateSentAssetKeys(...)` returns empty arrays in the following cases: | |
* - the index returned from the data key `notifierMapKey` is bigger than | |
* the length of the `LSP5ReceivedAssets[]`, meaning, index is out of bounds. | |
*/ | |
if (dataKeys.length == 0 && dataValues.length == 0) | |
return "LSP1: asset data corrupted"; | |
// Set the LSP5 generated data keys on the account | |
IERC725Y(msg.sender).setDataBatch(dataKeys, dataValues); | |
return ""; | |
} | |
function _handleLSP7TokensReceived( | |
address notifier | |
) internal returns (bytes memory) { | |
// Generate the LSP5ReceivedAssetsMap data key of the notifier | |
bytes32 notifierMapKey = LSP2Utils.generateMappingKey( | |
_LSP5_RECEIVED_ASSETS_MAP_KEY_PREFIX, | |
bytes20(notifier) | |
); | |
// Query the value under this data key in the ERC725Y storage | |
bytes memory notifierMapValue = IERC725Y(msg.sender).getData( | |
notifierMapKey | |
); | |
bool isMapValueSet = bytes20(notifierMapValue) != bytes20(0); | |
if (isMapValueSet) return "LSP1: asset received is already registered"; | |
if (notifier.code.length > 0) { | |
// if the amount sent is 0, then do not update the keys | |
uint256 balance = ILSP7DigitalAsset(notifier).balanceOf(msg.sender); | |
if (balance == 0) return "LSP1: balance not updated"; | |
} | |
(bytes32[] memory dataKeys, bytes[] memory dataValues) = LSP5Utils | |
.generateReceivedAssetKeys( | |
msg.sender, | |
notifier, | |
notifierMapKey, | |
_INTERFACEID_LSP7 | |
); | |
// Set the LSP5 generated data keys on the account | |
IERC725Y(msg.sender).setDataBatch(dataKeys, dataValues); | |
return ""; | |
} | |
function _handleLSP8NFTSent( | |
address notifier | |
) internal returns (bytes memory) { | |
// Generate the LSP5ReceivedAssetsMap data key of the notifier | |
bytes32 notifierMapKey = LSP2Utils.generateMappingKey( | |
_LSP5_RECEIVED_ASSETS_MAP_KEY_PREFIX, | |
bytes20(notifier) | |
); | |
// Query the value under this data key in the ERC725Y storage | |
bytes memory notifierMapValue = IERC725Y(msg.sender).getData( | |
notifierMapKey | |
); | |
bool isMapValueSet = bytes20(notifierMapValue) != bytes20(0); | |
if (!isMapValueSet) return "LSP1: asset sent is not registered"; | |
if (notifierMapValue.length < 20) return "LSP1: asset data corrupted"; | |
uint128 arrayIndex = uint128(uint160(bytes20(notifierMapValue))); | |
// if the amount sent is not the full balance, then do not update the keys | |
uint256 balance = ILSP7DigitalAsset(notifier).balanceOf(msg.sender); | |
if (balance != 0) return "LSP1: full balance is not sent"; | |
(bytes32[] memory dataKeys, bytes[] memory dataValues) = LSP5Utils | |
.generateSentAssetKeys(msg.sender, notifierMapKey, arrayIndex); | |
/** | |
* `generateSentAssetKeys(...)` returns empty arrays in the following cases: | |
* - the index returned from the data key `notifierMapKey` is bigger than | |
* the length of the `LSP5ReceivedAssets[]`, meaning, index is out of bounds. | |
*/ | |
if (dataKeys.length == 0 && dataValues.length == 0) | |
return "LSP1: asset data corrupted"; | |
// Set the LSP5 generated data keys on the account | |
IERC725Y(msg.sender).setDataBatch(dataKeys, dataValues); | |
return ""; | |
} | |
function _handleLSP8NFTReceived( | |
address notifier | |
) internal returns (bytes memory) { | |
// Generate the LSP5ReceivedAssetsMap data key of the notifier | |
bytes32 notifierMapKey = LSP2Utils.generateMappingKey( | |
_LSP5_RECEIVED_ASSETS_MAP_KEY_PREFIX, | |
bytes20(notifier) | |
); | |
// Query the value under this data key in the ERC725Y storage | |
bytes memory notifierMapValue = IERC725Y(msg.sender).getData( | |
notifierMapKey | |
); | |
bool isMapValueSet = bytes20(notifierMapValue) != bytes20(0); | |
if (isMapValueSet) return "LSP1: asset received is already registered"; | |
if (notifier.code.length > 0) { | |
// if the amount sent is 0, then do not update the keys | |
uint256 balance = ILSP7DigitalAsset(notifier).balanceOf(msg.sender); | |
if (balance == 0) return "LSP1: balance not updated"; | |
} | |
(bytes32[] memory dataKeys, bytes[] memory dataValues) = LSP5Utils | |
.generateReceivedAssetKeys( | |
msg.sender, | |
notifier, | |
notifierMapKey, | |
_INTERFACEID_LSP8 | |
); | |
// Set the LSP5 generated data keys on the account | |
IERC725Y(msg.sender).setDataBatch(dataKeys, dataValues); | |
return ""; | |
} | |
function _handleLSP9VaultsSent( | |
address notifier | |
) internal returns (bytes memory) { | |
// Generate the LSP5ReceivedAssetsMap data key of the notifier | |
bytes32 notifierMapKey = LSP2Utils.generateMappingKey( | |
_LSP10_VAULTS_MAP_KEY_PREFIX, | |
bytes20(notifier) | |
); | |
// Query the value under this data key in the ERC725Y storage | |
bytes memory notifierMapValue = IERC725Y(msg.sender).getData( | |
notifierMapKey | |
); | |
bool isMapValueSet = bytes20(notifierMapValue) != bytes20(0); | |
if (!isMapValueSet) return "LSP1: asset sent is not registered"; | |
if (notifierMapValue.length < 20) return "LSP1: asset data corrupted"; | |
uint128 arrayIndex = uint128(uint160(bytes20(notifierMapValue))); | |
(bytes32[] memory dataKeys, bytes[] memory dataValues) = LSP10Utils | |
.generateSentVaultKeys(msg.sender, notifierMapKey, arrayIndex); | |
/** | |
* `generateSentAssetKeys(...)` returns empty arrays in the following cases: | |
* - the index returned from the data key `notifierMapKey` is bigger than | |
* the length of the `LSP10Vaults[]`, meaning, index is out of bounds. | |
*/ | |
if (dataKeys.length == 0 && dataValues.length == 0) | |
return "LSP1: asset data corrupted"; | |
// Set the LSP10 generated data keys on the account | |
IERC725Y(msg.sender).setDataBatch(dataKeys, dataValues); | |
return ""; | |
} | |
function _handleLSP9VaultsReceived( | |
address notifier | |
) internal returns (bytes memory) { | |
// Generate the LSP5ReceivedAssetsMap data key of the notifier | |
bytes32 notifierMapKey = LSP2Utils.generateMappingKey( | |
_LSP10_VAULTS_MAP_KEY_PREFIX, | |
bytes20(notifier) | |
); | |
// Query the value under this data key in the ERC725Y storage | |
bytes memory notifierMapValue = IERC725Y(msg.sender).getData( | |
notifierMapKey | |
); | |
bool isMapValueSet = bytes20(notifierMapValue) != bytes20(0); | |
if (isMapValueSet) return "LSP1: asset received is already registered"; | |
(bytes32[] memory dataKeys, bytes[] memory dataValues) = LSP10Utils | |
.generateReceivedVaultKeys(msg.sender, notifier, notifierMapKey); | |
// Set the LSP10 generated data keys on the account | |
IERC725Y(msg.sender).setDataBatch(dataKeys, dataValues); | |
return ""; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment