Skip to content

Commit

Permalink
Merge master into SRC16 branch, up to version 0.6.2, commit 3f6543f.
Browse files Browse the repository at this point in the history
  • Loading branch information
CatspersCoffee committed Dec 15, 2024
2 parents cb0324c + 3f6543f commit df8a3d8
Show file tree
Hide file tree
Showing 17 changed files with 505 additions and 17 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ jobs:
"examples/src11-security-information",
"examples/src12-contract-factory",
"examples/src14-simple-proxy",
"examples/src15-offchain-metadata",
"examples/src20-native-asset",
]

Expand Down
17 changes: 14 additions & 3 deletions .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@ on:
pull_request:

jobs:
test:
spell-check:
name: Spell Check
uses: FuelLabs/github-actions/.github/workflows/mdbook-docs.yml@master
with:
docs-src-path: 'docs/src'
spellcheck-config-path: 'docs/.spellcheck.yml'
docs-src-path: "docs/src"
spellcheck-config-path: "docs/.spellcheck.yml"

link-check:
name: Link Check
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Run Markdown Link Check
uses: gaurav-nelson/github-action-markdown-link-check@1.0.15
42 changes: 33 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,55 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

Description of the upcoming release here.

### Added

- [#152](https://github.com/FuelLabs/sway-standards/pull/152) Adds inline documentation examples to the SRC-6 standard.
- Something new here 1
- Something new here 2

### Changed

- Something changed here 1
- Something changed here 2

### Fixed

- Some fix here 1
- Some fix here 2

### Breaking

- Some breaking change here 1
- Some breaking change here 2

## [Version 0.6.2]

### New Standards v0.6.2

- [#159](https://github.com/FuelLabs/sway-standards/pull/159) Defines the SRC-15; Offchain Metadata Standard.

### Added v0.6.2

- [#152](https://github.com/FuelLabs/sway-standards/pull/152) Adds inline documentation examples to the SRC-6 standard.
- [#159](https://github.com/FuelLabs/sway-standards/pull/159) Adds the SRC-15 standard files and docs.
- [#162](https://github.com/FuelLabs/sway-standards/pull/162) Adds link checker to CI.

### Changed v0.6.2

- [#154](https://github.com/FuelLabs/sway-standards/pull/154) Updates the examples in the standards specififcations to use the offical abi name.
- [#157](https://github.com/FuelLabs/sway-standards/pull/157) Updates the name of the SRC-7 standard to "Onchain Native Asset Metadata Standard".
- [#163](https://github.com/FuelLabs/sway-standards/pull/163) Prepares for the v0.6.2 release.

### Fixed
### Fixed v0.6.2

- [#153](https://github.com/FuelLabs/sway-standards/pull/153) Actually write to storage in `set_src20_data()` in the SRC-20 multi asset example.
- [#160](https://github.com/FuelLabs/sway-standards/pull/160) Fixes a typo in the SRC-7 inline docs.

#### Breaking
#### Breaking v0.6.2

- Some breaking change here 1
- Some breaking change here 2
- None

## [Version 0.6.1]

Description of the upcoming release here.

### Added v0.6.1

- [#149](https://github.com/FuelLabs/sway-standards/pull/149) Adds struct field getters, `new()`, and `Eq` implementations to SRC-10's `DepositMessage` and `MetadataMessage` types and SRC-11's `SecurityInformation` type.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[package]
name = "sway-standards"
version = "0.6.1"
version = "0.6.2"
edition = "2021"
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
</p>

<p align="center">
<a href="https://github.com/FuelLabs/sway-standards/actions/workflows/ci.yml" alt="CI">
<img src="https://github.com/FuelLabs/sway-standards/actions/workflows/ci.yml/badge.svg" />
<a href="https://github.com/FuelLabs/sway-standards/actions/workflows/ci.yaml" alt="CI">
<img src="https://github.com/FuelLabs/sway-standards/actions/workflows/ci.yaml/badge.svg" />
</a>
<a href="https://crates.io/crates/forc/0.63.3" alt="forc">
<img src="https://img.shields.io/badge/forc-v0.63.3-orange" />
Expand Down Expand Up @@ -65,7 +65,7 @@ If you don't find what you're looking for, feel free to create an issue and prop
To import a standard the following should be added to the project's `Forc.toml` file under `[dependencies]` with the most recent release:

```toml
standards = { git = "https://github.com/FuelLabs/sway-standards", tag = "v0.6.1" }
standards = { git = "https://github.com/FuelLabs/sway-standards", tag = "v0.6.2" }
```

> **NOTE:**
Expand Down
3 changes: 3 additions & 0 deletions docs/spell-check-custom-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,6 @@ SetDecimalsEvent
UpdateTotalSupplyEvent
Onchain
onchain
Offchain
offchain
MetadataEvent
1 change: 1 addition & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
- [SRC-12: Contract Factory](./src-12-contract-factory.md)
- [SRC-13: Soulbound Address](./src-13-soulbound-address.md)
- [SRC-14: Simple Upgradeable Contract](./src-14-simple-upgradeable-proxies.md)
- [SRC-15: Offchain Asset Metadata](./src-15-offchain-asset-metadata.md)
- [SRC-16: Typed Structured Data](./src-16-typed-structured-data.md)
- [SRC-20: Native Asset](./src-20-native-asset.md)
3 changes: 2 additions & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ If you don't find what you're looking for, feel free to create an issue and prop
To import a standard the following should be added to the project's `Forc.toml` file under `[dependencies]` with the most recent release:

```toml
standards = { git = "https://github.com/FuelLabs/sway-standards", tag = "v0.6.1" }
standards = { git = "https://github.com/FuelLabs/sway-standards", tag = "v0.6.2" }
```

> **NOTE:**
Expand Down Expand Up @@ -42,6 +42,7 @@ use standards::src20::SRC20;
- [SRC-9; Metadata Keys Standard](./src-9-metadata-keys.md) is used to store standardized metadata keys for [Native Assets](https://docs.fuel.network/docs/sway/blockchain-development/native_assets) in combination with the SRC-7 standard.
- [SRC-6; Vault Standard](./src-6-vault.md) defines the implementation of a standard API for asset vaults developed in Sway.
- [SRC-13; Soulbound Address](./src-13-soulbound-address.md) defines the implementation of a soulbound address.
- [SRC-15; Offchain Asset Metadata Standard](./src-15-offchain-asset-metadata.md) is used to associated metadata with [Native Assets](https://docs.fuel.network/docs/sway/blockchain-development/native_assets) offchain.

### Security and Access Control

Expand Down
73 changes: 73 additions & 0 deletions docs/src/src-15-offchain-asset-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# SRC-15: Off-Chain Native Asset Metadata

The following standard attempts to define arbitrary metadata for any [Native Asset](https://docs.fuel.network/docs/sway/blockchain-development/native_assets) that is not required by other contracts onchain, in a stateless manner. Any contract that implements the SRC-15 standard MUST implement the [SRC-20](./src-20-native-asset.md) standard.

## Motivation

The SRC-15 standard seeks to enable data-rich assets on the Fuel Network while maintaining a stateless solution. All metadata queries are done off-chain using the indexer.

## Prior Art

The SRC-7 standard exists prior to the SRC-15 standard and is a stateful solution. The SRC-15 builds off the SRC-7 standard by using the `Metadata` enum however provides a stateless solution.

The use of generic metadata was originally found in the Sway-Lib's [NFT Library](https://github.com/FuelLabs/sway-libs/tree/v0.12.0/libs/nft) which did not use Fuel's [Native Assets](https://docs.fuel.network/docs/sway/blockchain-development/native_assets). This library has since been deprecated.

A previous definition for a metadata standard was written in the original edit of the now defunct [SRC-721](https://github.com/FuelLabs/sway-standards/issues/2). This has since been replaced with the [SRC-20](./src-20-native-asset.md) standard as `SubId` was introduced to enable multiple assets to be minted from a single contract.

## Specification

### Metadata Type

The `Metadata` enum from the SRC-7 standard is also used to represent the metadata in the SRC-15 standard.

### Logging

The following logs MUST be implemented and emitted to follow the SRC-15 standard. Logging MUST be emitted from the contract which minted the asset.

#### SRC15MetadataEvent

The `SRC15MetadataEvent` MUST be emitted at least once for each distinct piece of metadata. The latest emitted `SRC15MetadataEvent` is determined to be the current metadata.

There SHALL be the following fields in the `SRC15MetadataEvent` struct:

* `asset`: The `asset` field SHALL be used for the corresponding `AssetId` for the metadata.
* `metadata`: The `metadata` field SHALL be used for the corresponding `Metadata` which represents the metadata of the asset.

Example:

```sway
pub struct SRC15MetadataEvent {
pub asset: AssetId,
pub metadata: Metadata,
}
```

## Rationale

The SRC-15 standard allows for data-rich assets in a stateless manner by associating an asset with some metadata that may later be fetched by the indexer.

## Backwards Compatibility

This standard is compatible with Fuel's [Native Assets](https://docs.fuel.network/docs/sway/blockchain-development/native_assets) and the [SRC-20](./src-20-native-asset.md) standard. This standard is also compatible with the SRC-7 standard which defines a stateful solution. It also maintains compatibility with existing standards in other ecosystems.

## Security Considerations

When indexing for SRC-15 metadata, developers should confirm that the contract that emitted the `SRC15MetadataEvent` is also the contract that minted the asset that the metadata associates with. Additionally, restrictions via access control on who may emit the Metadata should be considered.

## Example Implementation

### Single Native Asset

Example of the SRC-15 implementation where metadata exists for only a single asset with one `SubId`.

```sway
{{#include ../examples/src15-offchain-metadata/single_asset/src/single_asset.sw}}
```

### Multi Native Asset

Example of the SRC-15 implementation where metadata exists for multiple assets with differing `SubId` values.

```sway
{{#include ../examples/src15-offchain-metadata/multi_asset/src/multi_asset.sw}}
```
2 changes: 2 additions & 0 deletions examples/src15-offchain-metadata/Forc.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[workspace]
members = ["single_asset", "multi_asset"]
8 changes: 8 additions & 0 deletions examples/src15-offchain-metadata/multi_asset/Forc.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "multi_asset.sw"
license = "Apache-2.0"
name = "multi_src15_asset"

[dependencies]
standards = { path = "../../../standards" }
123 changes: 123 additions & 0 deletions examples/src15-offchain-metadata/multi_asset/src/multi_asset.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
contract;

use standards::{
src15::{
SRC15MetadataEvent,
},
src20::{
SetDecimalsEvent,
SetNameEvent,
SetSymbolEvent,
SRC20,
TotalSupplyEvent,
},
src7::{
Metadata,
},
};

use std::{hash::Hash, storage::storage_string::*, string::String};

// In this example, all assets minted from this contract have the same decimals, name, and symbol
configurable {
/// The decimals of every asset minted by this contract.
DECIMALS: u8 = 0u8,
/// The name of every asset minted by this contract.
NAME: str[7] = __to_str_array("MyAsset"),
/// The symbol of every asset minted by this contract.
SYMBOL: str[5] = __to_str_array("MYAST"),
/// The metadata for the "social:x" key.
SOCIAL_X: str[12] = __to_str_array("fuel_network"),
/// The metadata for the "site:forum" key.
SITE_FORUM: str[27] = __to_str_array("https://forum.fuel.network/"),
}

storage {
/// The total number of distinguishable assets this contract has minted.
total_assets: u64 = 0,
/// The total supply of a particular asset.
total_supply: StorageMap<AssetId, u64> = StorageMap {},
}

abi EmitSRC15Events {
#[storage(read)]
fn emit_src15_events(asset: AssetId, svg_image: String, health_attribute: u64);
}

impl EmitSRC15Events for Contract {
#[storage(read)]
fn emit_src15_events(asset: AssetId, svg_image: String, health_attribute: u64) {
// NOTE: There are no checks for if the caller has permissions to emit the metadata
// NOTE: Nothing is stored in storage and there is no method to retrieve the configurables.

// If this asset does not exist, revert
if storage.total_supply.get(asset).try_read().is_none() {
revert(0);
}

let metadata_1 = Metadata::String(String::from_ascii_str(from_str_array(SOCIAL_X)));
let metadata_2 = Metadata::String(String::from_ascii_str(from_str_array(SITE_FORUM)));
let metadata_3 = Metadata::String(svg_image);
let metadata_4 = Metadata::Int(health_attribute);

SRC15MetadataEvent::new(asset, metadata_1).log();
SRC15MetadataEvent::new(asset, metadata_2).log();
SRC15MetadataEvent::new(asset, metadata_3).log();
SRC15MetadataEvent::new(asset, metadata_4).log();
}
}

// SRC15 extends SRC20, so this must be included
impl SRC20 for Contract {
#[storage(read)]
fn total_assets() -> u64 {
storage.total_assets.read()
}

#[storage(read)]
fn total_supply(asset: AssetId) -> Option<u64> {
storage.total_supply.get(asset).try_read()
}

#[storage(read)]
fn name(asset: AssetId) -> Option<String> {
match storage.total_supply.get(asset).try_read() {
Some(_) => Some(String::from_ascii_str(from_str_array(NAME))),
None => None,
}
}

#[storage(read)]
fn symbol(asset: AssetId) -> Option<String> {
match storage.total_supply.get(asset).try_read() {
Some(_) => Some(String::from_ascii_str(from_str_array(SYMBOL))),
None => None,
}
}

#[storage(read)]
fn decimals(asset: AssetId) -> Option<u8> {
match storage.total_supply.get(asset).try_read() {
Some(_) => Some(DECIMALS),
None => None,
}
}
}

abi EmitSRC20Data {
fn emit_src20_data(asset: AssetId, total_supply: u64);
}

impl EmitSRC20Data for Contract {
fn emit_src20_data(asset: AssetId, supply: u64) {
// NOTE: There are no checks for if the caller has permissions to update the metadata
let sender = msg_sender().unwrap();
let name = Some(String::from_ascii_str(from_str_array(NAME)));
let symbol = Some(String::from_ascii_str(from_str_array(SYMBOL)));

SetNameEvent::new(asset, name, sender).log();
SetSymbolEvent::new(asset, symbol, sender).log();
SetDecimalsEvent::new(asset, DECIMALS, sender).log();
TotalSupplyEvent::new(asset, supply, sender).log();
}
}
8 changes: 8 additions & 0 deletions examples/src15-offchain-metadata/single_asset/Forc.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "single_asset.sw"
license = "Apache-2.0"
name = "single_src15_asset"

[dependencies]
standards = { path = "../../../standards" }
Loading

0 comments on commit df8a3d8

Please sign in to comment.