### 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);
}
```