# Metadata Functionality

For implementation details on the Asset Library metadata functionality please see the [Sway Libs Docs](https://fuellabs.github.io/sway-libs/master/sway_libs/asset/asset/metadata/index.html).

## Importing the Asset Library Metadata Functionality

In order to use metadata functionality the Asset Library, the Asset Library and the [SRC-7](https://docs.fuel.network/docs/sway-standards/src-7-asset-metadata/) Standard must be added to your `Forc.toml` file and then imported into your Sway project.

To add the Asset Library and the [SRC-7](https://docs.fuel.network/docs/sway-standards/src-7-asset-metadata/) Standard as a dependency to your `Forc.toml` file in your project, use the `forc add` command.

```bash
forc add asset@0.26.0
forc add src7@0.8.0
```

> **NOTE:** Be sure to set the version to the latest release.

To import the Asset Library Base Functionality and [SRC-7](https://docs.fuel.network/docs/sway-standards/src-7-asset-metadata/) Standard to your Sway Smart Contract, add the following to your Sway file:

```sway
use asset::metadata::{_metadata, _set_metadata, SetAssetMetadata, StorageMetadata};
use src7::*;
```

## Integration with the SRC-7 Standard

The [SRC-7](https://docs.fuel.network/docs/sway-standards/src-7-asset-metadata/) definition states that the following abi implementation is required for any Native Asset on Fuel which uses stateful metadata:

```sway
abi SRC7 {
    #[storage(read)]
    fn metadata(asset: AssetId, key: String) -> Option<Metadata>;
}
```

The Asset Library has the following complimentary data type for the [SRC-7](https://docs.fuel.network/docs/sway-standards/src-7-asset-metadata/) standard:

- `StorageMetadata`

## Setting Up Storage

Once imported, the Asset Library's metadata functionality should be available. To use them, be sure to add the storage block below to your contract which enables the [SRC-7](https://docs.fuel.network/docs/sway-standards/src-7-asset-metadata/) standard.

```sway
storage {
    metadata: StorageMetadata = StorageMetadata {},
}
```

## Using the `StorageMetadata` Type

### Setting Metadata

As described in the [SRC-7](https://docs.fuel.network/docs/sway-standards/src-7-asset-metadata/) standard, the metadata type is a simple enum of the following types:

- `b256`
- `Bytes`
- `u64`
- `String`

To set some metadata of any of the above types for an Asset, you can use the `SetAssetMetadata` ABI provided by the Asset Library with the `_set_metadata()` function. Be sure to follow the [SRC-9](https://docs.fuel.network/docs/sway-standards/src-9-metadata-keys/) standard for your `key`. It is recommended that the [Ownership Library](../ownership/index.md) is used in conjunction with the `SetAssetMetadata` ABI to ensure only a single user has permissions to set an Asset's metadata.

The `_set_metadata()` function follows the SRC-7 standard for logging and will emit the `SetMetadataEvent` when called.

```sway
use asset::metadata::*;
use src7::Metadata;

storage {
    metadata: StorageMetadata = StorageMetadata {},
}

impl SetAssetMetadata for Contract {
    #[storage(read, write)]
    fn set_metadata(asset: AssetId, key: String, metadata: Metadata) {
        // add your authentication logic here
        // eg. only_owner()
        _set_metadata(storage.metadata, asset, key, metadata);
    }
}
abi CustomSetAssetMetadata {
    #[storage(read, write)]
    fn custom_set_metadata(
        asset: AssetId,
        key: String,
        bits256: b256,
        bytes: Bytes,
        int: u64,
        string: String,
    );
}

impl CustomSetAssetMetadata for Contract {
    #[storage(read, write)]
    fn custom_set_metadata(
        asset: AssetId,
        key: String,
        bits256: b256,
        bytes: Bytes,
        int: u64,
        string: String,
    ) {
        let b256_metadata = Metadata::B256(bits256);
        let bytes_metadata = Metadata::Bytes(bytes);
        let int_metadata = Metadata::Int(int);
        let string_metadata = Metadata::String(string);

        // your authentication logic here

        // set whichever metadata you want
        storage.metadata.insert(asset, key, string_metadata);
    }
}
```

> **NOTE** The `_set_metadata()` function will set the metadata of an asset *unconditionally*. External checks should be applied to restrict the setting of metadata.

To set the metadata of an Asset, using only one of the above types, you can define a custom ABI and use it as such:

```sway
abi CustomSetAssetMetadata {
    #[storage(read, write)]
    fn custom_set_metadata(
        asset: AssetId,
        key: String,
        bits256: b256,
        bytes: Bytes,
        int: u64,
        string: String,
    );
}

impl CustomSetAssetMetadata for Contract {
    #[storage(read, write)]
    fn custom_set_metadata(
        asset: AssetId,
        key: String,
        bits256: b256,
        bytes: Bytes,
        int: u64,
        string: String,
    ) {
        let b256_metadata = Metadata::B256(bits256);
        let bytes_metadata = Metadata::Bytes(bytes);
        let int_metadata = Metadata::Int(int);
        let string_metadata = Metadata::String(string);

        // your authentication logic here

        // set whichever metadata you want
        storage.metadata.insert(asset, key, string_metadata);
    }
}
```

> **NOTE** The `_set_metadata()` function will set the metadata of an asset *unconditionally*. External checks should be applied to restrict the setting of metadata.

### Implementing the SRC-7 Standard with StorageMetadata

To use the `StorageMetadata` type, simply get the stored metadata with the associated `key` and `AssetId` using the provided `_metadata()` convenience function. The example below shows the implementation of the [SRC-7](https://docs.fuel.network/docs/sway-standards/src-7-asset-metadata/) standard in combination with the Asset Library's `StorageMetadata` type and the `_metadata()` function with no user defined restrictions or custom functionality.

```sway
use asset::metadata::*;
use src7::{Metadata, SRC7};

storage {
    metadata: StorageMetadata = StorageMetadata {},
}

// Implement the SRC-7 Standard for this contract
impl SRC7 for Contract {
    #[storage(read)]
    fn metadata(asset: AssetId, key: String) -> Option<Metadata> {
        // Return the stored metadata
        storage.metadata.get(asset, key)
    }
}
```

### Getting Metadata

To get the metadata for an asset, apart from the above mentioned `_metadata()` convenience function, you can also use the `get()` method on the `StorageMetadata` type, which returns the `Metadata` type.

```sway
    use asset::metadata::*; // To access trait implementations you must import everything using the glob operator.
    let metadata: Option<Metadata> = storage.metadata.get(asset, key);
    match metadata.unwrap() {
        Metadata::B256(b256) => {
        // do something with b256
},
        Metadata::Bytes(bytes) => {
        // do something with bytes
},
        Metadata::Int(int) => {
        // do something with int
},
        Metadata::String(string) => {
        // do something with string
},
    }
    let metadata: Metadata = storage.metadata.get(asset, key).unwrap();

    if metadata.is_b256() {
        let b256: b256 = metadata.as_b256().unwrap();
        // do something with b256
    } else if metadata.is_bytes() {
        let bytes: Bytes = metadata.as_bytes().unwrap();
        // do something with bytes
    } else if metadata.is_u64() {
        let int: u64 = metadata.as_u64().unwrap();
        // do something with int
    } else if metadata.is_string() {
        let string: String = metadata.as_string().unwrap();
        // do something with string
    }
```

This results an `Option` type as the metadata may not be set for the asset and key combination.

If you know that the metadata is set, but you don't know the type, you can use a match statement to access the metadata.

```sway
    match metadata.unwrap() {
        Metadata::B256(b256) => {
        // do something with b256
},
        Metadata::Bytes(bytes) => {
        // do something with bytes
},
        Metadata::Int(int) => {
        // do something with int
},
        Metadata::String(string) => {
        // do something with string
},
    }
```

If you know that the metadata is set and you know the type, you can use the `as_*` methods to access the metadata. We also provide `is_*` methods to check if the metadata is of a specific type.

```sway
    let metadata: Metadata = storage.metadata.get(asset, key).unwrap();

    if metadata.is_b256() {
        let b256: b256 = metadata.as_b256().unwrap();
        // do something with b256
    } else if metadata.is_bytes() {
        let bytes: Bytes = metadata.as_bytes().unwrap();
        // do something with bytes
    } else if metadata.is_u64() {
        let int: u64 = metadata.as_u64().unwrap();
        // do something with int
    } else if metadata.is_string() {
        let string: String = metadata.as_string().unwrap();
        // do something with string
    }
```
