Turn an ownable smart contract into an NFT
Smart contracts are little applications that reside at their deployed address on blockchains. NFTs are standardised unique tokens that you can sell, swap, put at auctions or as collateral for a loan. This is very convenient, and many sites have specialised into NFT market places: OpenSea, Rarible, PaintSwap, ...
What if you could turn your smart contract into an NFT?
That way, you could integrate it with the flourishing NFT ecosystem: its market places, galleries, search engines, ... you could sell it or put it to auction much more easily than a traditional smart contract.
This story will explain how you can do that.
is Ownable
Most of the smart contract derive from OpenZepellin Ownable smart contract. This is very good practice. It gives you a way to transfer ownership of your smart contract. It gives anyone an owner address that they can reference to, in case they need help, provide feedback, make propositions...
So we'll make our contract ownable:
// myContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
contract myContract is Ownable {
// your contract in here
}
This is enough. Deriving your contract from Ownable with the is keyword is enough to make it ownable.
Once you've deployed your contract, you'll be the original owner. Everybody (and every other contract) can check than by calling the owner() method on your contract: they will get your wallet address back.
Your contract now also have the transferOwnership(to address) method, which only you can call, to transfer ownership of your contract to someone else. (And when I write someone, keep in mind that this someone can also be another smart contract.)
is ERC721
Now, for the NFT part. This will be a bit more complex.
Here again, we derive our contract from another one: ERC721.sol. This is the very good implementation of the ERC-721 standard that is commonly used to define NFTs. This ERC721 contract usually defines a collection of NFTs.
Here, our collection only has ... one element: our contract itself. So, we will just have tokenId = 1.
Turning the Ownable contract into an NFT
Now that the two pieces are together, all we have to do, is to mint the NFT 1 when the contract is created, and override a few functions from Ownable.sol so when ownership is transferred or renounced, the NFT 1 is also transferred or burnt.
We also need to make sure that contract ownership is transferred when the NFT 1 is transferred.
// abstractOwnableNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract OwnableNFT is Ownable, ERC721 {
// in the constructor, we must mint the NFT 1 to the owner
constructor(string memory name, string memory symbol) ERC721(name, symbol) {
// mint the NFT 1 to the owner
_safeMint(_msgSender(), 1);
}
// we override the transferOwnership() function from Ownable.sol
// so that when the owner changes, the NFT 1 is transferred to the new owner
function transferOwnership(address newOwner) override public virtual onlyOwner {
address oldOwner = owner();
Ownable.transferOwnership(newOwner);
ERC721.safeTransferFrom(oldOwner, newOwner, 1);
}
// we override the renounceOwnership() function from Ownable.sol
// so that when the owner renounces, the NFT 1 is burnt
function renounceOwnership() override public virtual onlyOwner {
Ownable.renounceOwnership();
ERC721._burn(1);
}
// we override the _afterTokenTransfer() function from ERC721.sol
// so that when the NFT 1 is transferred, the ownership is transferred
// to the new owner
function _afterTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize
) override internal virtual {
if (firstTokenId == 1) {
Ownable._transferOwnership(to);
}
}
}
Now, to create a contract that is, at the same time Ownable and whose ownership can be exchanged, sold, as an NFT, simply derive your contract from OwnableNFT:
// yourContract.sol
contract yourContract is OwnableNFT {
// your contract goes here
}
I hope this little tutorial helped you. Don't hesitate to react on this story, or make a comment if something isn't clear enough.
In my following stories, I'll show you what application involving vaults I'll build on top of this basic foundation. So stay tuned.