# Anatomy of a smart contract

## Anatomy of a smart contract

💡INFO

* What is a smart contract?
* Deep dive into smart contract types:
*
  * Fungible
  * Non-fungible
* Use cases of fungible and non-fungible tokens

### What is a smart contract?[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#what-is-a-smart-contract) <a href="#what-is-a-smart-contract" id="what-is-a-smart-contract"></a>

A smart contract is a class of code that is deployed to and runs on the blockchain. They can be made up of any arrangement of code and perform a wide range of functionality.

Examples of some common smart contracts:

* **Settlement contracts:** Facilitates the sale of assets from one user (seller) to another (buyer) by handling the filling of an order, payment and transfer of assets. Typically used by marketplaces in conjunction with an orderbook service.
* **Token contracts:** Facilitates the creation (<mark style="color:blue;">minting</mark>) of tokens that can be used and transferred between users in the open market.

The main type of smart contract that we are mostly concerned about as developers of blockchain games and NFT applications are <mark style="color:blue;">token smart contracts</mark>.

### Token smart contracts[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#token-smart-contracts) <a href="#token-smart-contracts" id="token-smart-contracts"></a>

These are smart contracts that govern the issuance (creation) of tokens. These contracts are typically defined by standards, which specify the functions that it needs to have to ensure that there is a standard way that games, applications and other contracts can interact with it.

The two main kinds of token smart contracts that we are concerned with when building games or NFT applications on XpansionChain are:

