Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create the asset_id.sw file and move AssetId out of contract_id.sw #5439

Merged
merged 5 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 1 addition & 84 deletions sway-lib-std/src/address.sw
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
//! A wrapper around the `b256` type to help enhance type-safety.
library;

use ::alias::SubId;
use ::call_frames::contract_id;
use ::contract_id::AssetId;
use ::convert::From;
use ::hash::*;
use ::error_signals::FAILED_TRANSFER_TO_ADDRESS_SIGNAL;
use ::hash::sha256;
use ::revert::revert;
use ::outputs::{Output, output_amount, output_count, output_type};
use ::hash::{Hash, Hasher};

/// The `Address` type, a struct wrapper around the inner `b256` value.
pub struct Address {
Expand Down Expand Up @@ -70,82 +63,6 @@ impl From<b256> for Address {
}
}

impl Address {
/// Transfer `amount` coins of type `asset_id` and send them to
/// the Address.
///
/// # Arguments
///
/// * `asset_id`: [AssetId] - The `AssetId` of the token to transfer.
/// * `amount`: [u64] - The amount of tokens to transfer.
///
/// # Reverts
///
/// * When `amount` is greater than the contract balance for `asset_id`.
/// * When `amount` is equal to zero.
/// * When there are no free variable outputs.
///
/// # Examples
///
/// ```sway
/// use std::constants::{BASE_ASSET_ID, ZERO_B256};
///
/// fn foo() {
/// let address = Address::from(ZERO_B256);
/// address.transfer(BASE_ASSET_ID, 500);
/// }
/// ```
pub fn transfer(self, asset_id: AssetId, amount: u64) {
// maintain a manual index as we only have `while` loops in sway atm:
let mut index = 0;

// If an output of type `OutputVariable` is found, check if its `amount` is
// zero. As one cannot transfer zero coins to an output without a panic, a
// variable output with a value of zero is by definition unused.
let number_of_outputs = output_count();
while index < number_of_outputs {
if let Output::Variable = output_type(index) {
if output_amount(index) == 0 {
asm(r1: self.value, r2: index, r3: amount, r4: asset_id.value) {
tro r1 r2 r3 r4;
};
return;
}
}
index += 1;
}

revert(FAILED_TRANSFER_TO_ADDRESS_SIGNAL);
}
}

impl Address {
/// Mint `amount` coins of the current contract's `asset_id` and send them to
/// the Address.
///
/// # Arguments
///
/// * `sub_id`: [SubId] - The sub id of the token to mint.
/// * `amount`: [u64] - The amount of tokens to mint.
///
/// # Examples
///
/// ```sway
/// use std::constants::ZERO_B256;
///
/// fn foo() {
/// let address = Address::from(ZERO_B256);
/// address.mint_to(ZERO_B256, 500);
/// }
/// ```
pub fn mint_to(self, sub_id: SubId, amount: u64) {
asm(r1: amount, r2: sub_id) {
mint r1 r2;
};
self.transfer(AssetId::new(contract_id(), sub_id), amount);
}
}

