# Extensions

{% hint style="info" %}
Currently, enabling an extension requires writing and deploying a customized smart contract with the desired extension functions and logic using a Solidity IDE like [remix](https://remix.ethereum.org). Once deployed, the contract can be registered to a base Creator Core contract using the registerExtension function.
{% endhint %}

## Writing Extensions

Any contract written in solidity on the Ethereum network can be registered as an extension to a base Creator Contract. The extension will only be recognized by your Creator Contract for the purpose of overriding various functions by implementing specific interfaces.

### Override TokenURI Functionality

To override Token URI functionality implement interface [ICreatorExtensionTokenURI](https://github.com/manifoldxyz/creator-core-solidity/blob/release-1.0.6/contracts/extensions/ICreatorExtensionTokenURI.sol). This is applicable to both ERC721 and ERC1155 contracts:

```solidity
interface ICreatorExtensionTokenURI is IERC165 {
    /**
     * Get the uri for a given creator/tokenId
     */
    function tokenURI(address creator, uint256 tokenId) external view returns (string memory);
}
```

{% hint style="danger" %}
If you intend on using this functionality **DO NOT** pass in URI or baseURI values when you call mintExtension functions on the Creator Core contracts.  Doing so will cause the Creator Core contracts to ignore the overridden tokenURI logic.
{% endhint %}

### Receive a Burn Callback

To receive an onBurn callback (pre-burn hook) whenever a token the extension created is burned implement either the [IERC721CreatorExtensionBurnable](https://github.com/manifoldxyz/creator-core-solidity/blob/release-1.0.6/contracts/extensions/ERC721/IERC721CreatorExtensionBurnable.sol) or [IERC1155CreatorExtensionBurnable](https://github.com/manifoldxyz/creator-core-solidity/blob/release-1.0.6/contracts/extensions/ERC1155/IERC1155CreatorExtensionBurnable.sol) interface. Whenever a token created by the extension is burned using the Creator Core's burn function, this hook will fire.

*ERC721*

```solidity
interface IERC721CreatorExtensionBurnable is IERC165 {
    /**
     * @dev callback handler for burn events
     */
    function onBurn(address owner, uint256 tokenId) external;
}
```

*ERC1155*

```solidity
interface IERC1155CreatorExtensionBurnable is IERC165 {
    /**
     * @dev callback handler for burn events
     */
    function onBurn(address owner, uint256[] calldata tokenIds, uint256[] calldata amounts) external;
}
```

### Receive a Transfer Callback

To receive a transfer callback (pre-transfer hook) whenever a token the extension created is transferred implement either the [IERC721CreatorExtensionApproveTransfer](https://github.com/manifoldxyz/creator-core-solidity/blob/release-1.0.6/contracts/extensions/ERC721/IERC721CreatorExtensionApproveTransfer.sol) or [IERC1155CreatorExtensionApproveTransfer](https://github.com/manifoldxyz/creator-core-solidity/blob/release-1.0.6/contracts/extensions/ERC1155/IERC1155CreatorExtensionApproveTransfer.sol) interface. Whenever a token created by the extension is transferred using the Creator Core's transfer function this hook will fire.

{% hint style="danger" %}
In order to add a pre-transfer hook you need to implement the appropriate (ERC721 or ERC1155) CreatorExtensionApproveTransfer interface **AND** have the extension call setApproveTransferExtenstion (enabled). See the suggested implementation below the CreatorExtensionApproveTransfer interfaces.
{% endhint %}

*ERC721*

```solidity
interface IERC721CreatorExtensionApproveTransfer is IERC165 {

    /**
     * @dev Set whether or not the creator will check the extension for approval of token transfer
     */
    function setApproveTransfer(address creator, bool enabled) external;

    /**
     * @dev Called by creator contract to approve a transfer
     */
    function approveTransfer(address from, address to, uint256 tokenId) external returns (bool);
}
```

*ERC1155*

```solidity
interface IERC1155CreatorExtensionApproveTransfer is IERC165 {

    /**
     * @dev Set whether or not the creator contract will check the extension for approval of token transfer
     */
    function setApproveTransfer(address creator, bool enabled) external;

    /**
     * @dev Called by creator contract to approve a transfer
     */
    function approveTransfer(address from, address to, uint256[] calldata tokenIds, uint256[] calldata amounts) external returns (bool);
}
```

*Suggested implementation for extensions with a transfer callback*

```solidity
abstract contract ERC1155CreatorExtensionApproveTransfer is AdminControl, IERC1155CreatorExtensionApproveTransfer {

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(AdminControl, IERC165) returns (bool) {
        return interfaceId == type(IERC1155CreatorExtensionApproveTransfer).interfaceId
            || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC1155CreatorExtensionApproveTransfer-setApproveTransfer}
     */
    function setApproveTransfer(address creator, bool enabled) external override adminRequired {
        require(ERC165Checker.supportsInterface(creator, type(IERC1155CreatorCore).interfaceId), "creator must implement IERC1155CreatorCore");
        IERC1155CreatorCore(creator).setApproveTransferExtension(enabled);
    }

}
```

## Adding and Removing Extensions

Once deployed on the Ethereum network, extensions can be added or removed using the `registerExtension` and `unregisterExtension` functions. An extension can also be blacklisted via the `blacklistExtension` function, preventing future registrations of the address and destroying all references to metadata associate with tokens created by the extension.

For detailed extensions functions information see [Extensions Functions](https://docs.manifold.xyz/manifold-for-developers/smart-contracts/manifold-creator/contracts/extensions/extensions-functions).

{% hint style="info" %}
Depending on how they've been written, some extensions may require configuration before registration (e.g. setting a token range or other piece of data). If you've incorporate custom interfaces that need configuration, be sure to do this before registration.
{% endhint %}
