FuelLabs/sway-standards

SRC-8; Bridged Asset Standard

bitzoic opened this issue · 5 comments

Abstract

The following standard attempts to define the retrieval of relevant on-chain metadata for any bridged Native Assets. Any contract that implements the SRC-8 standard MUST implement the SRC-7 standard.

Motivation

The SRC-8 standard seeks to enable relevant data for bridged assets on the Fuel Network. This data includes the origin chain, address, ID, decimals, and any arbitrary data. All metadata queries are done through a single function to facilitate cross-contract calls.

Prior Art

The use of generic metadata for Native Assets is defined in the SRC-7 standard. This standard integrates into the existing SRC-7 standard.

Specification

Token Creation

The SubId of the token MUST be the digest of the sha256(origin_chain_id, origin_asset_address, origin_asset_id) hash where:

  • origin_chain_id is a u64 of the chain ID where the asset was originally minted.
  • origin_asset_address is a b256 of the asset's address on the chain where the asset was originally minted.
  • origin_asset_id is a b256 of the asset's ID on the chain where the asset was originally minted. IF there is no ID, ZERO_B256 SHALL be used.

SRC-20 Metadata

Any bridged assets MUST use the name and symbol of the asset on the chain where the asset was originally minted.

SRC-7 Metadata

- origin_chain

The key origin_chain SHALL return an Int variant the chain ID where the asset was originally minted.

- origin_asset_address

The key origin_asset_address SHALL return a B256 variant of the asset's address on the chain where the asset was originally minted.

- origin_asset_id

The key origin_asset_id MAY return a B256 variant of the asset's ID on the chain where the asset was originally minted. IF there is no ID, None SHALL be returned.

- origin_asset_decimals

The key origin_decimals MAY return an Int variant of the asset's decimals on the chain where the asset was originally minted. IF there are no decimals, None SHALL be returned.

- origin_asset_data

The key origin_asset_data MAY return any arbitrary Metadata of the asset's data that exists on the chain where the asset was originally minted. IF there is no data, None SHALL be returned.

Rationale

The SRC-8 standard should allow for data on any bridged assets on the Fuel Network. This standard builds off existing standards and should allow other contracts to query any relevant information on the bridged asset.

Backwards Compatibility

This standard is compatible with Fuel's Native Assets, the SRC-20 standard, and the SRC-7 standard.

The standard is also compatible with both tokens and NFTs native to other ecosystems by introducing a token ID element of the original chain.

Security Considerations

There is no guarantee that any data returned from the origin_asset_data key is up to date with the data on the origin chain.

This standard does not call external contracts, nor does it define any mutations of the contract state.

Example

impl SRC7 for Contract {
     fn metadata(asset: AssetId, key: String) -> Option<Metadata> {
          if (asset != AssetId::from(ZERO_B256)) {
               return Option::None();
          }

          match key {
                String::from_ascii_str("origin_chain") => {
                     Option::Some(Metadata::Int(1))
                },
                String::from_ascii_str("origin_asset_address") => {
                     let origin_asset_address = ZERO_B256;
                     Option::Some(Metadata::B256(origin_asset_address))
                },
                String::from_ascii_str("origin_asset_id") => {
                     let origin_asset_id = ZERO_B256;
                     Option::Some(Metadata::B256(origin_asset_id))
                },
                String::from_ascii_str("origin_asset_decimals") => {
                     Option::Some(Metadata::Int(1))
                },
                String::from_ascii_str("origin_asset_data") => {
                     let origin_asset_data = String::from_ascii_str("My Data");
                     Option::Some(Metadata::StringData(origin_asset_data))
                },
                _ => Option::None(),
           }
     }
}

impl SRC20 for Contract {
     fn total_assets() -> u64 {
          1
      }         