impl Hash for Address {
fn hash(self, ref mut state: Hasher) {
let Address { value } = self;
Expand Down
216 changes: 216 additions & 0 deletions sway-lib-std/src/asset_id.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
library;

use ::alias::SubId;
use ::contract_id::ContractId;
use ::convert::From;
use ::hash::{Hash, Hasher};

/// An AssetId is used for interacting with an asset on the network.
///
/// # Additional Information
///
/// It is calculated by taking the sha256 hash of the originating ContractId and a SubId.
/// i.e. sha256((contract_id, sub_id)).
///
/// An exception is the Base Asset, which is just the ZERO_B256 AssetId.
///
/// The SubId is used to differentiate between different assets that are created by the same contract.
pub struct AssetId {
value: b256,
}

impl Hash for AssetId {
fn hash(self, ref mut state: Hasher) {
let Self { value } = self;
value.hash(state);
}
}

impl core::ops::Eq for AssetId {
fn eq(self, other: Self) -> bool {
self.value == other.value
}
}

impl From<b256> for AssetId {
/// Casts raw `b256` data to an `AssetId`.
///
/// # Arguments
///
/// * `bits`: [b256] - The raw `b256` data to be casted.
///
/// # Returns
///
/// * [AssetId] - The newly created `AssetId` from the raw `b256`.
///
/// # Examples
///
/// ```sway
/// use std::constants::ZERO_B256;
///
/// fn foo() {
/// let asset_id = AssetId::from(ZERO_B256);
/// }
/// ```
fn from(bits: b256) -> Self {
Self { value: bits }
}

/// Casts an `AssetId` to raw `b256` data.
///
/// # Returns
///
/// * [b256] - The underlying raw `b256` data of the `AssetId`.
///
/// # Examples
///
/// ```sway
/// use std::constants::ZERO_B256;
///
/// fn foo() {
/// let asset_id = AssetId::from(ZERO_B256);
/// let b256_data = asset_id.into();
/// assert(b256_data == ZERO_B256);
/// }
/// ```
fn into(self) -> b256 {
self.value
}
}

impl AssetId {
/// Creates a new AssetId from a ContractId and SubId.
///
/// # Arguments
///
/// * `contract_id`: [ContractId] - The ContractId of the contract that created the asset.
/// * `sub_id`: [SubId] - The SubId of the asset.
///
/// # Returns
///
/// * [AssetId] - The AssetId of the asset. Computed by hashing the ContractId and SubId.
///
/// # Examples
///
/// ```sway
/// use std::{callframes::contract_id, constants::ZERO_B256};
///
/// fn foo() {
/// let contract_id = contract_id();
/// let sub_id = ZERO_B256;
///
/// let asset_id = AssetId::new(contract_id, sub_id);
/// }
/// ```
pub fn new(contract_id: ContractId, sub_id: SubId) -> Self {
let result_buffer = 0x0000000000000000000000000000000000000000000000000000000000000000;
asm(
asset_id: result_buffer,
ptr: (contract_id, sub_id),
bytes: 64,
) {
s256 asset_id ptr bytes;
};

Self {
value: result_buffer,
}
}

/// Creates a new AssetId with the default SubId for the current contract.
///
/// # Returns
///
/// * [AssetId] - The AssetId of the asset. Computed by hashing the ContractId and the default SubId.
///
/// # Examples
///
/// ```sway
/// use std::{callframes::contract_id, constants::DEFAULT_SUB_ID};
///
/// fn foo() {
/// let asset_id = AssetId::default();
/// assert(asset_id == AssetId::new(contract_id(), DEFAULT_SUB_ID));
/// }
/// ```
pub fn default() -> Self {
let contract_id = asm() {
fp: b256
};
let result_buffer = 0x0000000000000000000000000000000000000000000000000000000000000000;
asm(
asset_id: result_buffer,
ptr: (
contract_id,
0x0000000000000000000000000000000000000000000000000000000000000000,
),
bytes: 64,
) {
s256 asset_id ptr bytes;
};

Self {
value: result_buffer,
}
}

/// The base_asset_id represents the base asset of a chain.
///
/// # Additional Information
///
/// On the Fuel network, the base asset is Ether. It is hardcoded as the 0x00..00 AssetId.
///
/// # Returns
///
/// * [AssetId] - The AssetId of the base asset.
///
/// # Examples
///
/// ```sway
/// use std::{constants::ZERO_B256, token::transfer};
///
/// fn foo() {
/// let asset_id = AssetId::base_asset_id();
/// let amount = 100;
/// let recipient = Identity::ContractId(ContractId::from(ZERO_B256));
///
/// transfer(recipient, asset_id, amount);
/// ```
pub fn base_asset_id() -> Self {
Self {
value: 0x0000000000000000000000000000000000000000000000000000000000000000,
}
}
}

#[test()]
fn test_hasher_sha256_asset_id() {
use ::assert::assert;
let mut hasher = Hasher::new();
AssetId::from(0x0000000000000000000000000000000000000000000000000000000000000000)
.hash(hasher);
let s256 = hasher.sha256();
assert(s256 == 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925);

let mut hasher = Hasher::new();
AssetId::from(0x0000000000000000000000000000000000000000000000000000000000000001)
.hash(hasher);
let s256 = hasher.sha256();
assert(s256 == 0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5);
}

#[test()]
fn test_hasher_sha256_contract_id() {
use ::assert::assert;
let mut hasher = Hasher::new();
ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000000)
.hash(hasher);
let s256 = hasher.sha256();
assert(s256 == 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925);

let mut hasher = Hasher::new();
ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000001)
.hash(hasher);
let s256 = hasher.sha256();
assert(s256 == 0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5);
}
3 changes: 2 additions & 1 deletion sway-lib-std/src/call_frames.sw
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//! [Call frames](https://fuellabs.github.io/fuel-specs/master/vm#call-frames) store metadata across untrusted inter-contract calls.
library;

use ::contract_id::{AssetId, ContractId};
use ::asset_id::AssetId;
use ::contract_id::ContractId;
use ::intrinsics::is_reference_type;
use ::registers::frame_ptr;

Expand Down
2 changes: 1 addition & 1 deletion sway-lib-std/src/constants.sw
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Base asset and zero address constants.
library;

use ::contract_id::AssetId;
use ::asset_id::AssetId;

/// The `BASE_ASSET_ID` represents the base asset of a chain.
///
Expand Down
3 changes: 2 additions & 1 deletion sway-lib-std/src/context.sw
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Functionality for accessing context-specific information about the current contract or message.
library;

use ::asset_id::AssetId;
use ::call_frames::contract_id;
use ::contract_id::{AssetId, ContractId};
use ::contract_id::ContractId;
use ::registers::balance;

/// Get the balance of coin `asset_id` for the current contract.
Expand Down
Loading
Loading