### Notes - El Wrapper en la funcion registerNewType el primero es el index 1. ```solidity function _registerNewType(address propertyManager_, bool isFungible_) internal { require(propertyManager_ != address(0), "Cannot set zero address"); typesCount++; typeContractPm[typesCount] = IExternalTokenPropertyManager(propertyManager_); isFungible[typesCount] = isFungible_; } ``` - Para ejecutar el wrap() tenes que hacer como usuario un approve al ExternalERC20|721 PM ```typescript await ERC20Token.connect(users[0]).approve(External_ERC20PropertyManager.address, amount); ``` - El tema del registerNewType es definitvamente una cagada y estaria bueno cambiarlo porque ademas no tiene condicion de revert en el caso de que vuelvas a agregar el mismo type, te lo pisa y listo. Deberia manejarse por un lado con un enumerable y a su vez la informacion arbitraria de que el tipo 1 es ERC20 , tipo 2 ERC721 ..etc tiene que estar a mi entender dentro del storage del contrato. Si les parece bien a mi me gustaria sugerirselo a Quentin o Pavel en el canal que tenemos. --- - La funcion wrap lo primero que hace es consultar si tiene que darle un mNFT al usuario: ```solidity function _wrap(WrapData memory data) internal { if (data.existingMetaNftToUse == 0) { metaNftId = metaNft.mint(msg.sender); } } ``` Si vamos a la funcion mint del metaToken es una funcion con permiso tambien: ```solidity function mint(address account) external onlyMinter returns (uint256) { require(MetaTokenStorage.layout().totalClaimed(account) == 0, "Token already minted"); uint256 pid = _mintInternal(account); MetaTokenStorage.layout().setClaimed(account, pid); return pid; } ``` - Con lo cual el metaNFT tiene que brindar permiso al wrapper para que pueda hacer minter, esto tambien se hace en los tests: ``` // Adding the Wrapper as minter for MetaNFT await metaContracts.PropertyRegistry.grantMinter(Wrapper.address); ``` - Manejo de los external para con el metaNFT y porque NO es necesario agregar el o los externals al metaNFT: ```solidity function lockTokensOnMetaNft(LockTokensOnMetaNftData memory data) external onlyWrapper { if (!isProperty[property]) { bytes32[] memory properties = new bytes32[](1); properties[0] = property; IMetaPropertyRegistry(propertyRegistry).addCategoryProperty(category, properties); isProperty[property] = true; } } ``` - Como se puede ver invocan al registry para añadir una category y la correspondiente property. Si vamos al registry para ver esa funcion: ```solidity function addCategoryProperty(bytes32 category, bytes32[] calldata properties) external onlyCategoryManager(category) { for (uint256 i = 0; i < properties.length; i++) { require(propertiesToCategories[properties[i]] == bytes32(0), "Property already registered"); propertiesToCategories[properties[i]] = category; categories[category].properties.push(properties[i]); } } ``` - El registry agrega una property a una categoria existente y para eso tiene que asignar al pm como admin de esa categoria. Esto lo realiza aca en los tests lo podemos ver: ``` // Create category (with the PM as his manager) await metaContracts.PropertyRegistry.connect(deployer).addCategory( kecakk256("ExternalErc20PropertyManager"), false, [kecakk256("ERC20")], External_ERC20PropertyManager.address ); await metaContracts.PropertyRegistry.connect(deployer).addCategory( kecakk256("ExternalErc721PropertyManager"), false, [kecakk256("ERC721")], External_ERC721PropertyManager.address ); await metaContracts.PropertyRegistry.connect(deployer).addCategory( kecakk256("ExternalErc1155PropertyManager"), false, [kecakk256("ERC1155")], External_ERC1155PropertyManager.address ); ``` - Por ultimo, el PM añade a traves del mNFT una restriccion que es justamente la data asociada al wrap y el timestamp que es lo mas importante que es el periodo de lockeo. El check en el unwrap esta dado por una facet del diamon que son ERC20LockRestriction y ERC1155LockRestriction que añaden hooks al proceso de wrap/unwrap lock/unlock: ```solidity /** * @dev Called by MetaRestrictionsInternal.removeRestrictionInternal() * If this is called not from the diamond via delegatecall, address(this) will be the Restriction contract itself which stores no tokens. */ function ERC20LockRestriction_removeRestrictionHook( uint256, /*pid*/ bytes32, /*prop*/ bytes32 rtype, bytes memory data ) external onlyDelegatecall { require(rtype == RTYPE, "wrong rtype"); Data memory d = abi.decode(data, (Data)); require(d.release <= block.timestamp, "Token release time not passed"); IERC20(d.token).safeTransfer(msg.sender, d.amount); } ```