* **Non-fungible (defined by the&#x20;**<mark style="color:blue;">**ERC-721 standard**</mark>**)** - these produce tokens with unique properties from other tokens in their collection. For example, <mark style="color:blue;">Bored Ape</mark> #1 isn't interchangeable for Bored Ape #2 because they differ across a range of characteristics (ie. image, rarity) that different users will value differently.
* **Fungible (defined by the&#x20;**<mark style="color:blue;">**ERC-721 standard**</mark>**)** - these produce commodity-like tokens that are interchangeable with another token in its category, ie. ETH, IMX. If you lend someone ETH, it doesn't matter whether they send you back the exact same tokens that you lent them. All ETH tokens are identical and their value is the same.

There are also semi-fungible contracts (defined by the <mark style="color:blue;">ERC-1155 standard</mark>), which can be very useful for blockchain games, however, they are not fully supported by XpansionChain yet.

As you might expected, non-fungible token contracts produce non-fungible tokens (NFTs), fungible contracts produce fungible tokens and... well, you get the drift 😉

#### Key components of fungible and non-fungible token contracts:[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#key-components-of-fungible-and-non-fungible-token-contracts) <a href="#key-components-of-fungible-and-non-fungible-token-contracts" id="key-components-of-fungible-and-non-fungible-token-contracts"></a>

|                                                    | Fungible                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | Non-fungible                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Information stored about tokens                    | <p><em>How many tokens in total can this contract create?</em><br><br><strong>Contract function:</strong><br><code>totalSupply()</code> returns this value</p>                                                                                                                                                                                                                                                                                                                                                                                                    | <p><em>How many tokens in total can this contract create?</em><br><br><strong>Contract function (in </strong><mark style="color:blue;"><strong>ERC-721 enumerable</strong></mark><strong>, which is an extension of the ERC-721 standard):</strong><br><code>totalSupply()</code> returns total tokens in the contract</p><hr><p><em>Metadata containing each token's characteristics</em><br><br><strong>Contract function:</strong><br><code>tokenURI()</code> returns the URL with the metadata JSON containing the details of each token</p>     |
| Information stored about token ownership           | <p><em>How many tokens does a given user own?</em><br><br><strong>Contract function:</strong></p><ul><li>Mapping of <code>address -> token amount</code></li><li>Retrieved by calling <code>balanceOf(</code><em><code>address</code></em><code>)</code> which returns the number of tokens owned by this user</li></ul>                                                                                                                                                                                                                                          | <p><em>Who owns the token at a given token ID?</em><br><br><strong>Contract function:</strong></p><ul><li>Mapping of <code>token ID -> address</code></li><li>Retrieved by calling <code>ownerOf(</code><em><code>tokenID</code></em><code>)</code> that returns the address of the user who owns this token</li></ul>                                                                                                                                                                                                                               |
| What happens when the `mint()` function is called? | <ul><li>Function call <code>mint(</code><em><code>address</code></em><code>, </code><em><code>tokenAmount</code></em><code>)</code> is executed, which specifies the amount of tokens to mint for a particular user</li><li>When new tokens are minted, the <code>totalSupply</code> is decremented by the amount.</li><li>If the mint function is called with an amount of tokens to mint that exceeds the remaining total supply, then it will fail.</li><li>When minting is successful, the mapping <code>address -> token amount</code> is updated.</li></ul> | <ul><li>Function call <code>mint(</code><em><code>tokenID</code></em><code>, </code><em><code>address</code></em><code>)</code> is executed, which specifies the token ID to mint for a particular user.</li><li>It will then attempt to update mapping <code>token ID -> address</code>.</li><li>If the token ID already exists in the mapping (which means that a token has already been minted), then minting will fail.</li><li>If not, then a new token ID is created and the mapping updated with the address of the token ID owner.</li></ul> |

#### Other useful functions[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#other-useful-functions) <a href="#other-useful-functions" id="other-useful-functions"></a>

* `transfer(`_`tokenAmount`_`,`` `_`address`_`)` - which transfers a specified amount of tokens from the caller's account to another user's
* `approve(`_`address`_`,`` `_`tokenAmount`_`)` (fungible) / `approve(`_`address`_`,`` `_`tokenID`_`)` (non-fungible) - the caller may approve another user to spend or transfer tokens on their behalf

**For the full list of standard functions, see:**[**​**](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#for-the-full-list-of-standard-functions-see)

* <mark style="color:blue;">Fungible (ERC-20) token standard</mark>
* <mark style="color:blue;">Non-fungible (ERC-721) token standard</mark>

#### Example contract[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#example-contract) <a href="#example-contract" id="example-contract"></a>

Our <mark style="color:blue;">imx-contracts</mark> repo on GitHub contains some templates for smart contracts that are compatible with XpansionChain.

_**Asset.sol**_[**​**](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#assetsol)

<mark style="color:blue;">Asset.sol</mark> is an example of a non-fungible (ERC-721 standard) contract that contains the <mark style="color:blue;">functions required</mark> so that tokens can be minted from it on XpansionChain.

It implements the `_mintFor` function which is called when the asset is minted on L1 when it is withdrawn from XpansionChain to Ethereum (see step 4 <mark style="color:blue;">here</mark>). This function calls `_safeMint`, which is an inherited function from the <mark style="color:blue;">ERC-721 contract</mark> that <mark style="color:blue;">mints the NFT in a safe way</mark>.

Asset.sol

```
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
​
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "./Mintable.sol";
​
contract Asset is ERC721, Mintable {
    constructor(
        address _owner,
        string memory _name,
        string memory _symbol,
        address _imx
    ) ERC721(_name, _symbol) Mintable(_owner, _imx) {}
​
    function _mintFor(
        address user,
        uint256 id,
        bytes memory
    ) internal override {
        _safeMint(user, id);
    }
}
```

The <mark style="color:blue;">Mintable.sol</mark> contract that Asset.sol inherits from provides the token-minting functionality:

Mintable.sol

```
/ SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
​
import "@openzeppelin/contracts/access/Ownable.sol";
import "./IMintable.sol";
import "./utils/Minting.sol";
​
abstract contract Mintable is Ownable, IMintable {
    address public imx;
    mapping(uint256 => bytes) public blueprints;
​
    event AssetMinted(address to, uint256 id, bytes blueprint);
​
    constructor(address _owner, address _imx) {
        imx = _imx;
        require(_owner != address(0), "Owner must not be empty");
        transferOwnership(_owner);
    }
​
    modifier onlyIMX() {
        require(msg.sender == imx, "Function can only be called by IMX");
        _;
    }
​
    function mintFor(
        address user,
        uint256 quantity,
        bytes calldata mintingBlob
    ) external override onlyIMX {
        require(quantity == 1, "Mintable: invalid quantity");
        (uint256 id, bytes memory blueprint) = Minting.split(mintingBlob);
        _mintFor(user, id, blueprint);
        blueprints[id] = blueprint;
        emit AssetMinted(user, id, blueprint);
    }
​
    function _mintFor(
        address to,
        uint256 id,
        bytes memory blueprint
    ) internal virtual;
}
```

Things to note about the examples above:

* `owner` is the wallet address you choose to be the minter of the contract, so it should be a very safe, secure wallet.
* `transferOwnership(_owner)` does exactly as described, and transfers the ownership of the contract from the contract deployer to the specific wallet address.
* The address named `imx` refers to the XpansionChain contract address that is interacting with your smart contract to perform minting operations. You can find the address for each environment in the <mark style="color:blue;">README of the imx-contracts repository</mark>. This address is used in the `onlyIMX` modifier, which checks if the sender of the transaction is our contract or not. This is a way of whitelisting our contract and ensuring that no one else can mint assets through your smart contract.
* The `mintFor` function is called by the XpansionChain smart contract at the time of withdrawing the NFT to Ethereum. The function has the `onlyIMX` modifier, as explained above. Because you’re minting NFTs, which are unique, ensure that quantity = 1.
* The blueprint is saved as on-chain, XpansionChain metadata in the mapping blueprints. For custom blueprint decoding, you can override the mintFor function in Asset.sol to save it in something like tokenURI, or split the string into different components.
* The function emits an event `AssetMinted` when the mintFor completes successfully, and this can be listened on by applications.

### Fungible tokens[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#fungible-tokens) <a href="#fungible-tokens" id="fungible-tokens"></a>

#### Use cases[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#use-cases) <a href="#use-cases" id="use-cases"></a>

* **Staking:** This process allows individuals to lock specified amounts of their tokens to earn a yield. This is not available to all cryptocurrencies, and those who offer this operate under a Proof of Stake (PoS) consensus mechanism that requires specified amounts of a token to validate transactions.
* **Voting:** Holders of tokens are often offered voting rights by DAOs, also known as Decentralized Autonomous Organizations, who control ownership of certain token contracts. There are a variety of voting mechanisms, each outlining different requirements, however, it can generally be understood that the weight of a vote is proportional to the number of tokens owned.
* **User acquisition:** Many projects reward their community with their native tokens. This practice is common within many Web3 organizations, whereby constructive actions within an ecosystem may grant community members ecosystem rewards such as its native token.
* **Game rewards:** Many Web3 games are governed by a proprietary native token which they leverage to reward their users. These token rewards can then be spent to purchase items and cosmetics that help to drive the in-game economy.

Consider the IMX token: It has the potential to be <mark style="color:blue;">staked</mark>, used for <mark style="color:blue;">governance, trading rewards, developer incentivization</mark>, and in-game rewards as seen in its native projects such as <mark style="color:blue;">Gods Unchained</mark> and <mark style="color:blue;">Guild of Guardians.</mark>

#### Minting on XpansionChain[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#minting-on-immutable-x) <a href="#minting-on-immutable-x" id="minting-on-immutable-x"></a>

Currently, L2 minting of fungible tokens are not supported by XpansionChain. To transact with these tokens on L2, they must be minted first on L1 then <mark style="color:blue;">deposited</mark> to L2 to be used.

### Non-fungible tokens[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#non-fungible-tokens) <a href="#non-fungible-tokens" id="non-fungible-tokens"></a>

#### Use cases[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#use-cases-1) <a href="#use-cases-1" id="use-cases-1"></a>

* **Ownership:** Demonstrate authenticity and ownership of assets (artwork, fashion, licenses, certificates, collectibles).
* **Gaming:** In game assets can be tokenised enabling players to own their assets and exchange them with others.
* **Recurring revenue:** Capture royalties from every transaction after the initial sale. This benefits all creators including: artists, designers, musicians, developers.
* **Customer insight:** Access to transaction data of NFT owners within apps and across platforms.
* **Funding source:** Increase the scale of investments by enabling fans to coinvest in their favourite artists and projects. NFTs can also be leveraged to reward these users in the future.
* **New product lines:** Create and sell merchandise which can give access to unique and personalised experiences eg tickets for events, backstage passes.

#### Minting on XpansionChain[​](https://docs.x.immutable.com/docs/x/anatomy-smart-contract#minting-on-immutable-x-1) <a href="#minting-on-immutable-x-1" id="minting-on-immutable-x-1"></a>

You can mint NFTs on XpansionChain.

More information:

* For a conceptual overview, see <mark style="color:blue;">Deep dive into minting</mark>
* <mark style="color:blue;">Guide on how to use our API/SDKs to mint</mark>
* <mark style="color:blue;">Guide to how to use the command line to mint tokens from your own collection</mark>