     fn total_supply(asset: AssetId) -> Option<u64> {
          match asset { 
               AssetId::from(ZERO_B256)) => Option::Some(1),
               _ => Option::None(),
          }
     }

     fn name(asset: AssetId) -> Option<String> {
          match asset { 
               AssetId::from(ZERO_B256)) => Option::Some(String::from_ascii_str("Name")),
               _ => Option::None(),
          }
     }

     fn symbol(asset: AssetId) -> Option<String> {
          match asset { 
               AssetId::from(ZERO_B256)) => Option::Some(String::from_ascii_str("Symbol")),
               _ => Option::None(),
          }
     }

     fn decimals(asset: AssetId) -> Option<u8> {
          match asset { 
               AssetId::from(ZERO_B256)) => Option::Some(0u8),
               _ => Option::None(),
          }
     }
}
K1-R1 commented

Looks good some initial feedback:

  • Links to SRC-7 give file not found : the [SRC-7](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_7) standard.
  • origin_asset_id is a u64 of the asset's ID on the chain where the asset was originally minted. IF there is no ID, 0u64 SHALL be used. Is it worth considering this value being an Option< u64 >; to distinguish between a fungible token (id None) and an NFT with an id of 0? Where this Option is used in the hash to create the SubId.
  • In the example; consider changing the order of impl blocks so that it's clear that theres only 1 asset when reading the if statement in the impl SRC7 block

Few things that come to my mind:

  • origin_asset_id -> this should be B256 / U256. An example of this would be ERC721 or ERC1155, where the ID of the non-fungible / fungible assets is an uint256 - this is just for the SubId = sha256(origin_chain_id, origin_asset_address, origin_asset_id). The metadata could fit in a BytesData type I guess, though we could consider adding another type b256 for SRC-7.
  • What 's the rationale behind making the origin_asset_decimals a BytesData? I need to reread the standards for fungible assets, but I think they are an uint8, for the cases they implement it.
  • wrt origin_chain_id, I am not sure what is the spec for EVM and non-EVMs. I would double check that we do not limit the size of this one as well, you never know when a funky chain can use something like the max of uint256 as chain ID.

Looks good some initial feedback:

  • Links to SRC-7 give file not found : the [SRC-7](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_7) standard.

This link will not work until the SRC-7 PR is merged.

  • origin_asset_id is a u64 of the asset's ID on the chain where the asset was originally minted. IF there is no ID, 0u64 SHALL be used. Is it worth considering this value being an Option< u64 >; to distinguish between a fungible token (id None) and an NFT with an id of 0? Where this Option is used in the hash to create the SubId.

There is no Hash trait implemented on an Option<T>. This may be possible in the future but serialization/deserialization would be needed.

  • In the example; consider changing the order of impl blocks so that it's clear that theres only 1 asset when reading the if statement in the impl SRC7 block

Could you elaborate on this? The match statement is also a return statement and the if block just ensures any random AssetId isn't passed.

  • origin_asset_id -> this should be B256 / U256. An example of this would be ERC721 or ERC1155, where the ID of the non-fungible / fungible assets is an uint256 - this is just for the SubId = sha256(origin_chain_id, origin_asset_address, origin_asset_id). The metadata could fit in a BytesData type I guess, though we could consider adding another type b256 for SRC-7.

I have considered adding a b256 to the SRC-7 standard as I think this would be a frequently used type. I was looking to get some feedback before adding this. I can also make the change to a b256.

  • What 's the rationale behind making the origin_asset_decimals a BytesData? I need to reread the standards for fungible assets, but I think they are an uint8, for the cases they implement it.

This is a typo. It should be a IntData type.

  • wrt origin_chain_id, I am not sure what is the spec for EVM and non-EVMs. I would double check that we do not limit the size of this one as well, you never know when a funky chain can use something like the max of uint256 as chain ID.

I am also unsure what the spec calls for in this case. Perhaps this is a good use case of the newly added u256 type.

K1-R1 commented

Could you elaborate on this? The match statement is also a return statement and the if block just ensures any random AssetId isn't passed.

only a nit; I just meant to switch the order of impl blocks so that SRC20 is impl'd first. Perhaps it was just a smooth brain moment but it didn't click until I saw the SRC20 block what the purpose of the if block in impl SRC7 was.

impl SRC20 for Contract {
     ...
}

impl SRC7 for Contract {
    ...
}