From b9970a168d6bb77d0e03ae1d665e2e1d2d44bced Mon Sep 17 00:00:00 2001 From: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:10:49 +0700 Subject: [PATCH] Formalize Asset and Coin Terminology in Sway Apps (#772) ## Type of change - Improvement (refactoring, restructuring repository, cleaning tech debt, ...) ## Changes The following changes have been made: - This PR is a continuation of https://github.com/FuelLabs/sway/pull/5461 where the terms "Asset" and "Coin" have been defined and formalized in the Sway lang --- .devops/aurora/apps.txt | 2 +- .../documentation/specification.md | 2 +- .github/workflows/ci.yml | 2 +- DAO/README.md | 2 +- DAO/project/SPECIFICATION.md | 22 ++++----- .../contracts/DAO-contract/src/events.sw | 8 ++-- .../contracts/DAO-contract/src/interface.sw | 44 +++++++++--------- .../contracts/DAO-contract/src/main.sw | 24 +++++----- .../tests/functions/core/constructor.rs | 18 +++---- .../tests/functions/core/create_proposal.rs | 30 ++++++------ .../tests/functions/core/deposit.rs | 22 ++++----- .../tests/functions/core/execute.rs | 34 +++++++------- .../tests/functions/core/unlock_votes.rs | 40 ++++++++-------- .../DAO-contract/tests/functions/core/vote.rs | 38 +++++++-------- .../tests/functions/core/withdraw.rs | 18 +++---- .../tests/functions/info/balance.rs | 6 +-- .../functions/info/governance_asset_id.rs | 27 +++++++++++ .../functions/info/governance_token_id.rs | 27 ----------- .../DAO-contract/tests/functions/info/mod.rs | 2 +- .../tests/functions/info/proposal.rs | 8 ++-- .../tests/functions/info/proposal_count.rs | 6 +-- .../tests/functions/info/user_balance.rs | 6 +-- .../tests/functions/info/user_votes.rs | 10 ++-- .../tests/utils/interface/core.rs | 4 +- .../tests/utils/interface/info.rs | 4 +- .../DAO-contract/tests/utils/setup.rs | 16 +++---- OTC-swap-predicate/README.md | 2 +- .../predicates/swap-predicate/src/main.sw | 6 +-- .../swap-predicate/tests/harness.rs | 10 ++-- .../swap-predicate/tests/utils/mod.rs | 22 ++++----- README.md | 8 ++-- airdrop/README.md | 2 +- .../distributor-contract/src/errors.sw | 10 ++-- .../distributor-contract/src/events.sw | 4 +- .../distributor-contract/src/interface.sw | 31 ++++-------- .../distributor-contract/src/main.sw | 16 +++---- .../tests/functions/core/claim.rs | 4 +- .../tests/functions/core/clawback.rs | 6 +-- .../tests/functions/core/constructor.rs | 4 +- .../contracts/exchange-contract/src/events.sw | 2 +- .../scripts/atomic-add-liquidity/src/main.sw | 2 +- .../auction-contract/src/interface.sw | 2 +- .../tests/functions/core/cancel.rs | 2 +- .../tests/functions/core/withdraw.rs | 6 +-- native-assets/NFT/README.md | 12 ++--- native-assets/NFT/project/SPECIFICATION.md | 6 +-- .../contracts/NFT-contract/src/main.sw | 32 ++++++------- .../.docs/native-asset-logo-dark-theme.png | Bin 0 -> 18135 bytes .../.docs/native-asset-logo-light-theme.png | Bin 0 -> 20195 bytes .../{token => native-asset}/.gitignore | 0 .../{token => native-asset}/README.md | 18 +++---- .../project/Cargo.lock | 2 +- .../project/Cargo.toml | 2 +- .../{token => native-asset}/project/Forc.lock | 20 ++++---- native-assets/native-asset/project/Forc.toml | 2 + .../project/SPECIFICATION.md | 10 ++-- .../native-asset-contract}/Cargo.toml | 2 +- .../native-asset-contract}/Forc.toml | 2 +- .../native-asset-contract}/src/errors.sw | 0 .../native-asset-contract}/src/main.sw | 34 +++++++------- .../native-asset-contract}/tests/harness.rs | 0 .../project/fuel-toolchain.toml | 0 .../ui/SPECIFICATION.md | 0 .../token/.docs/token-logo-dark-theme.png | Bin 14693 -> 0 bytes .../token/.docs/token-logo-light-theme.png | Bin 15193 -> 0 bytes native-assets/token/project/Forc.toml | 2 - .../contracts/oracle-contract/src/events.sw | 2 +- 67 files changed, 348 insertions(+), 359 deletions(-) create mode 100644 DAO/project/contracts/DAO-contract/tests/functions/info/governance_asset_id.rs delete mode 100644 DAO/project/contracts/DAO-contract/tests/functions/info/governance_token_id.rs create mode 100644 native-assets/native-asset/.docs/native-asset-logo-dark-theme.png create mode 100644 native-assets/native-asset/.docs/native-asset-logo-light-theme.png rename native-assets/{token => native-asset}/.gitignore (100%) rename native-assets/{token => native-asset}/README.md (71%) rename native-assets/{token => native-asset}/project/Cargo.lock (81%) rename native-assets/{token => native-asset}/project/Cargo.toml (50%) rename native-assets/{token => native-asset}/project/Forc.lock (96%) create mode 100644 native-assets/native-asset/project/Forc.toml rename native-assets/{token => native-asset}/project/SPECIFICATION.md (86%) rename native-assets/{token/project/contracts/token-contract => native-asset/project/contracts/native-asset-contract}/Cargo.toml (86%) rename native-assets/{token/project/contracts/token-contract => native-asset/project/contracts/native-asset-contract}/Forc.toml (91%) rename native-assets/{token/project/contracts/token-contract => native-asset/project/contracts/native-asset-contract}/src/errors.sw (100%) rename native-assets/{token/project/contracts/token-contract => native-asset/project/contracts/native-asset-contract}/src/main.sw (94%) rename native-assets/{token/project/contracts/token-contract => native-asset/project/contracts/native-asset-contract}/tests/harness.rs (100%) rename native-assets/{token => native-asset}/project/fuel-toolchain.toml (100%) rename native-assets/{token => native-asset}/ui/SPECIFICATION.md (100%) delete mode 100644 native-assets/token/.docs/token-logo-dark-theme.png delete mode 100644 native-assets/token/.docs/token-logo-light-theme.png delete mode 100644 native-assets/token/project/Forc.toml diff --git a/.devops/aurora/apps.txt b/.devops/aurora/apps.txt index f2e2e04ec..190d70caf 100644 --- a/.devops/aurora/apps.txt +++ b/.devops/aurora/apps.txt @@ -10,7 +10,7 @@ games/TicTacToe multisig-wallet name-registry native-assets/NFT +native-assets/native-asset native-assets/fractional-NFT -native-assets/token oracle timelock diff --git a/.docs/contributing-book/src/documentation/project-quality/documentation/specification.md b/.docs/contributing-book/src/documentation/project-quality/documentation/specification.md index 7eff558c8..1fb4599cc 100644 --- a/.docs/contributing-book/src/documentation/project-quality/documentation/specification.md +++ b/.docs/contributing-book/src/documentation/project-quality/documentation/specification.md @@ -8,7 +8,7 @@ For simplicity, a specification can be broken into two levels of detail and the A non-technical specification is aimed at an audience that may not have the expertise in an area to appreciate the technical challenges involved in achieving the goals and thus it can be seen as an overview or summary. -As an example, this may be a developer explaining how a user would interact with the user interface in order to send a coin / token to someone, without revealing the functionality behind signing a transaction and why a transaction may take some amount of time to be confirmed. +As an example, this may be a developer explaining how a user would interact with the user interface in order to send a coin / asset to someone, without revealing the functionality behind signing a transaction and why a transaction may take some amount of time to be confirmed. This type of specification is simple so that any layperson can follow the basic concepts of the workflow. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0dc367beb..1bd6fb264 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,8 +50,8 @@ jobs: "multisig-wallet", "name-registry", "native-assets/NFT", + "native-assets/native-asset", "native-assets/fractional-NFT", - "native-assets/token", "oracle", "OTC-swap-predicate", ".devops/.template", diff --git a/DAO/README.md b/DAO/README.md index d477884b2..e697f6943 100644 --- a/DAO/README.md +++ b/DAO/README.md @@ -19,7 +19,7 @@ ## Overview -A decentralized autonomous organization (DAO) is akin to an on-chain government where participants are able to cast votes on proposals using some governance token. Various consensus mechanisms may be implemented in order to determine whether a proposal will pass and if that happens then the DAO will begin to operate under the rules of the new proposal. In this implementation the user deposits governance tokens and receives some number of votes that can be cast and recast on different proposals. They can vote in favour or against proposals and they can transform their votes back into the governance tokens if they wish to withdraw. +A decentralized autonomous organization (DAO) is akin to an on-chain government where participants are able to cast votes on proposals using some governance asset. Various consensus mechanisms may be implemented in order to determine whether a proposal will pass and if that happens then the DAO will begin to operate under the rules of the new proposal. In this implementation the user deposits governance assets and receives some number of votes that can be cast and recast on different proposals. They can vote in favour or against proposals and they can transform their votes back into the governance assets if they wish to withdraw. More information can be found in the [specification](./project/SPECIFICATION.md). diff --git a/DAO/project/SPECIFICATION.md b/DAO/project/SPECIFICATION.md index ffa159d37..8e2411166 100644 --- a/DAO/project/SPECIFICATION.md +++ b/DAO/project/SPECIFICATION.md @@ -14,7 +14,7 @@ Table of Content - [`user_balance()`](#user_balance) - [`user_votes()`](#user_votes) - [`proposal()`](#proposal) - - [`governance_token_id()`](#governance_token_id) + - [`governance_asset_id()`](#governance_asset_id) - [`proposal_count()`](#proposal_count) - [Sequence diagram](#sequence-diagram) @@ -34,7 +34,7 @@ If you are interested in a functional overview then this is the section for you. ### `constructor()` -1. Initializes the contract by setting the governance token used for voting +1. Initializes the contract by setting the governance asset used for voting ### `create_proposal()` @@ -44,13 +44,13 @@ If you are interested in a functional overview then this is the section for you. ### `deposit()` -1. Allows a user to deposit any number of governance tokens - 1. Each token deposited equates to one vote the user can cast +1. Allows a user to deposit any number of governance assets + 1. Each coin deposited equates to one vote the user can cast ### `withdraw()` -1. Allows a user to withdraw any number of governance tokens that they have deposited - 1. The user can only withdraw tokens that have not been bonded as votes in proposals +1. Allows a user to withdraw any number of governance assets that they have deposited + 1. The user can only withdraw coins that have not been bonded as votes in proposals ### `vote()` @@ -76,12 +76,12 @@ If you are interested in a functional overview then this is the section for you. ### `balance()` -1. Returns the total balance of the governance tokens deposited in the contract +1. Returns the total balance of the governance coins deposited in the contract ### `user_balance()` -1. Returns the number of unlocked governance tokens for a user - 1. If a user has voted on a proposal then those tokens will not be reflected in this balance +1. Returns the number of unlocked governance coins for a user + 1. If a user has voted on a proposal then those coins will not be reflected in this balance ### `user_votes()` @@ -98,9 +98,9 @@ If you are interested in a functional overview then this is the section for you. 5. The raw number of "yes" and "no" votes 6. Arbitrary data required for the proposal to execute -### `governance_token_id()` +### `governance_asset_id()` -1. Returns the ID of the governance token +1. Returns the ID of the governance asset ### `proposal_count()` diff --git a/DAO/project/contracts/DAO-contract/src/events.sw b/DAO/project/contracts/DAO-contract/src/events.sw index 2daf4daeb..0db86a4ea 100644 --- a/DAO/project/contracts/DAO-contract/src/events.sw +++ b/DAO/project/contracts/DAO-contract/src/events.sw @@ -32,15 +32,15 @@ pub struct ExecuteEvent { pub struct InitializeEvent { /// User who initialized the contract. author: Identity, - /// AssetId of the token used for DAO governance. - token: AssetId, + /// AssetId of the asset used for DAO governance. + asset: AssetId, } -/// Event for unlocking of governance tokens. +/// Event for unlocking of governance coins. pub struct UnlockVotesEvent { /// The unique identifier for the proposal. id: u64, - /// User who unlocks the tokens. + /// User who unlocks the coins. user: Identity, /// Amount of votes unlocked. vote_amount: u64, diff --git a/DAO/project/contracts/DAO-contract/src/interface.sw b/DAO/project/contracts/DAO-contract/src/interface.sw index 8f2d4feb6..00e3c0bf0 100644 --- a/DAO/project/contracts/DAO-contract/src/interface.sw +++ b/DAO/project/contracts/DAO-contract/src/interface.sw @@ -3,17 +3,17 @@ library; use ::data_structures::{Proposal, ProposalInfo, Votes}; abi DaoVoting { - /// Initialize the dao with the governance token. + /// Initialize the dao with the governance asset. /// /// # Arguments /// - /// * `gov_token`: [AssetId] - AssetId of the token used to vote on governance proposals. + /// * `gov_asset`: [AssetId] - AssetId of the asset used to vote on governance proposals. /// /// # Reverts /// /// * When the constructor is called more than once. #[storage(read, write)] - fn constructor(gov_token: AssetId); + fn constructor(gov_asset: AssetId); /// Create a new proposal. /// @@ -35,28 +35,28 @@ abi DaoVoting { proposal_transaction: Proposal, ); - /// Deposit governance tokens into contract. + /// Deposit governance assets into contract. /// /// # Additional Information /// - /// Update the user balance to indicate they have deposited governance tokens. + /// Update the user balance to indicate they have deposited governance assets. /// A successful deposit unlocks voting functionality. - /// Voting power is directly proportional to the amount of deposited governance tokens, - /// That is: 1 governance token = 1 vote. + /// Voting power is directly proportional to the amount of deposited governance coins, + /// That is: 1 governance coin = 1 vote. /// /// # Reverts /// /// * When the constructor has not been called to initialize. - /// * When the user deposits an asset that is not the specified governance token. + /// * When the user deposits an asset that is not the specified governance asset. /// * When the user does not deposit any assets. #[payable, storage(read, write)] fn deposit(); - /// Update the user balance to indicate they have withdrawn governance tokens. + /// Update the user balance to indicate they have withdrawn governance assets. /// /// # Arguments /// - /// * `amount`: [u64] - amount of governance tokens to withdraw from the contract. + /// * `amount`: [u64] - amount of governance coins to withdraw from the contract. /// /// # Reverts /// @@ -97,13 +97,13 @@ abi DaoVoting { #[storage(read, write)] fn execute(proposal_id: u64); - /// Unlock governance tokens from a proposal. + /// Unlock governance assets from a proposal. /// /// # Additional Information /// - /// Governance tokens are locked whenever a user votes on a proposal. - /// This is to ensure a user cannot vote twice on a proposal with the same governance token. - /// As 1 token = 1 vote. + /// Governance assets are locked whenever a user votes on a proposal. + /// This is to ensure a user cannot vote twice on a proposal with the same governance asset. + /// As 1 coin = 1 vote. /// If the user did not vote on the proposal then nothing happens. /// /// # Arguments @@ -119,23 +119,23 @@ abi DaoVoting { } abi Info { - /// Return the amount of governance tokens in this contract. + /// Return the amount of governance coins in this contract. /// /// # Returns /// - /// * [u64] - the amount of governance tokens in this contract. + /// * [u64] - the amount of governance coin in this contract. #[storage(read)] fn balance() -> u64; - /// Return the amount of governance tokens a user has in this contract. + /// Return the amount of governance coins a user has in this contract. /// /// # Arguments /// - /// * `user`: [Identity] - Identity to look up governance token balance in this contract. + /// * `user`: [Identity] - Identity to look up governance coin balance in this contract. /// /// # Returns /// - /// * [u64] - the amount of governance tokens a user has in this contract. + /// * [u64] - the amount of governance coins a user has in this contract. #[storage(read)] fn user_balance(user: Identity) -> u64; @@ -168,17 +168,17 @@ abi Info { #[storage(read)] fn proposal(id: u64) -> ProposalInfo; - /// Return governance token id + /// Return governance asset id /// /// # Returns /// - /// * [AssetId] - AssetId of the token used to vote on governance proposals. + /// * [AssetId] - AssetId of the asset used to vote on governance proposals. /// /// # Reverts /// /// * When the constructor has not been called to initialize #[storage(read)] - fn governance_token_id() -> AssetId; + fn governance_asset_id() -> AssetId; /// Return proposal count /// diff --git a/DAO/project/contracts/DAO-contract/src/main.sw b/DAO/project/contracts/DAO-contract/src/main.sw index 8beeaf155..9f21f7300 100644 --- a/DAO/project/contracts/DAO-contract/src/main.sw +++ b/DAO/project/contracts/DAO-contract/src/main.sw @@ -33,7 +33,7 @@ use ::interface::{DaoVoting, Info}; use ::utils::validate_id; storage { - /// The amount of governance tokens a user has deposited + /// The amount of governance coins a user has deposited balances: StorageMap = StorageMap {}, /// Information describing a proposal created via create_proposal(...) proposals: StorageMap = StorageMap {}, @@ -43,15 +43,15 @@ storage { proposal_count: u64 = 0, /// The initialization state of the contract. state: State = State::NotInitialized, - /// Contract Id of the governance token - token: AssetId = AssetId::base_asset_id(), + /// Contract Id of the governance asset + asset: AssetId = AssetId::base_asset_id(), /// The amount of votes a user has used on a proposal votes: StorageMap<(Identity, u64), Votes> = StorageMap {}, } impl DaoVoting for Contract { #[storage(read, write)] - fn constructor(token: AssetId) { + fn constructor(asset: AssetId) { require( storage .state @@ -59,12 +59,12 @@ impl DaoVoting for Contract { InitializationError::CannotReinitialize, ); - storage.token.write(token); + storage.asset.write(asset); storage.state.write(State::Initialized); log(InitializeEvent { author: msg_sender().unwrap(), - token, + asset, }) } @@ -111,7 +111,7 @@ impl DaoVoting for Contract { ); require( storage - .token + .asset .read() == msg_asset_id(), UserError::IncorrectAssetSent, ); @@ -147,7 +147,7 @@ impl DaoVoting for Contract { storage.balances.insert(user, prev_balance - amount); // Transfer the asset back to the user - transfer(user, storage.token.read(), amount); + transfer(user, storage.asset.read(), amount); log(WithdrawEvent { amount, user }) } @@ -225,7 +225,7 @@ impl DaoVoting for Contract { call call_data amount asset gas; } - // Users can now convert their votes back into tokens + // Users can now convert their votes back into assets log(ExecuteEvent { user: msg_sender().unwrap(), acceptance_percentage, @@ -273,7 +273,7 @@ impl DaoVoting for Contract { impl Info for Contract { #[storage(read)] fn balance() -> u64 { - this_balance(storage.token.read()) + this_balance(storage.asset.read()) } #[storage(read)] @@ -294,14 +294,14 @@ impl Info for Contract { } #[storage(read)] - fn governance_token_id() -> AssetId { + fn governance_asset_id() -> AssetId { require( storage .state .read() == State::Initialized, InitializationError::ContractNotInitialized, ); - storage.token.read() + storage.asset.read() } #[storage(read)] diff --git a/DAO/project/contracts/DAO-contract/tests/functions/core/constructor.rs b/DAO/project/contracts/DAO-contract/tests/functions/core/constructor.rs index 68183d5e2..57d9b14a8 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/core/constructor.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/core/constructor.rs @@ -2,13 +2,13 @@ use crate::utils::{interface::core::constructor, setup::setup}; mod success { use super::*; - use crate::utils::{interface::info::governance_token_id, setup::InitializeEvent}; + use crate::utils::{interface::info::governance_asset_id, setup::InitializeEvent}; use fuels::{prelude::Address, types::Identity}; #[tokio::test] async fn constructs() { - let (gov_token_id, _other_token_id, deployer, _user, _asset_amount) = setup().await; - let response = constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, _user, _asset_amount) = setup().await; + let response = constructor(&deployer.dao_voting, gov_asset_id).await; let log = response.decode_logs_with_type::().unwrap(); let event = log.get(0).unwrap(); @@ -17,12 +17,12 @@ mod success { *event, InitializeEvent { author: Identity::Address(Address::from(deployer.wallet.address())), - token: gov_token_id + asset: gov_asset_id } ); assert_eq!( - governance_token_id(&deployer.dao_voting).await, - gov_token_id + governance_asset_id(&deployer.dao_voting).await, + gov_asset_id ); } } @@ -33,8 +33,8 @@ mod revert { #[tokio::test] #[should_panic(expected = "CannotReinitialize")] async fn when_reinitialized() { - let (gov_token_id, _other_token_id, deployer, _user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, _user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; + constructor(&deployer.dao_voting, gov_asset_id).await; } } diff --git a/DAO/project/contracts/DAO-contract/tests/functions/core/create_proposal.rs b/DAO/project/contracts/DAO-contract/tests/functions/core/create_proposal.rs index 3c0cfa753..7f4f40b40 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/core/create_proposal.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/core/create_proposal.rs @@ -13,10 +13,10 @@ mod success { #[tokio::test] async fn user_can_create_proposal() { - let (gov_token_id, _other_token_id, deployer, user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); let response = create_proposal(&user.dao_voting, 10, 10, proposal_transaction.clone()).await; @@ -47,10 +47,10 @@ mod success { #[tokio::test] async fn user_can_create_multiple_proposals() { - let (gov_token_id, _other_token_id, deployer, user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); let response = create_proposal(&user.dao_voting, 10, 10, proposal_transaction.clone()).await; @@ -131,30 +131,30 @@ mod revert { #[tokio::test] #[should_panic(expected = "DurationCannotBeZero")] async fn when_duration_is_zero() { - let (gov_token_id, _other_token_id, deployer, _user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, _user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&deployer.dao_voting, 10, 0, proposal_transaction.clone()).await; } #[tokio::test] #[should_panic(expected = "InvalidAcceptancePercentage")] async fn with_zero_acceptance_percentage() { - let (gov_token_id, _other_token_id, deployer, _user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, _user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&deployer.dao_voting, 0, 10, proposal_transaction.clone()).await; } #[tokio::test] #[should_panic(expected = "InvalidAcceptancePercentage")] async fn with_over_hundred_acceptance_percentage() { - let (gov_token_id, _other_token_id, deployer, _user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, _user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&deployer.dao_voting, 101, 10, proposal_transaction.clone()).await; } } diff --git a/DAO/project/contracts/DAO-contract/tests/functions/core/deposit.rs b/DAO/project/contracts/DAO-contract/tests/functions/core/deposit.rs index 9f497a27b..7e8853e65 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/core/deposit.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/core/deposit.rs @@ -14,9 +14,9 @@ mod success { #[tokio::test] async fn user_can_deposit() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + constructor(&deployer.dao_voting, gov_asset_id).await; assert_eq!(balance(&user.dao_voting).await, 0); @@ -25,7 +25,7 @@ mod success { 0 ); - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); let response = deposit(&user.dao_voting, call_params).await; let log = response.decode_logs_with_type::().unwrap(); @@ -57,32 +57,32 @@ mod revert { #[tokio::test] #[should_panic(expected = "ContractNotInitialized")] async fn when_not_initialized() { - let (gov_token_id, _other_token_id, _deployer, user, asset_amount) = setup().await; + let (gov_asset_id, _other_asset_id, _deployer, user, asset_amount) = setup().await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; } #[tokio::test] #[should_panic(expected = "IncorrectAssetSent")] async fn with_incorrect_asset() { - let (gov_token_id, other_token_id, deployer, _user, asset_amount) = setup().await; + let (gov_asset_id, other_asset_id, deployer, _user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + constructor(&deployer.dao_voting, gov_asset_id).await; let call_params = - CallParameters::new(asset_amount, AssetId::from(*other_token_id), 100_000); + CallParameters::new(asset_amount, AssetId::from(*other_asset_id), 100_000); deposit(&deployer.dao_voting, call_params).await; } #[tokio::test] #[should_panic(expected = "AmountCannotBeZero")] async fn on_zero_deposit() { - let (gov_token_id, _other_token_id, deployer, user, _asset_amount) = setup().await; + let (gov_asset_id, _other_asset_id, deployer, user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(0, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(0, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; } } diff --git a/DAO/project/contracts/DAO-contract/tests/functions/core/execute.rs b/DAO/project/contracts/DAO-contract/tests/functions/core/execute.rs index e66ec65d7..6175aa88e 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/core/execute.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/core/execute.rs @@ -12,13 +12,13 @@ mod success { #[tokio::test] #[ignore] async fn user_proposal_can_execute() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 1, proposal_transaction.clone()).await; vote(&user.dao_voting, true, 0, asset_amount / 2).await; @@ -46,7 +46,7 @@ mod revert { #[tokio::test] #[should_panic(expected = "InvalidId")] async fn on_invalid_proposal_id() { - let (_gov_token, _gov_token_id, _deployer, user, _asset_amount) = setup().await; + let (_gov_asset, _gov_asset_id, _deployer, user, _asset_amount) = setup().await; execute(&user.dao_voting, 0).await; } @@ -54,13 +54,13 @@ mod revert { #[should_panic(expected = "ProposalExecuted")] #[ignore] async fn on_already_executed_proposal() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 1, proposal_transaction.clone()).await; vote(&user.dao_voting, true, 0, asset_amount / 2).await; @@ -71,13 +71,13 @@ mod revert { #[tokio::test] #[should_panic(expected = "ProposalStillActive")] pub async fn on_active_proposal() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 100, proposal_transaction.clone()).await; vote(&user.dao_voting, true, 0, asset_amount / 2).await; @@ -87,13 +87,13 @@ mod revert { #[tokio::test] #[should_panic(expected = "InsufficientApprovals")] pub async fn on_not_enough_yes_votes() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 1, proposal_transaction.clone()).await; vote(&user.dao_voting, false, 0, asset_amount / 2).await; diff --git a/DAO/project/contracts/DAO-contract/tests/functions/core/unlock_votes.rs b/DAO/project/contracts/DAO-contract/tests/functions/core/unlock_votes.rs index 234c62e53..8d329aad7 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/core/unlock_votes.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/core/unlock_votes.rs @@ -13,14 +13,14 @@ mod success { use fuels::{prelude::Address, types::Identity}; #[tokio::test] - async fn user_can_unlock_tokens() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + async fn user_can_unlock_assets() { + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 1, 1, proposal_transaction.clone()).await; vote(&user.dao_voting, true, 0, asset_amount / 2).await; @@ -66,15 +66,15 @@ mod success { } #[tokio::test] - async fn user_can_unlock_tokens_from_simultaneous_proposals() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + async fn user_can_unlock_assets_from_simultaneous_proposals() { + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 1, 3, proposal_transaction.clone()).await; create_proposal(&user.dao_voting, 10, 4, proposal_transaction.clone()).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; vote(&user.dao_voting, true, 0, asset_amount / 2).await; @@ -155,14 +155,14 @@ mod success { } #[tokio::test] - async fn user_can_unlock_tokens_from_multiple_proposals() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + async fn user_can_unlock_assets_from_multiple_proposals() { + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 1, 1, proposal_transaction.clone()).await; vote(&user.dao_voting, true, 0, asset_amount / 2).await; @@ -257,20 +257,20 @@ mod revert { #[tokio::test] #[should_panic(expected = "InvalidId")] async fn on_invalid_proposal_id() { - let (_gov_token, _gov_token_id, _deployer, user, _asset_amount) = setup().await; + let (_gov_asset, _gov_asset_id, _deployer, user, _asset_amount) = setup().await; unlock_votes(&user.dao_voting, 0).await; } #[tokio::test] #[should_panic(expected = "ProposalStillActive")] pub async fn on_active_proposal() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 100, proposal_transaction.clone()).await; vote(&user.dao_voting, true, 0, asset_amount / 2).await; unlock_votes(&user.dao_voting, 0).await; diff --git a/DAO/project/contracts/DAO-contract/tests/functions/core/vote.rs b/DAO/project/contracts/DAO-contract/tests/functions/core/vote.rs index 1f2f18c1e..0f153bfbd 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/core/vote.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/core/vote.rs @@ -14,13 +14,13 @@ mod success { #[tokio::test] async fn user_can_vote() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 10, proposal_transaction.clone()).await; let response1 = vote(&user.dao_voting, true, 0, asset_amount / 4).await; @@ -77,13 +77,13 @@ mod success { #[tokio::test] async fn user_can_vote_on_multiple_proposals() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 10, proposal_transaction.clone()).await; let response1 = vote(&user.dao_voting, true, 0, asset_amount / 4).await; @@ -161,17 +161,17 @@ mod revert { #[tokio::test] #[should_panic(expected = "InvalidId")] async fn on_invalid_proposal_id() { - let (_gov_token, _gov_token_id, _deployer, user, _asset_amount) = setup().await; + let (_gov_asset, _gov_asset_id, _deployer, user, _asset_amount) = setup().await; vote(&user.dao_voting, true, 0, 10).await; } #[tokio::test] #[should_panic(expected = "VoteAmountCannotBeZero")] async fn on_zero_vote_amount() { - let (gov_token_id, _other_token_id, deployer, user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 10, proposal_transaction.clone()).await; vote(&user.dao_voting, true, 0, 0).await; } @@ -179,13 +179,13 @@ mod revert { #[tokio::test] #[should_panic(expected = "ProposalExpired")] async fn on_expired_proposal() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 1, 1, proposal_transaction.clone()).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; vote(&user.dao_voting, true, 0, asset_amount / 4).await; } @@ -193,10 +193,10 @@ mod revert { #[tokio::test] #[should_panic(expected = "InsufficientBalance")] async fn on_vote_amount_greater_than_balance() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 10, proposal_transaction.clone()).await; vote(&user.dao_voting, true, 0, asset_amount).await; } diff --git a/DAO/project/contracts/DAO-contract/tests/functions/core/withdraw.rs b/DAO/project/contracts/DAO-contract/tests/functions/core/withdraw.rs index ef03f8c5a..91fb81818 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/core/withdraw.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/core/withdraw.rs @@ -14,11 +14,11 @@ mod success { #[tokio::test] async fn user_can_withdraw() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; assert_eq!(balance(&user.dao_voting).await, asset_amount); @@ -56,11 +56,11 @@ mod revert { #[tokio::test] #[should_panic(expected = "AmountCannotBeZero")] async fn on_withdraw_zero() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; withdraw(&user.dao_voting, 0).await; } @@ -68,11 +68,11 @@ mod revert { #[tokio::test] #[should_panic(expected = "InsufficientBalance")] async fn on_not_enough_assets() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; withdraw(&user.dao_voting, asset_amount * 100).await; } diff --git a/DAO/project/contracts/DAO-contract/tests/functions/info/balance.rs b/DAO/project/contracts/DAO-contract/tests/functions/info/balance.rs index 918432669..6aa2d0433 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/info/balance.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/info/balance.rs @@ -10,10 +10,10 @@ mod success { #[tokio::test] pub async fn user_can_check_contract_balance() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); assert_eq!(balance(&user.dao_voting).await, 0); deposit(&user.dao_voting, call_params).await; assert_eq!(balance(&user.dao_voting).await, asset_amount); diff --git a/DAO/project/contracts/DAO-contract/tests/functions/info/governance_asset_id.rs b/DAO/project/contracts/DAO-contract/tests/functions/info/governance_asset_id.rs new file mode 100644 index 000000000..ee7fe14ab --- /dev/null +++ b/DAO/project/contracts/DAO-contract/tests/functions/info/governance_asset_id.rs @@ -0,0 +1,27 @@ +use crate::utils::{interface::info::governance_asset_id, setup::setup}; + +mod success { + use super::*; + use crate::utils::interface::core::constructor; + + #[tokio::test] + pub async fn user_can_get_governance_asset_id() { + let (gov_asset_id, _other_asset_id, deployer, _user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; + assert_eq!( + governance_asset_id(&deployer.dao_voting).await, + gov_asset_id + ); + } +} + +mod revert { + use super::*; + + #[tokio::test] + #[should_panic(expected = "ContractNotInitialized")] + pub async fn on_not_inialized() { + let (_gov_asset, _gov_asset_id, deployer, _user, _asset_amount) = setup().await; + governance_asset_id(&deployer.dao_voting).await; + } +} diff --git a/DAO/project/contracts/DAO-contract/tests/functions/info/governance_token_id.rs b/DAO/project/contracts/DAO-contract/tests/functions/info/governance_token_id.rs deleted file mode 100644 index 77447c2e6..000000000 --- a/DAO/project/contracts/DAO-contract/tests/functions/info/governance_token_id.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::utils::{interface::info::governance_token_id, setup::setup}; - -mod success { - use super::*; - use crate::utils::interface::core::constructor; - - #[tokio::test] - pub async fn user_can_get_governance_token_id() { - let (gov_token_id, _other_token_id, deployer, _user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; - assert_eq!( - governance_token_id(&deployer.dao_voting).await, - gov_token_id - ); - } -} - -mod revert { - use super::*; - - #[tokio::test] - #[should_panic(expected = "ContractNotInitialized")] - pub async fn on_not_inialized() { - let (_gov_token, _gov_token_id, deployer, _user, _asset_amount) = setup().await; - governance_token_id(&deployer.dao_voting).await; - } -} diff --git a/DAO/project/contracts/DAO-contract/tests/functions/info/mod.rs b/DAO/project/contracts/DAO-contract/tests/functions/info/mod.rs index 74bbaa6c0..9d0d5dff9 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/info/mod.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/info/mod.rs @@ -1,5 +1,5 @@ mod balance; -mod governance_token_id; +mod governance_asset_id; mod proposal; mod proposal_count; mod user_balance; diff --git a/DAO/project/contracts/DAO-contract/tests/functions/info/proposal.rs b/DAO/project/contracts/DAO-contract/tests/functions/info/proposal.rs index 690294a96..cfc037739 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/info/proposal.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/info/proposal.rs @@ -10,10 +10,10 @@ mod success { #[tokio::test] pub async fn user_can_get_proposal() { - let (gov_token_id, _other_token_id, deployer, user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 10, proposal_transaction.clone()).await; assert_eq!( @@ -37,7 +37,7 @@ mod revert { #[tokio::test] #[should_panic(expected = "InvalidId")] async fn on_invalid_proposal_id() { - let (_gov_token, _gov_token_id, _deployer, user, _asset_amount) = setup().await; + let (_gov_asset, _gov_asset_id, _deployer, user, _asset_amount) = setup().await; proposal(&user.dao_voting, 0).await; } } diff --git a/DAO/project/contracts/DAO-contract/tests/functions/info/proposal_count.rs b/DAO/project/contracts/DAO-contract/tests/functions/info/proposal_count.rs index 78b160e8d..db2574448 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/info/proposal_count.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/info/proposal_count.rs @@ -9,10 +9,10 @@ mod success { #[tokio::test] async fn use_can_get_proposal_count() { - let (gov_token_id, _other_token_id, deployer, user, _asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, _asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 10, proposal_transaction.clone()).await; assert_eq!(proposal_count(&user.dao_voting).await, 1); diff --git a/DAO/project/contracts/DAO-contract/tests/functions/info/user_balance.rs b/DAO/project/contracts/DAO-contract/tests/functions/info/user_balance.rs index 6f934fa2d..0886d21d8 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/info/user_balance.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/info/user_balance.rs @@ -10,10 +10,10 @@ mod success { #[tokio::test] pub async fn user_can_check_user_balance() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); assert_eq!( user_balance(&user.dao_voting, user.wallet.address()).await, 0 diff --git a/DAO/project/contracts/DAO-contract/tests/functions/info/user_votes.rs b/DAO/project/contracts/DAO-contract/tests/functions/info/user_votes.rs index cfd378959..8cb5846fd 100644 --- a/DAO/project/contracts/DAO-contract/tests/functions/info/user_votes.rs +++ b/DAO/project/contracts/DAO-contract/tests/functions/info/user_votes.rs @@ -10,12 +10,12 @@ mod sucess { #[tokio::test] pub async fn user_can_check_user_votes() { - let (gov_token_id, _other_token_id, deployer, user, asset_amount) = setup().await; - constructor(&deployer.dao_voting, gov_token_id).await; + let (gov_asset_id, _other_asset_id, deployer, user, asset_amount) = setup().await; + constructor(&deployer.dao_voting, gov_asset_id).await; - let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_token_id), 100_000); + let call_params = CallParameters::new(asset_amount, AssetId::from(*gov_asset_id), 100_000); deposit(&user.dao_voting, call_params).await; - let proposal_transaction = proposal_transaction(gov_token_id); + let proposal_transaction = proposal_transaction(gov_asset_id); create_proposal(&user.dao_voting, 10, 10, proposal_transaction).await; assert_eq!( user_votes(&user.dao_voting, user.wallet.address(), 0).await, @@ -41,7 +41,7 @@ mod revert { #[tokio::test] #[should_panic(expected = "InvalidId")] pub async fn on_invalid_proposal_id() { - let (_gov_token, _gov_token_id, _deployer, user, _asset_amount) = setup().await; + let (_gov_asset, _gov_asset_id, _deployer, user, _asset_amount) = setup().await; user_votes(&user.dao_voting, user.wallet.address(), 0).await; } } diff --git a/DAO/project/contracts/DAO-contract/tests/utils/interface/core.rs b/DAO/project/contracts/DAO-contract/tests/utils/interface/core.rs index 28c7bf110..ce11586fc 100644 --- a/DAO/project/contracts/DAO-contract/tests/utils/interface/core.rs +++ b/DAO/project/contracts/DAO-contract/tests/utils/interface/core.rs @@ -7,9 +7,9 @@ use fuels::{ pub(crate) async fn constructor( contract: &DaoVoting, - token: AssetId, + asset: AssetId, ) -> FuelCallResponse<()> { - contract.methods().constructor(token).call().await.unwrap() + contract.methods().constructor(asset).call().await.unwrap() } pub(crate) async fn create_proposal( diff --git a/DAO/project/contracts/DAO-contract/tests/utils/interface/info.rs b/DAO/project/contracts/DAO-contract/tests/utils/interface/info.rs index 2f30cb58e..1ca29bfd5 100644 --- a/DAO/project/contracts/DAO-contract/tests/utils/interface/info.rs +++ b/DAO/project/contracts/DAO-contract/tests/utils/interface/info.rs @@ -39,10 +39,10 @@ pub(crate) async fn proposal(contract: &DaoVoting, id: u64) -> P contract.methods().proposal(id).call().await.unwrap().value } -pub(crate) async fn governance_token_id(contract: &DaoVoting) -> AssetId { +pub(crate) async fn governance_asset_id(contract: &DaoVoting) -> AssetId { contract .methods() - .governance_token_id() + .governance_asset_id() .call() .await .unwrap() diff --git a/DAO/project/contracts/DAO-contract/tests/utils/setup.rs b/DAO/project/contracts/DAO-contract/tests/utils/setup.rs index 30a1adeed..b851e8c4d 100644 --- a/DAO/project/contracts/DAO-contract/tests/utils/setup.rs +++ b/DAO/project/contracts/DAO-contract/tests/utils/setup.rs @@ -45,19 +45,19 @@ pub(crate) async fn setup() -> (AssetId, AssetId, Metadata, Metadata, u64) { num_coins: number_of_coins, coin_amount, }; - let gov_token_id = AssetId::new([1; 32]); - let gov_token = AssetConfig { - id: gov_token_id, + let gov_asset_id = AssetId::new([1; 32]); + let gov_asset = AssetConfig { + id: gov_asset_id, num_coins: number_of_coins, coin_amount, }; - let other_token_id = AssetId::new([2; 32]); - let other_token = AssetConfig { - id: other_token_id, + let other_asset_id = AssetId::new([2; 32]); + let other_asset = AssetConfig { + id: other_asset_id, num_coins: number_of_coins, coin_amount, }; - let assets = vec![base_asset, gov_token, other_token]; + let assets = vec![base_asset, gov_asset, other_asset]; let wallet_config = WalletsConfig::new_multiple_assets(number_of_wallets, assets); let mut wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None) @@ -88,5 +88,5 @@ pub(crate) async fn setup() -> (AssetId, AssetId, Metadata, Metadata, u64) { let asset_amount = 10; - (gov_token_id, other_token_id, deployer, user, asset_amount) + (gov_asset_id, other_asset_id, deployer, user, asset_amount) } diff --git a/OTC-swap-predicate/README.md b/OTC-swap-predicate/README.md index 88985d3a4..6cf124c50 100644 --- a/OTC-swap-predicate/README.md +++ b/OTC-swap-predicate/README.md @@ -31,7 +31,7 @@ Predicates may introspect the transaction spending their coins (inputs, outputs, ## Order / OTC swap Predicate -This predicate serves as an "order" that anyone can fill. The order maker transfers a coin to the predicate root which can be unlocked by any transaction which has an output that satisfies the conditions of the order : the spending transaction must transfer `ask_amount` of `ask_token` to the `receiver`. These constants are hard-coded in the predicate itself, so that the bytecode root commits to this specific set of conditions. +This predicate serves as an "order" that anyone can fill. The order maker transfers a coin to the predicate root which can be unlocked by any transaction which has an output that satisfies the conditions of the order : the spending transaction must transfer `ask_amount` of `ask_asset` to the `receiver`. These constants are hard-coded in the predicate itself, so that the bytecode root commits to this specific set of conditions. The order "taker" can then execute the order by spending the predicate. They are free to spend the predicate's coin in any way they wish, so long as the transaction has an output which satisfies the above conditions. This output must be the first output in the output set (i.e. its index is 0) diff --git a/OTC-swap-predicate/project/predicates/swap-predicate/src/main.sw b/OTC-swap-predicate/project/predicates/swap-predicate/src/main.sw index d9d2c31dc..6adefe18e 100644 --- a/OTC-swap-predicate/project/predicates/swap-predicate/src/main.sw +++ b/OTC-swap-predicate/project/predicates/swap-predicate/src/main.sw @@ -19,7 +19,7 @@ configurable { /// The amount of asset required to unlock the predicate. ASK_AMOUNT: u64 = 42, /// The asset to be paid. - ASK_TOKEN: AssetId = AssetId::from(0x0101010101010101010101010101010101010101010101010101010101010101), + ASK_ASSET: AssetId = AssetId::from(0x0101010101010101010101010101010101010101010101010101010101010101), /// The receiver to whom the swapped asset will be sent. RECEIVER: Address = Address::from(0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db), } @@ -34,7 +34,7 @@ configurable { /// /// * [bool] - `true` if the spender is the receiver or if the terms of the order are met, `false` otherwise. fn main() -> bool { - // The spending transaction must have an output that sends `ask_amount` of `ask_token` to `receiver` + // The spending transaction must have an output that sends `ask_amount` of `ask_asset` to `receiver` // Check if the transaction contains a single input coin from the receiver, to cancel their own order (in addition to this predicate) if input_count() == 2u8 { @@ -62,5 +62,5 @@ fn main() -> bool { let amount = output_amount(output_index); // Evaluate the predicate - (to == RECEIVER) && (amount == ASK_AMOUNT) && (asset_id == ASK_TOKEN) + (to == RECEIVER) && (amount == ASK_AMOUNT) && (asset_id == ASK_ASSET) } diff --git a/OTC-swap-predicate/project/predicates/swap-predicate/tests/harness.rs b/OTC-swap-predicate/project/predicates/swap-predicate/tests/harness.rs index 9609ad9c5..14dd12a81 100644 --- a/OTC-swap-predicate/project/predicates/swap-predicate/tests/harness.rs +++ b/OTC-swap-predicate/project/predicates/swap-predicate/tests/harness.rs @@ -4,7 +4,7 @@ use fuels::prelude::AssetId; // These constants should match those hard-coded in the predicate const ASK_AMOUNT: u64 = 42; -const ASK_TOKEN: AssetId = AssetId::new([1u8; 32]); +const ASK_ASSET: AssetId = AssetId::new([1u8; 32]); const RECEIVER: &str = "fuel1p8qt95dysmzrn2rmewntg6n6rg3l8ztueqafg5s6jmd9cgautrdslwdqdw"; mod success { @@ -13,7 +13,7 @@ mod success { #[tokio::test] async fn valid_predicate_spend_with_swap() { - utils::test_predicate_spend_with_parameters(ASK_AMOUNT, ASK_TOKEN, RECEIVER).await; + utils::test_predicate_spend_with_parameters(ASK_AMOUNT, ASK_ASSET, RECEIVER).await; } #[tokio::test] async fn owner_recover_funds() { @@ -27,12 +27,12 @@ mod revert { #[tokio::test] #[should_panic] async fn incorrect_ask_amount() { - utils::test_predicate_spend_with_parameters(41, ASK_TOKEN, RECEIVER).await; + utils::test_predicate_spend_with_parameters(41, ASK_ASSET, RECEIVER).await; } #[tokio::test] #[should_panic] - async fn incorrect_ask_token() { + async fn incorrect_ask_asset() { utils::test_predicate_spend_with_parameters(ASK_AMOUNT, AssetId::new([42u8; 32]), RECEIVER) .await; } @@ -42,7 +42,7 @@ mod revert { async fn incorrect_receiver_address() { utils::test_predicate_spend_with_parameters( ASK_AMOUNT, - ASK_TOKEN, + ASK_ASSET, "fuelthisaddressisnotthereceiver11111111111111111111111111111111", ) .await; diff --git a/OTC-swap-predicate/project/predicates/swap-predicate/tests/utils/mod.rs b/OTC-swap-predicate/project/predicates/swap-predicate/tests/utils/mod.rs index ad7788099..748257a4f 100644 --- a/OTC-swap-predicate/project/predicates/swap-predicate/tests/utils/mod.rs +++ b/OTC-swap-predicate/project/predicates/swap-predicate/tests/utils/mod.rs @@ -20,7 +20,7 @@ const BASE_ASSET: AssetId = AssetId::new([0u8; 32]); const OFFERED_ASSET: AssetId = AssetId::new([2u8; 32]); const PREDICATE_BINARY: &str = "../swap-predicate/out/debug/swap-predicate.bin"; -// Get the balance of a given token of an address +// Get the balance of a given asset of an address async fn get_balance(provider: &Provider, address: &Bech32Address, asset: AssetId) -> u64 { provider.get_asset_balance(address, asset).await.unwrap() } @@ -59,9 +59,9 @@ pub async fn test_predicate_spend_with_parameters( let provider = receiver_wallet.provider().unwrap(); - let initial_taker_offered_token_balance = + let initial_taker_offered_asset_balance = get_balance(provider, taker_wallet.address(), OFFERED_ASSET).await; - let initial_taker_asked_token_balance = + let initial_taker_asked_asset_balance = get_balance(provider, taker_wallet.address(), asked_asset).await; let initial_receiver_balance = get_balance(provider, &receiver_address, asked_asset).await; @@ -108,7 +108,7 @@ pub async fn test_predicate_spend_with_parameters( .unwrap()[0]; // Configure inputs and outputs to send coins from the predicate root to another address - // The predicate allows to spend its tokens if `ask_amount` is sent to the receiver. + // The predicate allows to spend its assets if `ask_amount` is sent to the receiver. // Offered asset coin belonging to the predicate root let input_predicate = match predicate_coin { @@ -164,9 +164,9 @@ pub async fn test_predicate_spend_with_parameters( let _response = script_call.call().await.unwrap(); let predicate_balance = get_balance(provider, predicate.address(), OFFERED_ASSET).await; - let taker_asked_token_balance = + let taker_asked_asset_balance = get_balance(provider, taker_wallet.address(), asked_asset).await; - let taker_offered_token_balance = + let taker_offered_asset_balance = get_balance(provider, taker_wallet.address(), OFFERED_ASSET).await; let receiver_balance = get_balance(provider, &receiver_address, asked_asset).await; @@ -176,14 +176,14 @@ pub async fn test_predicate_spend_with_parameters( // Receiver has been paid `ask_amount` assert_eq!(receiver_balance, initial_receiver_balance + ask_amount); - // Taker has sent `ask_amount` of the asked token and received `offered_amount` of the offered token in return + // Taker has sent `ask_amount` of the asked asset and received `offered_amount` of the offered asset in return assert_eq!( - taker_asked_token_balance, - initial_taker_asked_token_balance - ask_amount + taker_asked_asset_balance, + initial_taker_asked_asset_balance - ask_amount ); assert_eq!( - taker_offered_token_balance, - initial_taker_offered_token_balance + offered_amount + taker_offered_asset_balance, + initial_taker_offered_asset_balance + offered_amount ); } diff --git a/README.md b/README.md index a09a7330c..9f571f853 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,12 @@ sway-applications/ #### Asset Management -- [Airdrop](./airdrop/) is a token distribution program where users are able to claim tokens given a valid merkle proof. +- [Airdrop](./airdrop/) is an asset distribution program where users are able to claim assets given a valid merkle proof. - [Escrow](./escrow) is a third party that keeps an asset on behalf of multiple parties. +- [Non-Fungible Native Asset (NFT)](./native-assets/NFT/) is an asset contract which provides unique collectibles, identified and differentiated by IDs, where assets contain metadata giving them distinctive characteristics. - [Fractional Non-Fungible Token (F-NFT)](./native-assets/fractional-NFT/) is a token contract which issues shares or partial ownership upon locking an NFT into a vault. -- [Non-Fungible Token (NFT)](./native-assets/NFT/) is a token contract which provides unique collectibles, identified and differentiated by token IDs, where tokens contain metadata giving them distinctive characteristics. - [Timelock](./timelock) is a contract which restricts the execution of a transaction to a specified time range. -- [Token](./native-assets/token/) is a basic token contract that enables the use of Native Assets on Fuel using existing standards and libraries. +- [Native Asset](./native-assets/native-asset/) is a basic asset contract that enables the use of Native Assets on Fuel using existing standards and libraries. #### Decentralized Finance @@ -63,7 +63,7 @@ sway-applications/ #### Governance -- [Decentralized Autonomous Organization (DAO)](./DAO) is an organization where users get to vote on governance proposals using governance tokens. +- [Decentralized Autonomous Organization (DAO)](./DAO) is an organization where users get to vote on governance proposals using governance assets. - [Multi-Signature Wallet](./multisig-wallet) is a wallet that requires multiple signatures to execute a transaction. #### Other diff --git a/airdrop/README.md b/airdrop/README.md index 362ae4221..e74d6ba7b 100644 --- a/airdrop/README.md +++ b/airdrop/README.md @@ -19,7 +19,7 @@ ## Overview -An airdrop is an application where a set number of users are able to claim a specific amount of an asset. In today's ecosystem, this is often used to distribute tokens to an application's user base that has previously interacted with their project. +An airdrop is an application where a set number of users are able to claim a specific amount of an asset. In today's ecosystem, this is often used to distribute assets to an application's user base that has previously interacted with their project. In order to verifiably prove that a user has a claim to an airdrop and avoiding the expensive transaction of storing every address on chain, a Merkle Proof is used. By storing the Merkle root, a single `b256` hash, the airdrop application can cryptographically prove a user's validity to their claim. diff --git a/airdrop/project/contracts/distributor-contract/src/errors.sw b/airdrop/project/contracts/distributor-contract/src/errors.sw index 29c53ac37..ef9cf1677 100644 --- a/airdrop/project/contracts/distributor-contract/src/errors.sw +++ b/airdrop/project/contracts/distributor-contract/src/errors.sw @@ -4,9 +4,9 @@ library; pub enum AccessError { /// The caller is not the admin of the contract. CallerNotAdmin: (), - /// There are not enough tokens in the contract to perform the operation. - NotEnoughTokens: (), - /// The user has already claimed their tokens. + /// There are not enough coins in the contract to perform the operation. + NotEnoughCoins: (), + /// The user has already claimed their coins. UserAlreadyClaimed: (), } @@ -14,8 +14,8 @@ pub enum AccessError { pub enum InitError { /// The contract has already been initialized. AlreadyInitialized: (), - /// No assets were transferred during initialization. - CannotAirdropZeroTokens: (), + /// No coins were transferred during initialization. + CannotAirdropZeroCoins: (), } /// Errors related to the state of the contract. diff --git a/airdrop/project/contracts/distributor-contract/src/events.sw b/airdrop/project/contracts/distributor-contract/src/events.sw index 5e1410ad8..f26af0a06 100644 --- a/airdrop/project/contracts/distributor-contract/src/events.sw +++ b/airdrop/project/contracts/distributor-contract/src/events.sw @@ -3,7 +3,7 @@ library; pub struct ClaimEvent { /// The quantity of an asset which is to be transferred to the user. amount: u64, - /// The user that has a claim to tokens with a valid proof. + /// The user that has a claim to coins with a valid proof. claimer: Identity, /// The identity that will receive the transferred asset. to: Identity, @@ -17,7 +17,7 @@ pub struct ClawbackEvent { } pub struct CreateAirdropEvent { - /// The user which can claim any left over tokens after the claiming period. + /// The user which can claim any left over coins after the claiming period. admin: Identity, /// The asset which is to be distributed. asset: AssetId, diff --git a/airdrop/project/contracts/distributor-contract/src/interface.sw b/airdrop/project/contracts/distributor-contract/src/interface.sw index a11a5493c..eb538bd70 100644 --- a/airdrop/project/contracts/distributor-contract/src/interface.sw +++ b/airdrop/project/contracts/distributor-contract/src/interface.sw @@ -13,10 +13,10 @@ abi AirdropDistributor { /// /// # Arguments /// - /// * `amount`: [u64] - The quantity of tokens allotted to the user to claim. + /// * `amount`: [u64] - The quantity of coins allotted to the user to claim. /// * `key`: [u64] - The index of the leaf which will be proven on the Merkle Tree. /// * `proof`: [Vec] - The Merkle proof to verify the user is authorized to claim. - /// * `to`: [Identity] - The user which has been allotted a quantity of the tokens. + /// * `to`: [Identity] - The user which has been allotted a quantity of the coins. /// /// # Reverts /// @@ -27,13 +27,13 @@ abi AirdropDistributor { #[storage(read, write)] fn claim(amount: u64, key: u64, proof: Vec, to: Identity); - /// Returns any unclaimed tokens to 'admin' when the claiming period of the airdrop has ended. + /// Returns any unclaimed coins to 'admin' when the claiming period of the airdrop has ended. /// /// # Reverts /// /// * When the sender is not the contract's admin. /// * When the claiming period is still active. - /// * When there are no tokens to claim. + /// * When there are no coins to claim. #[storage(read)] fn clawback(); @@ -41,7 +41,7 @@ abi AirdropDistributor { /// /// # Arguments /// - /// * `admin`: [Identity] - The user which has the ability to clawback any unclaimed tokens. + /// * `admin`: [Identity] - The user which has the ability to clawback any unclaimed coins. /// * `claim_time`: [u64] - The number fo blocks the claiming period should last. /// * `merkleRoot`: [b256] - The root of the merkle proof used to verify claiming. /// * `num_leaves`: [u64] - The number of leaves in the Merkle Tree. @@ -49,7 +49,7 @@ abi AirdropDistributor { /// # Reverts /// /// * When the constructor has already been called. - /// * When no tokens are sent to the airdrop contract. + /// * When no coins are sent to the airdrop contract. #[payable] #[storage(read, write)] fn constructor( @@ -61,11 +61,11 @@ abi AirdropDistributor { } abi Info { - /// Returns the user which has the ability to clawback any unclaimed tokens. + /// Returns the user which has the ability to clawback any unclaimed coins. /// /// # Returns /// - /// * [Option] - The user which has the ability to clawback any unclaimed tokens. + /// * [Option] - The user which has the ability to clawback any unclaimed coins. #[storage(read)] fn admin() -> Option; @@ -89,11 +89,11 @@ abi Info { #[storage(read)] fn end_block() -> u32; - /// Returns whether the airdrop is active and tokens can be claimed. + /// Returns whether the airdrop is active and coins can be claimed. /// /// # Returns /// - /// * [bool] - Whether the airdrop is active and tokens can be claimed. + /// * [bool] - Whether the airdrop is active and coins can be claimed. #[storage(read)] fn is_active() -> bool; @@ -113,14 +113,3 @@ abi Info { #[storage(read)] fn number_of_leaves() -> u64; } - -abi SimpleAsset { - /// Mints the given amount of tokens to the given Identity. - /// - /// # Arguments - /// - /// * `amount`: [u64] - The quantity of tokens to mint. - /// * `to`: [Identity] - The user which will receive the minted tokens. - #[storage(read, write)] - fn mint_to(amount: u64, to: Identity); -} diff --git a/airdrop/project/contracts/distributor-contract/src/main.sw b/airdrop/project/contracts/distributor-contract/src/main.sw index 8bbda01e8..b8fd7bf43 100644 --- a/airdrop/project/contracts/distributor-contract/src/main.sw +++ b/airdrop/project/contracts/distributor-contract/src/main.sw @@ -27,9 +27,9 @@ use std::{ }; storage { - /// The Identity which has the ability to clawback unclaimed tokens. + /// The Identity which has the ability to clawback unclaimed coins of an asset. admin: Option = Option::None, - /// The contract of the tokens which is to be distributed. + /// The asset which is to be distributed. asset: Option = Option::None, /// Stores the ClaimState of users that have interacted with the Airdrop Distributor contract. /// Maps (user => claim) @@ -64,9 +64,9 @@ impl AirdropDistributor for Contract { AccessError::UserAlreadyClaimed, ); - // There must be enough tokens left in the contract + // There must be enough coins left in the contract let asset = storage.asset.read().unwrap(); - require(this_balance(asset) >= amount, AccessError::NotEnoughTokens); + require(this_balance(asset) >= amount, AccessError::NotEnoughCoins); // Verify the merkle proof against the user and amount // TODO: Remove assembly when https://github.com/FuelLabs/sway-libs/issues/186 is resolved @@ -94,7 +94,7 @@ impl AirdropDistributor for Contract { storage.claims.insert(sender, ClaimState::Claimed(amount)); - // Transfer tokens + // Transfer coins transfer(to, asset, amount); log(ClaimEvent { @@ -123,9 +123,9 @@ impl AirdropDistributor for Contract { let asset = storage.asset.read().unwrap(); let balance = this_balance(asset); - require(balance > 0, AccessError::NotEnoughTokens); + require(balance > 0, AccessError::NotEnoughCoins); - // Send the remaining balance of tokens to the admin + // Send the remaining balance of coins to the admin transfer(admin.unwrap(), asset, balance); log(ClawbackEvent { @@ -145,7 +145,7 @@ impl AirdropDistributor for Contract { // If `end_block` is set to a value other than 0, we know that the constructor has already // been called. require(storage.end_block.read() == 0, InitError::AlreadyInitialized); - require(msg_amount() > 0, InitError::CannotAirdropZeroTokens); + require(msg_amount() > 0, InitError::CannotAirdropZeroCoins); let asset = msg_asset_id(); storage.end_block.write(claim_time + height()); diff --git a/airdrop/project/contracts/distributor-contract/tests/functions/core/claim.rs b/airdrop/project/contracts/distributor-contract/tests/functions/core/claim.rs index 2ea054f97..ab440a0a8 100644 --- a/airdrop/project/contracts/distributor-contract/tests/functions/core/claim.rs +++ b/airdrop/project/contracts/distributor-contract/tests/functions/core/claim.rs @@ -625,8 +625,8 @@ mod revert { } #[tokio::test] - #[should_panic(expected = "NotEnoughTokens")] - async fn when_not_enough_tokens_to_claim() { + #[should_panic(expected = "NotEnoughCoins")] + async fn when_not_enough_coins_to_claim() { let (deploy_wallet, wallet1, wallet2, wallet3, asset_id) = setup().await; let (_, _, _, minter, key, num_leaves, _asset_supply, airdrop_leaves, claim_time, _, _) = defaults(&deploy_wallet, &wallet1, &wallet2, &wallet3).await; diff --git a/airdrop/project/contracts/distributor-contract/tests/functions/core/clawback.rs b/airdrop/project/contracts/distributor-contract/tests/functions/core/clawback.rs index aa5023638..4be521473 100644 --- a/airdrop/project/contracts/distributor-contract/tests/functions/core/clawback.rs +++ b/airdrop/project/contracts/distributor-contract/tests/functions/core/clawback.rs @@ -8,7 +8,7 @@ mod success { use super::*; #[tokio::test] - async fn returns_all_tokens() { + async fn returns_all_coins() { let (deploy_wallet, wallet1, wallet2, wallet3, asset_id) = setup().await; let ( _, @@ -54,7 +54,7 @@ mod success { } #[tokio::test] - async fn returns_unclaimed_tokens() { + async fn returns_unclaimed_coins() { let (deploy_wallet, wallet1, wallet2, wallet3, asset_id) = setup().await; let ( identity_a, @@ -175,7 +175,7 @@ mod revert { } #[tokio::test] - #[should_panic(expected = "NotEnoughTokens")] + #[should_panic(expected = "NotEnoughCoins")] async fn when_called_twice() { let (deploy_wallet, wallet1, wallet2, wallet3, asset_id) = setup().await; let (_, _, _, minter, key, num_leaves, asset_supply, airdrop_leaves, claim_time, _, _) = diff --git a/airdrop/project/contracts/distributor-contract/tests/functions/core/constructor.rs b/airdrop/project/contracts/distributor-contract/tests/functions/core/constructor.rs index 51e9caddd..f8a74b22f 100644 --- a/airdrop/project/contracts/distributor-contract/tests/functions/core/constructor.rs +++ b/airdrop/project/contracts/distributor-contract/tests/functions/core/constructor.rs @@ -97,8 +97,8 @@ mod revert { } #[tokio::test] - #[should_panic(expected = "CannotAirdropZeroTokens")] - async fn when_no_tokens_provided() { + #[should_panic(expected = "CannotAirdropZeroCoins")] + async fn when_no_coins_provided() { let (deploy_wallet, wallet1, wallet2, wallet3, asset_id) = setup().await; let (_, admin, _, _, _, num_leaves, _, _, claim_time, _, _) = defaults(&deploy_wallet, &wallet1, &wallet2, &wallet3).await; diff --git a/archive/AMM/project/contracts/exchange-contract/src/events.sw b/archive/AMM/project/contracts/exchange-contract/src/events.sw index ed6df6575..c980efe4f 100644 --- a/archive/AMM/project/contracts/exchange-contract/src/events.sw +++ b/archive/AMM/project/contracts/exchange-contract/src/events.sw @@ -34,7 +34,7 @@ pub struct RemoveLiquidityEvent { burned_liquidity: Asset, } -/// The information logged when a token swap is made. +/// The information logged when an asset swap is made. pub struct SwapEvent { /// Identifier and amount of sold asset. input: Asset, diff --git a/archive/AMM/project/scripts/atomic-add-liquidity/src/main.sw b/archive/AMM/project/scripts/atomic-add-liquidity/src/main.sw index caec2a7aa..1541a036b 100644 --- a/archive/AMM/project/scripts/atomic-add-liquidity/src/main.sw +++ b/archive/AMM/project/scripts/atomic-add-liquidity/src/main.sw @@ -17,7 +17,7 @@ enum InputError { /// /// # Returns /// -/// * The amount of liquidity tokens minted. +/// * The amount of liquidity assets minted. /// /// # Reverts /// diff --git a/auctions/english-auction/project/contracts/auction-contract/src/interface.sw b/auctions/english-auction/project/contracts/auction-contract/src/interface.sw index 7e279f08c..d47e71424 100644 --- a/auctions/english-auction/project/contracts/auction-contract/src/interface.sw +++ b/auctions/english-auction/project/contracts/auction-contract/src/interface.sw @@ -63,7 +63,7 @@ abi EnglishAuction { /// * When the `reserve_price` is less than `initial_price` and a reserve is set. /// * When the `duration` of the auction is set to zero. /// * When the `bid_asset` amount is not zero. - /// * When the `initial_price` for tokens is set to zero. + /// * When the `initial_price` for coins is set to zero. /// * When the native asset amount sent and the `sell_asset` enum do not match. /// * When the native asset type sent and the `sell_asset` enum do not match. /// * When the `initial_price` for NFTs is not one. diff --git a/auctions/english-auction/project/contracts/auction-contract/tests/functions/core/cancel.rs b/auctions/english-auction/project/contracts/auction-contract/tests/functions/core/cancel.rs index 9e2b6563f..a7b90a0d4 100644 --- a/auctions/english-auction/project/contracts/auction-contract/tests/functions/core/cancel.rs +++ b/auctions/english-auction/project/contracts/auction-contract/tests/functions/core/cancel.rs @@ -90,7 +90,7 @@ mod success { } #[tokio::test] - async fn cancels_token_auction() { + async fn cancels_asset_auction() { let (_, seller, _, _, _, sell_asset, buy_asset) = setup().await; let (sell_amount, initial_price, reserve_price, duration, _initial_wallet_amount) = defaults().await; diff --git a/auctions/english-auction/project/contracts/auction-contract/tests/functions/core/withdraw.rs b/auctions/english-auction/project/contracts/auction-contract/tests/functions/core/withdraw.rs index 6b6d6acc9..afb6d9a71 100644 --- a/auctions/english-auction/project/contracts/auction-contract/tests/functions/core/withdraw.rs +++ b/auctions/english-auction/project/contracts/auction-contract/tests/functions/core/withdraw.rs @@ -56,7 +56,7 @@ mod success { } #[tokio::test] - async fn buyer_withdraws_tokens() { + async fn buyer_withdraws_assets() { let (_, seller, buyer1, _, _, sell_asset, buy_asset) = setup().await; let (sell_amount, initial_price, reserve_price, duration, initial_wallet_amount) = defaults().await; @@ -98,7 +98,7 @@ mod success { } #[tokio::test] - async fn out_bid_withdraws_tokens() { + async fn out_bid_withdraws_assets() { let (_, seller, buyer1, buyer2, _, sell_asset, buy_asset) = setup().await; let (sell_amount, initial_price, reserve_price, duration, initial_wallet_amount) = defaults().await; @@ -183,7 +183,7 @@ mod success { } #[tokio::test] - async fn seller_withdraws_tokens() { + async fn seller_withdraws_assets() { let (_, seller, buyer1, _, _, sell_asset, buy_asset) = setup().await; let (sell_amount, initial_price, reserve_price, duration, initial_wallet_amount) = defaults().await; diff --git a/native-assets/NFT/README.md b/native-assets/NFT/README.md index b8ee5ad9b..c5c2f401f 100644 --- a/native-assets/NFT/README.md +++ b/native-assets/NFT/README.md @@ -16,21 +16,21 @@ ## Overview -A non-fungible token (NFT) is a unique token that has a maximum supply of one. On the Fuel Network, all NFTs are [Native Assets](https://docs.fuel.network/docs/sway/blockchain-development/native_assets). They are commonly associated with artwork / collectibles however there are many greater utilities beyond that which have yet to be written for the Fuel Network. +A non-fungible token (NFT) is a unique asset that has a maximum supply of one. On the Fuel Network, all NFTs are [Native Assets](https://docs.fuel.network/docs/sway/blockchain-development/native_assets). They are commonly associated with artwork / collectibles however there are many greater utilities beyond that which have yet to be written for the Fuel Network. In this barebones NFT example project, there are a maximum of 100,000 NFTs that may be minted. Each NFT may contain any metadata the user desires to store. ## Standards Implementations -The project implements and follows the [SRC-20; Token](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20), [SRC-3; Mint and Burn](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_3), and [SRC-7; Metadata](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_7) standards. It also uses the [Token Library](https://github.com/FuelLabs/sway-libs/tree/master/libs/token) to implement the basic functionality behind the standards. +The project implements and follows the [SRC-20; Native Asset](https://github.com/FuelLabs/sway-standards/tree/master/standards/src20-native-asset), [SRC-3; Mint and Burn](https://github.com/FuelLabs/sway-standards/tree/master/standards/src3-mint-burn), and [SRC-7; Metadata](https://github.com/FuelLabs/sway-standards/tree/master/standards/src7-metadata) standards. It also uses the [Native Asset Library](https://github.com/FuelLabs/sway-libs/tree/master/libs/native-asset) to implement the basic functionality behind the standards. ### SRC-20 -The [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) standard requires that there is a maximum number of one token per NFT asset. It also states that the decimals must be `0u8` for any NFT. This project conforms to both these restrictions and thus can be deemed an NFT on the Fuel Network. +The [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src20-native-asset) standard requires that there is a maximum number of one coin per NFT asset. It also states that the decimals must be `0u8` for any NFT. This project conforms to both these restrictions and thus can be deemed an NFT on the Fuel Network. Set functions for name and symbol have been provided to the user. While traditionally name and symbol are written into the contract rather than storage, this contract is open to mint new types of assets. This means that every NFT minted by this contract may contain a different name and symbol. -The [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) ABI defined below has also been implemented. +The [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src20-native-asset) ABI defined below has also been implemented. ```sway abi SRC20 { @@ -49,7 +49,7 @@ abi SRC20 { ### SRC-3 -The [SRC-3](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_3) standard defines the ABI for minting and burning. This has been properly implemented. +The [SRC-3](https://github.com/FuelLabs/sway-standards/tree/master/standards/src3-mint-burn) standard defines the ABI for minting and burning. This has been properly implemented. ```sway abi SRC3 { @@ -62,7 +62,7 @@ abi SRC3 { ### SRC-7 -The [SRC-7](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_7) standard defines the ABI for retrieving metadata. This has been properly implemented. +The [SRC-7](https://github.com/FuelLabs/sway-standards/tree/master/standards/src7-metadata) standard defines the ABI for retrieving metadata. This has been properly implemented. A set function that uses storage has been provided to allow the user to set their own desired metadata. There is no limit or restrictions to what and the amount of metadata an asset may have. diff --git a/native-assets/NFT/project/SPECIFICATION.md b/native-assets/NFT/project/SPECIFICATION.md index 8f0c2d41a..8b6fc4375 100644 --- a/native-assets/NFT/project/SPECIFICATION.md +++ b/native-assets/NFT/project/SPECIFICATION.md @@ -39,7 +39,7 @@ This function will return the total number of individual assets for a contract. ### `total_supply()` -This function will return the total supply of tokens for an asset. +This function will return the total supply of coins for an asset. ### `name()` @@ -65,11 +65,11 @@ This function will unconditionally set the symbol of an asset. ### `mint()` -This function will mint new tokens using a sub-identifier. +This function will mint new assets using a sub-identifier. ### `burn()` -This function will burn tokens with the given sub-identifier. +This function will burn assets with the given sub-identifier. ## SRC-7 diff --git a/native-assets/NFT/project/contracts/NFT-contract/src/main.sw b/native-assets/NFT/project/contracts/NFT-contract/src/main.sw index 13b21b7a5..f2513d956 100644 --- a/native-assets/NFT/project/contracts/NFT-contract/src/main.sw +++ b/native-assets/NFT/project/contracts/NFT-contract/src/main.sw @@ -31,7 +31,7 @@ storage { /// /// This is the number of NFTs that have been minted. total_assets: u64 = 0, - /// The total number of tokens minted for a particular asset. + /// The total number of coins minted for a particular asset. /// /// # Additional Information /// @@ -77,7 +77,7 @@ impl SRC20 for Contract { _total_assets(storage.total_assets) } - /// Returns the total supply of tokens for an asset. + /// Returns the total supply of coins for an asset. /// /// # Additional Information /// @@ -89,7 +89,7 @@ impl SRC20 for Contract { /// /// # Returns /// - /// * [Option] - The total supply of tokens for `asset`. + /// * [Option] - The total supply of coins for `asset`. /// /// # Number of Storage Accesses /// @@ -203,18 +203,18 @@ impl SRC20 for Contract { } impl SRC3 for Contract { - /// Mints new tokens using the `sub_id` sub-identifier. + /// Mints new assets using the `sub_id` sub-identifier. /// /// # Additional Information /// /// This conforms to the SRC-20 NFT portion of the standard for a maximium - /// mint amount of 1 token per asset. + /// mint amount of 1 coin per asset. /// /// # Arguments /// - /// * `recipient`: [Identity] - The user to which the newly minted tokens are transferred to. - /// * `sub_id`: [SubId] - The sub-identifier of the newly minted token. - /// * `amount`: [u64] - The quantity of tokens to mint. + /// * `recipient`: [Identity] - The user to which the newly minted assets are transferred to. + /// * `sub_id`: [SubId] - The sub-identifier of the newly minted asset. + /// * `amount`: [u64] - The quantity of coins to mint. /// /// # Reverts /// @@ -266,7 +266,7 @@ impl SRC3 for Contract { amount, ); } - /// Burns tokens sent with the given `sub_id`. + /// Burns assets sent with the given `sub_id`. /// /// # Additional Information /// @@ -275,8 +275,8 @@ impl SRC3 for Contract { /// /// # Arguments /// - /// * `sub_id`: [SubId] - The sub-identifier of the token to burn. - /// * `amount`: [u64] - The quantity of tokens to burn. + /// * `sub_id`: [SubId] - The sub-identifier of the asset to burn. + /// * `amount`: [u64] - The quantity of coins to burn. /// /// # Number of Storage Accesses /// @@ -358,7 +358,7 @@ impl SetAssetAttributes for Contract { /// # Examples /// /// ```sway - /// use token::SetAssetAttributes; + /// use asset::SetAssetAttributes; /// use src20::SRC20; /// use std::string::String; /// @@ -401,7 +401,7 @@ impl SetAssetAttributes for Contract { /// # Examples /// /// ```sway - /// use token::SetAssetAttributes; + /// use asset::SetAssetAttributes; /// use src20::SRC20; /// use std::string::String; /// @@ -463,8 +463,8 @@ impl SetAssetMetadata for Contract { /// # Example /// /// ```sway + /// use asset::metdata::SetAssetMetadata; /// use src_7::{SRC7, Metadata}; - /// use token::metdata::SetAssetMetadata; /// /// fn foo(asset: AssetId, key: String, contract_id: ContractId, metadata: Metadata) { /// let set_abi = abi(SetAssetMetadata, contract_id); @@ -564,7 +564,7 @@ fn test_name() { let attributes_abi = abi(SetAssetAttributes, CONTRACT_ID); let sub_id = ZERO_B256; let asset_id = AssetId::new(ContractId::from(CONTRACT_ID), sub_id); - let name = String::from_ascii_str("Fuel Token"); + let name = String::from_ascii_str("Fuel Asset"); assert(src20_abi.name(asset_id).is_none()); attributes_abi.set_name(asset_id, name); assert(src20_abi.name(asset_id).unwrap().as_bytes() == name.as_bytes()); @@ -575,7 +575,7 @@ fn test_revert_set_name_twice() { let attributes_abi = abi(SetAssetAttributes, CONTRACT_ID); let sub_id = ZERO_B256; let asset_id = AssetId::new(ContractId::from(CONTRACT_ID), sub_id); - let name = String::from_ascii_str("Fuel Token"); + let name = String::from_ascii_str("Fuel Asset"); attributes_abi.set_name(asset_id, name); attributes_abi.set_name(asset_id, name); } diff --git a/native-assets/native-asset/.docs/native-asset-logo-dark-theme.png b/native-assets/native-asset/.docs/native-asset-logo-dark-theme.png new file mode 100644 index 0000000000000000000000000000000000000000..0fb81657ecabe50d1c26859485e97798522f3547 GIT binary patch literal 18135 zcmeIZcQ{<%-ZwmBq6g85PC`T*ozW7aM~R*wj54B^!Az9VQxFoOB}xP#iI(UDgCKgM z1yM#s3kDHJ_w141`Q7Kd?{mNJb*}4q?!V4hBm zjiwDsaY$g|ib&&9P8hmiBEPg7b0xoaO;@#_w?F-Tvz_)`1&RV4+sf@xEUzt$hLI}5 zS1K|y4mJ1I+V5?JvDW7|W7yl3v8qp2#2y8m zm(&Cg*?+8g5nzkAvqGik`o<Sr<+gvApg-CJ5Z9Y$K(Z(5RDUOg8QuArnKT(9$R zQ80!@lDl>?@g)0XaT*B@tLQe9P6wIwNlCrVf80|>m20^RjppS~f1Lh$;Gx6$?Ck)f zDKnIB_WTsVMe}K77bxdSrhPq}-uv8u$1T`m==Vz^`c#{Wo3&S2FJOMuum0j#Olreq zv&+8ExcmLmJL8`Yb#XVxjUN_1bc}s-qe*S?ee2!0id!WWJ1TqBZKR&g87q}qk6Zau zdDX+?VV8?q)iVPhF)^~kjDmLWb2aOTXV@@9{X}1oF(=KDpG3`6$i|r_dzmOu{{Aqw z(|PIK1nDiBZ^x?DYonCs&}5~R3C*Kt5Nf*K{*`0&pPOlHY)~?H>1rpzWI6s_k2!^} z^w^1#th@X+xNDDNS+Yhhj;eMpLmn60EbtDG(y%YSHon5Wj$h0E)~vF&cLWOm?pKUm z`y~Sc(J8wE9%f~59p>omDGqn?c5oI)d-?#b2LdUpp?%NrbidWgs2>~;?ru7#I;7*1A zj=#STOhN*MLW!fK#l8JpBqS9T6(yij5>irPKo2qGT`zw)TFeV6KqT>p#x-Z8qo1pf zzpJ+wFOeqP!8^cTg`XdI&ifDkJberd{wD8*{7VafJ|xg^9|=iusD!7d#6OQf`fCOP zME+vve>(zc1_Y{vi8InWz|YZHGtk+~U*MlfXzLmn|4o4?l8dXS#=^8RHqC&$10 z`2_fRoc3{YlyLTN_5_F`0sbWarN6%`;=h#jFT4?-oQm_$i~!U9P5)nd|3miE&Ok2% z1K2fh#{lA_y4O_riTuKxyd7PgV5cADWtb5}5z)Y15yOGIjR-bNA=g z!}TdBLWg0=%FBfMZef;IG|7dsp-}r*Ow4{Qhq@#8x zD*!G0uf0)soQdXvN=b`BrNpG<&7e@2lq5`6Mg;f(C`{siKt!mtl(V9uf|#7Nth|_v zgRC6j_=@skPEv|cc{oA_3Uz@0E7SkIh?cHiPTnZw|A&x(oC;=8MVPEKOiJ#5LOe;h zgENo-0F%i>;XpJa9K{r+fz%);C#wjRl9N${{^gf{`^SGT-k%`+@1&CvgGvH<<{v&U z^_S28WkO{MV&4CU(<)2+zufvyhksfq0Mq|z0~R1)J(Ku*LHo-m0EYi>UVnwt|II0Q zdH*xXzop;*sOvxK`nNRjZ*~5Ucl}3Q|CR>+t-f@n`vX7ak4pJI;C4bG|spa+Q;2`xrq01in-Ypc*hMF6?%zAA-0(W$HZs5xY(2V@apxPs2;kSgmI zAdcYQrr1D{1{#M;5N`%K!N+Lzpahn32IA<~dBs|j_aUA?4T*P87AQ9Ezv!wWcH|F8 zGmlM(3_fiaq}n(oeGS|M$ot^IB`hnkot|{}wCn%l>F{m${)v?~pGLPBDoEi9|

Eq!D135E4kl#JS@R?5?MKr;ZvWN8Ue<2hDdi;!h<86 zvFkqE1#{Bgchbz4`pS&3A=V+@9XkDp_CuxW5*^-lJ;RSlQR18;~xX+y$#T_9WGq07xlCaxx1?pOgV zO}edaOZJPUET%XWE7IkiENbd#n}e=*Dislsxs!)Pu98W2-CKBajYHVBswT{tNeN`} z(o<)WYYsuhyaEzt>qG-TlflkV z>|9=RDIN5BbE($*QOnVB`T%JH@AXoyOSS8Q*IzVJTg4tcD!$zunRU`AlpGi!&Z$uw z<>UVWmrfEtNXrNq>h*O2asT%_KkXkQ(A3El_^A9s4a&^>XSyZ zyNCQn#YIzEC(|A$N#BS1m1Pn`;mK7799?Gytum#ue$hh-$jzEhJ{^v|Ahqnrb4~h@ zp|%%>Yr{abX9&-iXD@byy%(uCq8tjp8C}U~P{a(3XLkZ)l;GdzO%-akCM@j=s&Mi9 zneH{7vbEl%9V7>{svKy`v-!!_i)cpt>?!fhE^YUO?s#@N{Fn}Z^4qW|iy3nCWCBi9 zQIrUlNAJ?S0_9i=Ukq!+$Zx~elo~PuOVj~-Esw?}r8@mcT+{vO5m$-!BeKaHm)5&C z3$9f$`r#8h6jIA?m1yCK27i>ku_CYMVPP|r&cPpi&`A$A%UJUCUA`q)BhEb5?%(anWku-s5^ zkE)6eEN?6-4j+0|=<51fc~Lcf5(Q$6$b%vv(l@eBvmWX0b9R!|hX>!Vb_K{U9R4AJ z8-~@kgfwQi!p_Wtx@gKSUBTf}vSSLH_=88a&DdI`oHJTdPL_<&$*6@-NhM}q6O9^6ITGOYr0L^WDwm!sPdBs9$ZNK%N5 z;OOTcPgLtAY#ASE72zDmZqY&wchPs5EE1J zAQW`tql<0t6x)s&>hxrAA@OuTC;*;E|Kxm+er!T}bpp9ylo45TnsIX|l$20FS=GrX zIE<${%Yl0`^)3fbR@!l-Ro{@~xXSwejh2kmDkGxZP0`f2pP2f9q#Ye(Swo{1C4i-K zRdjUlQR7J0xO8=V=2Igevn9P2KFvh*wg!rTWTHx0oV-t2)h1kG%rWRkdu_yzXkR8= zAv7KudBX1{|L#|FPHsuVr!gb>_2_RkhD9pibj|cc=;tO82Ek!f3Y*9Sze!7kg5Qjx zPR8XDW58R8j!(5=>JF|Z-65HYODJ`Tu%vLk)W+e6V{|(*Xh;6@E+kE9+;r(|f+3i^g)#xWT&e!Ec{D~bVoaG(Sj;mNxCiJ-_kN3Ey z7-%k9Z8Gs<{N%dUFUl$uNpt%VLe4V?RskdAGA&$djh?8B?y3?9IRBSrhjrBZ2~PGT zQ*oo8_s0zk-f64**Z~ue_LA?Mx3^Q|TRfHp23=%|voscMdOS;2wH95OX;PI5`SR&6 zbDaIAa(*m|e`x7fmA|-+ZYO(tCOJV1SZ3$}Ptv>;qiEcB!Vmv(tcsJG^nPV!)3sC~ zhZufO8^rn!CV1QC^{s?IX1z}HsAZk6w(*L7kG|yRK6jrPl=_+|PA5ss!TgzVuo_%_ zjmBe=jpf}Nvvgynq-m4%iijiQe~i8iwHE@4A95^Spe)&Q29~>HrGBfw^n!Kn4h=35 zTTpvKOITzN^RhVlY^W0jJ3pt;da3D;7SCJpEw0hI!ph}Urj&;2ip1`>go>2YKr05K zCmPulnj2;O!dQKn@jc_^v%XpwjIH1r6{A}rgCBnJ99}TqE7DO5aI5^+RSO@ENH>hf z+cUt$q!tU8Y9-ED6lHO*O!CmJX4^Oa{)jt<<8H;azxA=pfM*>90{nTz?_t54C;965 zrU%fgb)3yo73=1&ZS~pErP_8Cy~Qq%*LxZxcwV7DT}13;oxM#6!Id-7?LEmjvT?~V z^Xa7lmtJ_PYxt8Ku|vI`y|iTm#?;*dn?l2A(K7O23FA4#Z3Z zM~L{?85#|2#VaZS?koWKT!n*AS!Jfj8Y>|{@m2kSQJ;q`^F+WUD1ZCTE8DIIPY-@I z#otB+b$_*eV|$VL8FjDzUV3ggNywMQyIC?C^_tYVT89{HfAPUBrIn`9v2~IB`KLc8 z2gnfMAvUysK8Ka2Ys`ehW{tFEmLzkrrWUzi(L7$U=B-)qFhQA5b!oZwpuVe0{5b zm2D|elhKXii#T@1V)m|Vqy)dUAIb6{fe9CP2|F-MVIO8MXf-$Dx(;LlE!8p^rSDSBHJSQIEm>b(73>VroYOMxo03#OBU z$D5AC06dC((JJCnqp!)jxwTFIp{__$kmMd^Rl$=3#_&8x>u*bHVuea%1QevX<46$5 zm+;|?6}B)hmX@PC_GFDCeuAC2+X93~p8Ol!K$UD_fLA@Q@G60o0$7=HSk$|^rm%$$ zO%OTU5?U2 z81&@b)IBkoDVtluaUuM4XjGmmCFre25PXN$*_TYG>Imn z7OJiFfw}JjXD_Ma!(7$Z&bEGP{P}EgV4Phw4bbr(HEJf+xK)u_ZwS~J*}bEWexG~* zYQVmlkQf|R$_*sLcb?OWU(=6BaQODU18<+ORLaEw>4nu|J-Fd3ATdSU`JpA|-`ur(W`fg2wkz|FMFqVh2cNM)IX_nluPW7RYiuG)>>3Zz2R>icGJ2>#n zbJ}VS=rdXBw@M~cfHnm2LL^(1aSSxMCx<(O(Gv&ZcC$_K4x6Mv-NTnxnMtdj9V#s5 za_dlSeo}s*eKmt!IT28@@ZOcy^#_lzCxRjU1antrFZ%IF1b55&1MtqZcr~~(nZJc_ ztv7L{V%3LpYwAR>FTH#T)Mr=ih1DLs6Vd0<@U7{v<_jNJ#a;s=X!o`{`6-sNZc%ZfFiGzgDw`I>?~w~skwmEcJk2Qw5h ztNxblW7)uLrJ<7+%7s2#OOF2BTR-fTg{0cx&}M6t%Oh*Lb!m*YNWVUxkqw8g14uJ{#|QuF~0${r+^V zd9ato`NKdny~KC7(R;OYs#Kgj5}ZTIJHTRxJ$W{sY!LKCTKKk&kgp2g+AAfvvTsl$ z$srr(iHeU~NSG_$0abS}g=NM{T;{ya&a~$B5m`#FHo%OtWcgtT&TgrV%8rq!pe$TF zJMd$??bDHh`YprPObe=%`&H{yRr?`TU4H7`QC_KjkPUa-tMFc)- zn4w!uvp)#)C!D;&Y2n;N{y4>>mIu+_}UBh#Dwi^-e%Ya!AH0Wp2S$NPb7nPm4e`3hM)hP=yf$H<>Bi>NNWmm?t^F#uVI+)Le)(THgKK5&90h(t(a zjEB0RO8e`y4wcKEAtbD2pF*Fhvb(U>vuR4^5k7d`h?u6VLWVQyq^1rrMjfbu|1NGz zR6I^{Qf$${a@s~*HzgCmv_NV5_t2# zuVKBU%{5M3r|#$)YDTQ>tD2Ov&xurde!QbcWy8st+DEIG>)3o4Ho_aiI;WJLE!FDO z*N%up*E!~oNpN8w%IAG~mCcU^)O$xkzoK+U6H-VL*ZRup^CUJl2rRS=sqB0=)vv)iGNSy`6ti|BBg>dWz z+*5$81>>bvAaWcRF2ta^;D}d!-~09LG6i6?b^KR|S^{hLh~F8XvWA>u4YxQjW?~@g zE_>7Q;nQy?gT3{p+%Db_Jh|$%04i#x@Wl2PjzQCO6ezWDAApwaB&4Y2r6vA& zN5N;q^^GOfM0i*%U>b5{LqNYUwye-sfgGIt;X+8qC6S$pV3$L7!NOBL^Lpo?K8jgoo(~5K!Q+v&4OhnidKrr#JvCt4_cU z&`>B}xu`$%I7Mqy9yFu3o4%%N@!kt*KG1?91ggv4&-yu>Ly9ZJH|5cmG}k^b&K7_D z1^Z13Jyn@UV9i(PpQg0Y3AI@EA}{^4{2>v=pr zJOW|n@NMK8r>@|gzxj|4*AUfABZ9xa82N+z`!mgZCk0FkA+6U^9#Za?0jmQXM-|&X zV=Sr~6-+nR|2pJH6LNL~*c09Q`18dXR?eg{>Y=0)zCE#xfx6%cx`|uyIEe?WFScdK zc3;t!V0&*1J!LU)#E?nYrhsOqgh0&`tCO#*zC=GQhbt;^b{h-`3t`o|r)majkK)2T ze@@;HhMY+1Oq3uE!I-u?eAlB@n8p}I1eMNB9|lpAR<|kg0%r@FIudtWaFkVV!<8cR zeVZQ|JkLe|rP$a`9QzqUTt@`g14%kZZa7nzQ&#DV0@%H6%8wS18U5W_6-wD;4nZu6 z01*zuTp2Yi?fCJYQ~&uZ>9STwxYZ%2!OuYHVCC6rHGU@Zq8bRrMOq}^E8BvM2bd!k zaTcD7qRMG9I|{OGJ4OX$$tcGCYobTrD*qV%3tR5l8Grlpx5u*jNd?eb4c2snO03l; zm+n<^hS0))xWSHQ^h6AbLYdK^T`|q(NCTC`8<)(g)z_ZIkdBIb` znroAw+LvBKrW%uO4QfBe8#=!1s={N=&ZpRi(C?nlJwMUE*%}mbSbTD(3)v%&3hZ#! zeCsOLrTwHKoTKJfLr}qTNO5oH6xE^rp(+>T?87kbbA+QTXXQm`>ppGY@(Eae7 z62q#(rB$*cL$+_U3TL*G9iWZW5Tl~Chv3deh33{!%Bgl%wqOfZ$Np0P9~gzPYYcx=G*XR1fPxH?_2$f*m04z zc0{Nksz-aXz=m=asPu6{-|AIqYfr?~=0NaVlUj87`@jh|l#t9_AY$e(;J7>{=FBB< zwoGyfg~%@=SA@{=Ub%rydu-}ldo_$KZaPUwx^h}{QaR|8hJBfIae&MUO93VRkdP%JW{M$k|^_v2kvJO`R;5aY{aGSIo4O#a$dH= z(t-5;eVyA5UQB$p>ja20AsW+!Ly!<&q3vd*DvV^8-c_fUC;6CcQJAZBKM_1Ru0ia$ zMXniM$QKseCW8+2;&ssRQ`{@TCkzUz?JFT;Q_Xh}67oOqU;pq~MYvs~bbS#ee-7^; z#O1RO^1;Nc&7}AX^FI&YLj+p4hBl8)bw2s<8H@$vRpt79UEc&Q?qzaZ%UO()!+P^g zc2Dq(u^iqgS0fp?&zqCFak9!0wXZ@sf+VBDXBpFO8Q>)CFCvs2o>tt-Y{!P8&t9t* z%D=G65*fs!oxZ1fP148I{aY*f@Ejf^*=6xO7oul{6IWPL|7$D1B{T-HY{BAOd;uj@Qa_!}mgYB_5Av=rzAUn>_!9^adHPXy-5}Z% znvF+f(}d0>ud1yT^4hT`2~4w~Z%_ePwcN6MO+x4V1;S=14oF_rwxCyoCosmlo;Ce- znQZakrgkivldllPv0+Q0xV0kb&G(~Xozp1xhH&=R?=8&D7mh%jWiKAJQPjPeqgYn| z_TsW)RM)6rWLV6Po~|643zQpgGoo^;L&j;GoBGX#A&0uKkH^0>f8sHGT|%$dmheM; zt1V9@QV_q74RF8Cu+lV~`?b$Vu7cQUkUDU+wSlgQCncK52bDh&R9Q49YGJ z;D>rwbEziOF3<1Cr@ot!uRj<>UricTg`DXovaU$FTW8E0-=E0$qd(0{jKyK5^66%X zBZWX}!P`DRNXUL=!PC+_D#a-MZx*T>cobnpC$%RezG2-3L7*$QmDS!r8Ppve&3|~1 zp)!kqOOafaG^TNX%=$3X-~7@7c;xJcglxq&WwnxQJ8PKyh8^?mvr}{Uv}EOy`75ZI z{@&Yem0WndK!gl3Aobb!l^IukQ*P}-daaC}D)IT9b}75X)Ta@@N)0A}ETTx|LoOW` z5yAm?3b}Szkp+#sZFo}ou`@AVEw6i5SS9cbpFv?sFGL^xZhD?iVTY*)b4 z>%@(;Ealb9{ySU_-g^w84~+Lj48n5+(>X~vv%d4iF?yvfyqryqZ~7gU<##YnQ~%9~ zf2uq0tI!xiaT!m6dC^LETpepschN6Lx9(_6@Q>p7O-evByO`BO#CKw5#0)cT58;e8*rTy+x@SFIy)nTiW*>AJN&H%sgbn-_JHG2=eeZ`-TR z4n9>19qY~R`KkV*mHJUrj>JIz+0;%*Gm3zE6_V9pf=LLiW&cK8MVlU&dA%4(ExT|x z3rAOXKnuJXe9M{7G#Sc)0^F+NbEJ35?RXXKdioj}SC}iwA+R}H5aUq$=i-WZj zWV=`->g0SEOY?cM5VGA#3rutFlWDXKr@OrRcF{4W`fBn(MKznkE0%%7drF2D+{ovWHDbigXtQM**2D0$(G6F7xR#qKjB5zHs~?x1 ze)G#z!^&pHIclSoH%^q`zu!G7FE^*|(l>fY64G1zZHo0t@$mr# zZqB38X}seWMzHoEAsTj6_>s=R73BM+{B3wLqpB14MpQgWh!Hz(Jw30K>&q3-y(``8 z&#e23rRUv6b=h&v15;`i{hul_N>BuEQ@CPBNeCGaLzt>2o7nJUu^14Dsg#HXXjbCR zYu0JtwM(u%Ew+38>AQ7Rw5>b?x$vRxql-7`E9j$RE(Y>VVg_xQg*Xr>AVxc^Uf1zbNxW4i~P`45wBW z2$xCB$qp{eCO+yMOmS{1B*g}YL*9&elj3l@6}+Q}lcbEJcae*|)_*oAR&=>G(?ih{ zy@?LWi3hOO2bgTd0?l`mgpTXW6z?zUn)vI99EEc14xD*z1UjbQ-C@C4Zrijgd?B1S zn|<-cR)fuoJ%ICWh4x-@{|xWK2!|_)~K_xJRgki^a4;&Yt}K`D%H)pENH#EBpwHc&W$x z-nlKw>kgu<;ed`J#gFVg^@cpw$c-7-`9|UE<=TOic1lPH#cSpivfZywCFzZkscwuo zp4)lV0U#j~Rtq2Bpt6Q$NbS?#7r8{*B;fvnSh^6ly_ zroRIhBT2HTVH6eJi&1^#wAZQ{3R*#G`!G0@%tPrKV^sY!fn7C{ozLQZDc0dare}7o z>&w6KX_mjQjhFKp_RTEKBl-&lB!&~KCvTFX*71cm zZkM>c7LZ1&vyWb&jTOoB^1`$Z)Qn)won?@XJ7%6yi|5l9@s838n1;U95PJ#SNs`yd znBG~icmRR&bhQG`gsC>5B?Av7wce=+ts-&%9Hm+si}ELFx_?s0;N;j*QA8gS5!vZm>barOmoK z*aPI};au#2)CXf*SHvQ{3F8dSA>9T#Wu|RRETl7$rm&$8(_3~VXS__sbzSGtxL{k_p&I_!TspX}>(3r-9ztvIr7erPgJF;l(fQ;+ zH#%04AHr_2FxRC1i@v-f!X(`85mT0_iPy!!g1t)n1 zo;aioiz!)jOGU4FUTyrrPB^D81 zJ|%l>Wu;BmVV7*6nb2Em5(|^-MpnIg`EI}o#T4n}W1p?OsiVicgzMTHj(XT)Cc2xB zh`1ga{8VF;F@SH=#^t-OtvUD)w z_QUS^_&6d^2F~^1CU$^wIo!3+y_FaUlqJt@spLhtMn3`G47aORx)tW%&~2P8%cm$E z;J+T(2h((sTK3{sX&i+0&b4C=BT6dtX{(6SX^uu&Z z-=D)#@|u3q7`9JF@hwLl_G-VX_Mgk#^E35_RutedtX&qx%3V`JmVDTmcO6Hv`uDGo zh#J!4B>V}Ux~ZdE;TbAcR~ztpbw`Hmq~`@FTzz!cWz?oXEq>D<`lbjn6+-*t2y2|J za5fTF{vop?eH?;6zM3?{RghyZQwAiWG=W=+vcYW;8CXeQ^)(rpT#Ihg<=6;2-F+@l zrtXg7?ziDLd6S_O8+0(IHwz~AwvlVJD8lRoiNu>-OF-evu(8NQmyvZNY}Ke;i9XwfXUEKkfVv}f=rK-G6*^$!>!5#=X=neteUAEJ1i)A2xvz4YR%BqVFYBA$r-* zCiR!nI=Qt~yJFv_9PIYFLSGaY;hU>-W{suu6ovE(f3f+K4jEL==)k&Ven``@uk4H; zAylc{CHB65#`wOV+i4n%5(i)&wV^WP9<+QXnCN}W%fqQH$U{zali`|?^>?qxhQjkP zD1xWM=NE$&BLwTDM-L>id*1k;%5-4I;2MW?1+uZK>QzxhYuG7+H>z`+JZ)tY|G(e=R@TITU2 zJyUA{eNH57Mfbz53@<37?MeDOPZ-e^fw+f-GkBp@oLPeVGEIKrg-(eZ?$8G4VNWwyntnbOX zK`rE$?_fdgQ=6fI^>{|OaJAKV&U+WK0 z5nDe$AHNL`GuTVNyXlhGpr*;TiEI^{;FA9EfV+ECe7oWgm40?mUfVdz9m0K0xLE%fu;9R*g9T`_L6jGkq>Ya$F328l1h zp})z`$%W4JX1^K21lh4i3~I{Wu@p8C>chZBrqqBVAZrSlbrgX^*U}QB&w7w7g~^$b zuIR^*{ICIziES{K$kj^vNr^y?in&im`RJ!)_-B6h*&jCQu?8g`ytXmqx~wls zUc9GbW;J`~$x5Q;8SZt9`h!rr&Yf2dvTp=TRad*gdIE^$@1hb`y{q`$y-^Cz-3J+s z88~#G^PidI1SlER79#rMB9473AEcOBT3Z-7AqGIrMH*MoJU$p2J3q-=Q7>6SZ4wH@ zt=~*mhY6ZlzDc9O9`vq8z^Z4DoI{%J%-VLuE{4ix5!%h~)+}%iieb&fTr$Q3gsTVs z2sBU!ptLTN{Vu4?Tz;B^6im_@O-459d1?>o_Y2%~zNe>RRD}QhN~7=%M)xi%O1vmA zATIrQ%gg>Q*Zw>WPC>e%ssBL8GpPT$nak~uqdPYgU15$(E-^o>I<}{_K?# z?%q?kwaMEl5iEXX-E(8PAtI`;xHRt_zKMLJ`YBz*V6WV8?d$o~=R;&;>+TUZu`#k3 zi87MHXX9x-%D0i@rw5f=BG-$u484VWyP|)k|CE27;ue1`$1YLc0pT7#{xmI2>2V77 z2_jHrek3&Y_u#_dj3Xj(cmw^-9|W;0t!7%5peZ z3gVH$;obVw0^A4XZgCEegMv${5kNc+M(+_ zE-d^ZVrPb3RL8Om6h`A?%eA8~zdYoB4x+jZJgBl3u_Mf0QWDyV{1RzTAfC za&92s1KvWYX=?#Bs`ywY`bA(-b3W~x6nzXvW#(zd(U~#wUC!Lfn?HMeTBBzny{j_P z!MOwLOt`O04m7o*vkNN2sz)!pt#hO+=-LNsxWe==}J*hMNLMQJ)-BW|A&S5Q&F3l z?n?tp*RuDa!z>8?s4JGN|8!G85p=wlU?Ze^>b)DsJ5ylFRY_p{}GWC=kmx#{rU`j@v^|w10 zHWBW?@!$Rzy=w0faPNg5lLLw5F9e5U&4Tk=R-#kV_Nd?UD1Fh`Y| z{|VQ?Eb4dwfhJ5w(C!rZ@#H5b5p@SZztz?NtfV1lT~4Il8WH#ffao}>3ZO!rIE);h zn6?0ch-!NYQgZ=TRUj0fOuH#c|AkWnfGq{|(LjyS4kIw$sQL#*Y4{J!g+?NnQBO{I z@f0`7gj+NYKD*@72_Q0V{DEZwgL9#|fhGX(t-U#M5CGl)7uCiV^B4#GDTV<`=OGS- zJenjT*a4Po&TD$#>Yrp=68W2;9)R?Uta&xRdjHKlvD0ZUVj%5FezyF3jx1mfe&7wX zP~IPW9w13t%aM;g6;w#vL6)ZA@1X#wG5ob;Z4Lm-WzV%0`o%I>=eFBWLi+vLG~Gd5zLAmJjD@S17pOi7zMxdCkPNsKmS3)5d}7;Lizy$ zGyYoFcB_f~!*mGg4r%MBqYL)pV>Ydk7Pmg??a%#%%b!WtB9W$0By4?-zC|?G6Hc;S zK)Gk&KbmB617W$52|8i*5ijeno?(~cFD62J36y8DQJvIdAiuim(b299$=~My^BQt^f)4dgDi{0M(T1NzM0nva>r($xqZX(k6`eWvf{hHk#XaJg~l{=drDLAYbq-hT+XIPZHathxEAf=|^ zGqkIqcyg*sV%pt9q}2>o5zO431gipZq7q1Vx4$q%g%teIxd>}nCvD)MddudU^j80r zqb8kWg>p(X%OcAMw1kJr!|T9+8{ra3rc+o)tO3@xRt-{W?m@&BgPU|{1Hd9JUXWCH zb>t0~V)L3)wnLsA3U}a+Y0I5I2PuvIdR9;D44lyYFygFRq{CL(qa;^%(_E)a8QuRP zlc4ZfqsTW*$cJk|9~!3HLc~4-UqR@~;l|y?(c<)Qa>a`mCkB=*zWy~q$TENY3?n>PY zY`kLh*6$Q$&4knMXId7Exl8K9(b02Ov9PF=I0c}#z4sB*m6-+D5+KLrpDF@S+mHK0 z4eDz{=~E;&-brLtz7v5l>TEZMRo`#yGtv1TVJiKOgH$&w}15JMP*gprVK zFi2C@kz!=~UZeN@zVG|-U4FmME2)Kl}!zn02 zCcKTTSg6k&+1+ASrINByN#4=D701^q;`REC^1Y5D4jP}S&aSJD0ckXGU&qaP|T>f#I z@Tem)|CHS8tk5};S4NAD==&DqM)ykZIVF}~Z&4?_ZV$bWvV4i!RNX$>LF?_3wN!ic zVY^_uz~$&9nAnT<%eg@h*x63O3~!MVcw4n4v#dF!{VzPF<9IYre-Jl=lDlt`=3}hL z@bm51X1B<(30h0$$$hmqE1wyTh0s;iCbxd3fvfBI2Goun|JcfGZ5<2^Wo^Jw(iH^s zJme9**lTxzYR&bheyBbE!zcj|}57RA2NaaZgsHO80t)>c>YCtFolw)ZHa z=lm-%D?gwV6s#)lz`kzk>%p9Sy(Jx-eH~pSL%b2d@F*x$)I$&sPM$6S0*)@O?mnu5 zYfY_!0`AVLg64Ai()x%iE^hAHxBOj9ZW)+5-STu&au!rqV^j%&0RrAG0S*Eo-d;XP zSct0NAzc{wo&2$spupjf08drHoBBoqSA6|l1fY^oNofhq5ceQiK{ZAJ6@O+dQhqokxHB`qr@D=Ps;NFYOf0vtjle2{0!B>vFQ za6vlxyCVYJeSHMTG#wm$0|QhA1;O_M|KQIXp|Afpc^~9oS^)Zx3UNS4$w*2|d3#I! z>l4TT%^*PJFNXe?PasXfHkC4VLHY*zJGp2Ex%dQ}{Z|rNI{HR`Qy`1v>h6s=6bdNs z-zIZ*`g^9LS!J)F4FQ6a~^L45}&0Yj62eq-wH?P3z(K-QX! zg0#GhoV<(zL{R|>Rrr_3Z@Bm)fyI%D%1BE>pofn;JHf63k`BOf+`S!KU8E2`u7_Wc z*98Wo0h)Cn8!DiD_&E>;cE#VtA;8z))YsQbRglcA0GZ_9U+aVYxU>RH`d`NTI=jO||G!3)caMO|pEcKZM}ql74?p^|rA%D> z{=ED1*312HF9`@7?h2TL(;pF#4nZ!?hkOEBf4*{ZbMSF>0q)~3d;Q1f?*9v0P=LrN z%E-vbOE^2oC`mwNT@)k~Wu2TQATAD$veFPoB?lRWf2WT0g$D#X_`6(k1$qR!0`_^R zD*+Kbcb~uz(SIKu?B+sV9%)&KgtV-Ltb(buG)z_oCI=Mejm{hvwxOZxqfy8ffC|B?p&ON0MoUH?(ne@O%XrNRHPuK#Q5V*F=H?BWA}Y%oZ8 zBgfCb1<5j<<25Y}iUabWr_H5l;1dRfwgr-c;wT&WFC|5GE*JQaK0rrbll~j!DVk%< z9Pi&vP*4a^=xAIr4VhS(3Jtejh*(=6Kwf?Qw#V{ol5-Lzs#D(HDZQpBp2F4wm6ka< zEo9^C`>EDlhf4p`=9?{f9q&)_`jh4xx*4@XJ6-uSmoGLc%- z`%q-$RtiBxHd!JM0k;Af(l5_Jb^2D@>^J=1XA(SHi@gY` z(~~y`BEHEd>;xCDNqk>w^7{?1+z-Z3;=}ry_LX5Pni?9;LY^n^eMb@9y2ZA{c(-7%Op>3GeJ-`$X$d?InU3bw0(blr7}p@B5ArQKX+d687iGbI8Vf$jzy7 zX1-iyCzH=QMHzWE+xl>N*#(a$h0pP}WE#$Nv?TIy!NNm{$ui$3Q@cwQPJRps_;23| z*-jKorR0S}CH@*dYt^qG~$ za;2vXZglX@n8=9;M?ZTzs!i%0k7HjH-g#%29!~50m6k;JlgcWFGn&u-7}w{jiks~8 zKhGe>KTOk z#&gn#k7Y!7&#Z~v>rCaNuFM$OE`Cw|Q)T>Azheq0QYa1MCK^#+OGlmV*jH#E&cbVqj^2{)EALzcEE73k)5d(?YW_Xhrt?FkV)ylfO ztyDv8of;YiH8RVgQyAz-!Bx}TpyXvF0yEQq+eWw2lhnqV6(c{qT?%#&Hgmw2&^_f{ zzL5Kp@-ua{ zeKizO6w9SFgAm2jAFIm68iFsLRAh5C?~M7mo}~UtJ~3{mRJw&`Q#Cg%wWLe6LA{2% z)=M&ScwZLJ7~c5Mf9;SZx9BJe>lmdqDGvoR4xGZfwml0)D|+js0&8Vkgk8Jg(+H*p zdeqKXov--)gG%ePAZ8z*&ZszqMR7K`02eNT8&^&nW_(QVF}fG zNFnTJYI8`WB@3xGSCDu%Y4UEY)!kUmo?*A34g6PhQptifORoNFGzHl@WRt%u#;VJr z{pCMmKc-BK9RxRJ?rEK0sbb&6J*M=>h~?TaSkv$%R7a?%pHPz^Tu*AkObxVHNDZ!6 zP5f--N82S=r=w05r2jEtXF7V)*{`$98ihYj?9v#59l6pZdPPIIOE>prGWGYgQ_2#q zMeOk7q%#PGlejjc4i@eYBc%&WUVNhQ+hXCmSj*k_&Hk%o4JALKh?4AL#E0U~hwF!* z8ko-Exq7l&x2A%qwAy`sZ1i|b*WM5&Lpm&4cFK81)fBbI;7U=k?yi(=MBZ5bk7-Fr zBAZmbgNojo)=?-;SL{}H(B$#B9lEE?ifkx3jOYACSkG-sI|=&Lu4U!rnFA!ZY#kRm z_#)&vn}>OKOe88OlWfw19Qc9u41a4n9z&-Zwz1A{=d43r5NmVz$n)@w`CbFQ41oqI zNF!{;TzcmuT#7C7#SPKxNTSkK#%u#stL4k9hvEonOZQL8pT3#o#1W$$V{bY0P|pRS z4tw@_Sr>m|_e0G*?WglkS?w4%ZuIftF);-9$eHQvT2FiAQ3R}pyBl`(nghIc24Nof`mF~}UUIU}-f)J{kzm&YPG29^6f&t` zs6(B~GFrNsV)yLE*)8(IGZNi9ZZfDmK(fmIyw}`!%iN+VIkh(TSV1~cPK~gy7=CN$ z<_A(hsc^IvP_f9Ztn||?!!KMmh-b-i@u>T&8y?!A2BjJ)74H;df-xwBLZc1El_uhL z;)I8*x(w}Y41REUMA3xb7ir9yo#lM*Tt0x_I=i(IU5qJK{7g|{lo$5LttGh87_={k z*HFbN{DQ0*CQtXg35$Alc_mSi5Xl>P+5ZtkT~jnawcWdAwZ2BT0}O)Mx62?UZl?lp zquWcSk)?5ow{C+5ufqSH4wXEi`c-RHOK8}Z#hNMi14&f+x%hBoxzqF9ohNbXZ zg~s59v#bm3ps>;RGM&6Ko%}#s=|bf_h!Z@)uvV28V6Y8K3}Ne@lqONBmG{{ zGC`=zKHC)Ay*)7>Q{wmLLg(I3MFc&3>$;eC>58GJ*@GA3Yiu{VNBj-0DE+lOY}__e zpAUF=DO(JC-5v`+{qALwkdyP5$n)H2POvi9qwR|2c?eXK zM@VO+6+2>gm?AH)XJy*N@T1jZzOZ@l)3(HnQ!}x)8lhlYE$m;7ftCYFJ$3!C2juO- zjyJD3Rj|>_b3}BiHs_A|sr=(%@94MAp53a5VaD{#FN=2&a9eZ2!_)fgQ@ZSdBZ&A3 zCEz+!J(LJfQ~xqhIj`WO2*Km7($3UOKGSV)m!88|S9v49M7pRv+cXXr?OXTQ*CM6v z2**@AZc<#Yjr(i2aM`?D{6YGvJL3O`mC@l!MUpBj(#BbK%I~RFHP9#UHPjgoy^dF; zGSnH)3J*u#r>5T(yfN~F%_HZOL_C^Kk*#=v9Ct)81r#ibCvowZA$)$3t?(pyDLDYA z^Ez)Xd#e+j@Zy;fr%@R_ku^8=r0EOj0#7B2uRkaK(PCCtEX=pna45z^B;zC`WM~=2 zw0b(4r)KdfL!B@rGIHnr`#mSj3fLq2d+N`(Bf>mCNvc2F3<$^WS?<;|NI>wJk214**|Cy_E}A!x9Y;^%@GyTDxLQq>er`-^L9ro^d3a zx+H|zYKwUP?e@gz+!Ahp+qL&ZWc&p1VKPkx{@X5=zLg`lC*a|h*hR$#b4vs7yi;pS z!@0;(Da+b#LpC-xVZu*sI4L%Upju6jwneuV(&|F4L#$H22F3|AXf^4U^HAKRuQUv8 z&ZZT?aM}!%zSq;Pe~{(#_D6;~SLzkmTIm2`nMfqA>Aho9Ca}B+)BJKo{s!Xgt=abY zqZu!j$OgQ@XNi%ZOLtsV?CZ~d^YRy)$K?9iEpsaK`5}MVBvmoXt`yt>7fBEvZ2uZZ+wZdC+pelfbwDV0zCw(600LPCN< zIlU&B6z*F`!zYr=u!S9umhy}$I-TqcsS518p%`*PFrSeAvH@z zBrSX?+B4eaoOt|rg59%C`9r6Al;%31E_A950WT41Cs>mMbDu)uvD zPs&R-0dTB4M#^c^Mz@&Lg1F!8tbX%8zJ>N?k6T^tf*+zfb?3XcyOvh>X#lq0Yj}8i zdQwVOe^tswa(8k9*Ykv_<;xca`_lPkE?mR&`LyFWSFV1v9djl14SdA`&pjDS#*GBb zl*S6j%yAw*M+MQa{Y;#UpTnAxu+Geu4a!s zdnbp}Kpd_}Hi>pZSZmvt;=Mem!wb?O#u5Y%yzcJ%2x_MkoEF$#1$1gD;|kJ~mzEyT zdqAHB`GlvvlC*smL_054d48xDJ?<5x|1!U?4;m{am{6{Xi1e4wQ8ly?Eu?6*v}Kliu$pn1novr$ttjWq zD}aIK#q80^sY;~6XCj)c9;tw!prFiy&*+n*oW(l4-DSU*gXs4MR3pcFG#IU*9!Dc04~XV|=^WB5jtox3_mUb#>YLkPl7E%V~}*9>_0o6jRL+ z93w)QLSlJZ<<;2{GNg0}Vy>Z7WNBS=19--e9C5C(2M+po>~j|{^mP!%Q;HUHj~^8H zue!eP_Yz7AjbhH%0_h|PBXDFood}tW&e{uWFO6Vht6{9a%QLOV*H*wuKX%P;m!=zu z!PC%gF@p#MnK#bNm@~2OYAWN(B1d<=!f!rz5^M#AjB<=KTUgVnGP(dS*S8aI%cA!| z&TS2yrtV*EeDmfF>#twGns2T%%;O>-KPUyKBUjJa%c%YGNzP)X zzf?2Y*O-Tt${J586#0D#s3VA1{?XO2upM_S8WrP$MYGL0d8tV|!{e}MTlTIeumgFZEeM3vB@Hd*awAfn#X9msgL%1Nq)rV zPI|*5NRP(}(fsU;@%&U*JnFGZw4|W~{^lSr>L5Ms=z|Xob>&4PTdN1})z_%O% z2KU=$x$C^-5x017b{sPZ5sA`Bs1iZV5zcvDDFyg(zL4NzDS7=5&RE6{Vn3#um5J%C z{E=8Cts`n&=u@Y*AxEg%rEwnc;OueNu&^-xD$Tfd>9@3QN|y_Y8!dvc%}PuiX7?of zn3;XY(MZ?*Bi_Gl@Qv)%J8j`=2beSbukXhRj6Hg->?6+3s4(K6kl;Y7Cvm(Ne#wls z_IZ-E$A>TrpARXD4C|bEE+WX(0dQ@Pv+Tk2)YRUt-dmzGYTRYr-ssU%mqP#YBo=Ml z9x?~B*QMGetH`+QXATza*}L#Vtkp`Z`aFGeX$NoV6)d{@xk#g2V&MSjmhrEx4TI$) zht_XZQM5J+Y(epwJSj%gxDM&A36NwNsuO;EtWRa|5#05Z4?GD94cz&hHmjh z9~+U)!>-d!v~P%bKU#;Emb4wdkCkRBpu*}QUTv?$ALZOPE9N{-z{Qktx2=8q_6>?s zhoWYvVC5m@Cb`HppdMwWj_x=C62j1MAfv)P2f1qAcfsm;{VlIuNY%4v&q`z_0v=_Z z&#&RqY_)cKT3;U=#&rixns_*T`6--o|IzttaIhk~d@YUUpZ3-V#i&L%@{s)cL%|7t zFvKmi^}apVoqCPyKij6Kr}+npjv8k7)PW8nNWs7w7LH0$Bs}`EY=?3iEJPp1^QFCa zZ3{ae7JlU9B2i+z;nJw1c}PyUY}Ntiomp=zy7fI_!?1kn7ZR)Ay|k^7{oSPkKC3m9 z;l$H@?C4#OpZQzU?9#AjK@teLo=^TC{169h_lD0#wVK+#6#) zU$LOQHTSm`=@geX(T4jJ&ka#?m9 zf{`Ee)4?9hH>w!r=izyKP9MSg^UKC|(@=|nm6g>s$&4LV0`AJXfS!IMYe>W~8bg9V z+7P&7Y|f>GtDibw{x};`h?M*unFU%H0{YL{SbYU{Cj$v%Qf~{s@gN^YVe1N4Khi-= zdkJ1(AECdymC%z|TKhHy?KxZw1k2m%PpUQWTfAHJu-6YiJNRylEln4I%kEP;y`mZQ zDE!`z+s=?BQ-S=vd9h8L)0OZJ8U7LeDlL7A_{+0LF#~LLUTaJpHRyJVC}WcVAXvM# z2R6)pl*uRx{^NVXrPqh#}qnoinf!7HonlLr6b z?dcvO5v6Dzf!)J=jgINxIHlifabGHayz0u^7V7Y)Uho_?pCJ!;tKA?+)Cu#~%pHib zELE@loa!FwnLagsLe;g(*46`Be9Yr+oqnot0&YQ6Vf@h##ilN$EpPm7op0DQV102b zD=VH$yES8(jt3FQFKeo*sx$OK!nlAd*RJ*6o*H&VjVowe50G;Da%&W78RT;>YpS4k zK@!G2`4VYBxo_&(i8fQL=fP3^Rx=yl*#rRa6fe3JruOhOS1bEhNxT+@Q@ZIWinn&} z`!NZHVUPF;NOYiL)jNWh=Vk8*LOLP5o7sFe7xZCU+5VI%n zR%t&e5#Q=o3p%9VUQPHcj?4X_Xra&i)h940C|~!X42Kvxh?ya+1KEX=x%@P3qbDUSp<8Zle(Y5)S$i4d#J94Clx3wi6RpBbW^no;Rf(@#r? za+l1ox;bBuV0)M|=cD4{=JxG?=lsfNrBaHhiT8Nnc3Xts{ji;-?$cl!Kwk38v_!M7c4DH&?weEsZfri#HUYwHR=lPo{{GGn}h01PO6!aON z7nhbM7jkz9w{!B@@66VTQomqeCU!`xlz!T#WW)Ef$)GE3i(i(Qc=JW>o(XqP91UwI zEhV@z3}i)ha++m&xRMvMI=_o8TA_4IxRo8x$r$e%lVSXhZ}fBdx?f^Xm;0xTsE>n# zgGyuJW`o72{C3w=_hP3HJ$BuX5l@)tt{X!*3ay2E1p<* z&tNb#igq+70*f}JzeI!+a216j9-{1w%vkhSCDf_#;5z&HZ0j7bt?9+GoL;e!PD8Am;P*lHJM{6R(Hm>Y zYH5_ZK&a35GoMNqi@|%3dlx=G3}+90@#@ujOGhNBSbM0<#r`x+o3i*gwy%YLw^~mK z_1app{v>037jU?Xxys7ZTPZh)wffiD_onrHfS3P`_Eevk_GM|H!BHZDV^!&S${y(p zBjmAF6q4-(;p9=*1x0)a)x5Ypt8rqZThp_Xy_y5G!72zf#F;TP=APT-l_XQi47+s+ z6SabwQ+H-dW6p8TK5^i(1?l&yHYvsrk2j<76s@Y?z4JInm0NQ#=T=x)l)Hv>!2l}- zHRdSB<|wD+Zfmje_oMr74Y+2Nx4xdgmi`tw`Nn%EWpmzZ>GMnacIn*{L@S;7vXYXL zy0FdVZR_~9o7wCIv*7)JaHu8ZTGNryW5l-Y4Z=akv+lOlsiv^`B~nVXVQqcA-7%WB zQsVv9b8@B6p3TzXx0dkI+H79xAw}`!bI`mQy^wzNQxt0B9rw#4yN!=iW_W4ZeEEFN zylrV|vB9vd4+y^=U#?an>@&ORt?!ysM=8bqWm!;q_20~6$J$~p#3?MqT&g+oHGC!9 z^(6`Rqqq?{{i3#`_iI1I(15tgJjBmC;*3U8TDY^IcnB z-rZPTUCsY~EAO5;dt^jn#6kaAI(BB}8L=n2SK9?y!P0qS5-QxI08i^h*N&e`1`+$2 zQHV%S9H`2qTT71S7k;F~j03CpUgya;HL`k3jgVZpw0-?F-j&FT==it_1LhEj1C;N3jHz$t*IzxA>mV`F=xFiR(mw&JPCK;)Hbnx^roC3 zL0}92^8(qgd=K=%u!PhRL+Aac^kezPfoq?NQ0f)YMem z{gV>6mOg&`7`(oebWWzpTJnGu?_0XmGJ|p*;J~73MX>|E$$==4wxq2SJRf;>1dh;= zvh==wfu<;+a=RPllh$WVl-$ew}M~GDSB-V)4=OS z>2KdXi~PDZdm(PX)sClt{iv}@bw|pZZvIC>@^{PzyM)54Je1XJL=wus@W>T@BeJyt zNUhDTc`rRp0d+dYk9rsEeRbfRZt<5Ep+kY=vErE4#@R|{4AGE!10FX!M$e%xe$w%{ z4^vh)4+suE03EsM@Sl+b%i}2DQ)`z19_gO#Jt@p=ba1|4Agbw+!Q$fL#A&I_O|G76 z#|^ja&+6YYcxEJ$r0^j$_!GrUAJ)y&Q~7yy^_mt3e*^sJCu_S{aPG0<`Oe*Ii(<5R zY0;V(%%+ent*_{wt_!qYcNMN2O(V+R9- z7jX`~$-jR7RN=TYJG!1$*^LYZAvy~zw&4RdQ~pfMmS6Y>0b-f1ZD~`}4gqal1xD>KpJZcB+c*SV2obscyq2f4`R zye==srx^k36msu%k*CTiR`jVq7w(qrOUqZ;nb49Ip|pU03x};DAz`YbH~4tPRbAi3 z(jHwE4y}{QMfz5JRRx&1JTVF@$i8&X^sn@-?l6%dp90Z{hD>_J3@{fy&rK+Mi{Wspi{L$9f z((r);)T3K#q)*B2RWmOkuclyx#qPoU!n3m8n%ALWx%SIvF%k^r%xHW!mM>eOwN>DS) z9x`e1-07Ap*PVM6otfjcRyQSVd+ogw_4B{4tW4z-_oe}xkl4oKq{#DYWE<|3X4*Jc zIqwU%fb1B6+$t|z4WPjyBaxyW%7Rw_7MZJqTAHlB5+S<_jhLa^Rh%8#yUKN^o9BDR z#@BvjqtYq%3)T(Nqn|$qU6s$Vd2lkkLYD_~p3m=op<6`ayb|!k>9TZ;}=rDpT-aH9Y99+L2B{+Tmb>YPras!lWJ;g+)Qv#^qvj_#mgmt zz70g4=;mS31_W#2mPe+g$f}{ftNVH4Pjs{Nu5Ju?hTyzqP}kVh>Vy zv%=fqYVN9w(EE6Mcog5A*@LR<=EYf7CnPOiJ8wdPLd|X&9HY5My$gyQ&e?9p5YcC3sxMJwE>`EIe!3O^a|KuXF|WmK8V4XZU0QF&mO>wbCI{V*5fOcj&b*PmA{ zxp^TH)Z|*J9+{SJ+kvPN6>(crPcZ!DTv>w<4L}x2b|ZeYkuhkeLJ`3uu^qqevm`T^ zialw`?Qz~eu8xjUxdt*~!*6SAQ4YDMW1!Es6iP#u8AMYOhDyrqc6N4@*DIt9(SW@R zk-T?{?ii=LL-AJUtg4-y?R;p&7>TX}`4JoYdpifPPUcRB>MNM+ad*`4_YKY6HW}=>$>R?mJSYI!$M0j2`U&fA!v+gA6#@eT zS5z-YtIs}hIVokU;(D;Zw?;ed3NLqtsCrYLpe6ZbV{cMM#$~-UAT_ckZFytPz!rFz#0JTr3uPJ`~@9$+f^mq&_? z-A&|knmhaU3+wB*x}T^y@B%-ZOSN16B!+T#RNRnyU@qhos+n|r?-o4iLZV9$BbN7h z$YmBb#q+1y_$|J#&139@LP8W(RCXsZ-K-l;3RI z;E1J2R=iQ^Je!TVy$iN!j{PwbqB*d7+uzW{LihDhfXoeKP)HNo`>O^!u;%7wDWKE~ zHPBA@>6k>S-IrGNe4yafAfH&+y$_E$*Ov$qV}o@~WDDd+BK<1a_0sRf0Ekl29w*E*z<%4_iYQwj3#LQTbPA=6mX@W6gBa% zccDt(r2VzQA=-@`p^ILNYod=W&DzPgfs~BWD@afz(_(4r8P(gax?KG7k#(-5C}pb7 z)7*~hPQg3#52ptF(AKL_phk6&SxM1aS69c;aIG!EX3E}226c{dUmM*=pMu~KW+tvx z+6zAYdZE}{Cpv2IT%ETq+Pa0VmF2SLkL_JHUS8hT6PknOL~6IR1un==kbF*r)~lO1 zSuzT*GSDL&pP$0>b;zc$(Z)dv>**C}nS8Pn3d~w4addbd(=jIWp1t~p*~W#o720D+$--;hM?NbgM=wbf>?q`6d691G|Bn6F#){Q10| z{WjBE%Fy`y{QLqA#&}Q#FpP;v8{4EK;9BDyLVB1$8U>2Z91wdhYxRev(E60^sGHem z_Eh=RQ{mJNzt-b}s#fnV9Jv%yUVRw=;$C<Hg&h6VHEz z9GP%Ep|*(&aT&hiYpihYZOe*fjeXk+N3CB$kV!dj<13bIbW3q@@yR&bV#ik`2fQ<6 zr}bjwqluX#;VxiX&NBUhS7x*%`shn|ikGdYMTiLD&*)aM4_e_69Hv1@JmL5NaD05{Yvi0*chqAQq|&_(b)A1C)I~1CT{T%VFa8yrFss2>!Um< zHO`ZHLc?Tiki@e!{+})uv-I7g{w?QciTy!3&`1t1&GDyE-!}@8%;}FDQOfv2{R8JE z-vna7G#mXcy+`w1(_M*6=a1$sQwLEf_jz@{p8?hL>%dyMPoEBUmd)Y?Ra{M$>;V2d zvyh^KF<~vE3n!zv@657l8?_JgeWor@{?;nHpKU&L`refly-@1ibP%A5pZnPb1q4`w zVR(;ZgE)5E)*K)0bwJ(NVV%OB!?A`ElT}k`B;3SJt^Ve7OdU?(>?rx(tr!wI z>bN3xEvWlSdw#A&_AgsQl+{_DirZXp4=OXApx7lak)uCMCQo?$bFl4iyihm31Wg+J z{mT!#XF=+$)DXIWkz!{|na#LoIQJUFJX;_MX<>Bw+6?_+rxTPdv~wYq;ROY2y|jg`mm#B>Ig z+$KRC{sislrDHgXw}VRNLlmve%@Io9TVT^B{Yy`J7dDL0wcW3gg%@pt`k z(#|VBwmY+HsfCNl$ki+4l#soj3&_1iwFL~oE4lESr2X~86+6|miNiwbpf|$g82yiH z^Y}<+giv7Z?;O3;`cHgrUO2f1>U%Qb`Cmi$i>e3UsNVkNXk^{aT%S_Co2+tg-;L4N zd$MAQg%VhF9Rpt@-xzLud>q*6fB}&NQj?~ro9<1q0wEU?3!&ZbU)6m}v6fVr>6_MQ z_s#BKju)MdKfOe(QEml=h$3KZ1u5&9EciOnZ68GS@N;8DoZ7Sie01`FPv1OwUZ5j_wjMwdhsIF`6~j*rz2*BpoeFkD@`PEi0I_ z(6>0jBP~?R`oxbQleL5@U}yDzT(a)}2C^yDDNI!9n6v(a#xEB>6{og94WCZ$?jL{_? z@~a@IcyQerm}}MNPRp_(6yZx-#Z*Mx84OjnwK6^DX0;8(AVM8c~+D{wn- z1(kaBUd2~;lOoC!C3QaaJ<4S%(hjzG8{*di5K)4w_MyHW;727J3XbMtzcJQT7-5_B z9HLn@uxNb-{>ht5oiF+>ti+0-#6t7HG0S|6KFnIk`qSX1ILpfyNSdu*o0~UmQqLZV ztuEQ^+i{jFhybU$V6B&oeKtv^D^P;<#Lrw%0h|p5L(Td5 z-@n{%qpc-JM0P>H2NLA7Crxh!wS!3H`_SG@9}vqR{`!zEgN(7b1ADZ$*&Loy0IO@;PHv`lMl$I5K~-xzj;JQd+!x~ zn>WpDu8BI>-+HuawO!C(^cR1$o0M@mUqL6y)z}@gq63)e7euxPk>?6##^CzS&P_=tbn6Lw|-1<3zTWFzB8@_oO^!K0;v+d{at*Ld? zDCP9;gVR3+lQ-2BMk0DWZjNZ{NM6ySDm0gf@%KCo)e2fqf4hdRo|f<0V5TrE_3G*b z&%XvIchK{J5C^XPQ$$WtyQTH4VV^wYFHI%VNLEVqLln%Q*CMfeL3;(-r7&yu^4oIm z4ku*C6yvN9b>LLQk31rZcCG>@nsn-It82@({C?uV;=xl;)oyZTaLP+q@4;X zNy=KkqrnkvlyUDq;_y&cL*Xp*Ux&Jpjl2&5eEkYe-py7vGRIdUA|jeR#;T&2V(}?T z?e8#W8){9(_MjlBeOB7y2S;kG-4%EEZoSRpplLfDJ@YKq>{0*neZ8sn2cSg1DK9TS ztroL#N*-kea&^O3{r5omh4bg;rds&znHj4#{e6xrSFWhDb`VW~vY!DYyxw8$`F_E_ zG;@3e)1;j-Cp(9gi8QY!XQslVNLtbpF5DL)+mQ@e(8m}cW~XHEr3L_X9Q1~y^NDqu zo+uhMD6Q{o5Pr+VR&kVi36$U|ypY&m+n#S0h-vRU0@+mWpUo&2*S~1TbNV0&9L2qG zhw-HV%*&eK(7>Ts{GoKhcs{5Zl%V%J`#w#FLp$5PPJ-MD>}XOf5)@%h?JB$yo+Ff+ zPShGZInB@LceZ%AySsN}Na)WeS5;LtvyE2?9BFZb`x=Joj~!77zfIT~5J}u`h%JFq zuQ9~pRUNokDAnnMvMf%y1z{y*P#%fSKV4+Ath&D?G=jnfC|&1^YnI9)i3?I%x(?-F zKi`dsiOII+g7;_t@_Y0|sZtcOvn3|)OO>8IP74om;4xiP$+@LqemVuzJDWVFUUYSJ z9bEbFGo^#aw>mMUZX?<})hFNwBIbMRG7gQLG+izNBNU3gTal|r*`}&=KLyO0d9ya% zwE;)hCYT7hhH*Q(+_l`W2S^`Uvl|!)Dhjx6K9x^vOLgQzMgrAtEuBJLC*@vt$d^cq z@XKXVE`n-BuA_6I>fhYb<`x zg!CJj2whHgw$QvauRN-{7zcL%DUoy1%mIU0iR|YwkjFm?)Ltad$&Md*fl;$Z47~-2 zkJX14AzwayhHYC%QNeb=O~yGlR&!Bue##Y#0EH{~AcaN!_LX4H}j?F6O|rgm!6| zW3vsgq8YvXE{tNgz{wqJ>QmV(%x{5r(DJCc6U}2Gl(xApZtl}Gcr#AxvTF{4^zaJXsWIA12!K4EZ?RpF z+`iF6znI?RW@l$NQw0t)s-MTkKPe{y|2@*_=%=gY1dy5`4b~7n4o)|{C)Io6IG-%% z$oN`=XmJtn=7C40;Z|q~xH_PYYVq-gzgXD=y`tvQptDY?MWy7ozR=Q@ny+UE*By=1 zsz7^1FxZ~l`1@?cpCIjPECNs?47j#)yh>?;-jaK)Kq^Dw3P19Mb|UQ4jJtenR+l_7 zkgHRmZ2mSRvi)&lp~%X&y`mBV5Bu;m_0JOAa&}1I^!nxwP|Z@B3}-i}Mp4tVTmX2^ zuDosCGWZXYo~8;TgH^wat!J=k^`j%`jGlveNWp1v|j7ZMxn%DA>2Rh#3>B~XbJ(FWJ z*EY6y)ukiKpA|6^gX`<+A|erK7l^6#;m+lf0Pv~D*Ic}duQ1v;YftdC;H7_zgEOf z-scCObkAu$S)=_h!n271bseNGfZ?!$0YhypnQu20LP_ARQJU*1+^#CVoqO7Wg(8KD zA3ptSCcAc;3&;L0X4jpRyCdiKw7N5JafSlHwo!F(G_dn0z{}(CH*|^vO2Odhdn`n* zi(-uVC-nfe`jJ@t4v2uk`actMWS`Tn%K(U__|bT`{Bi&KuNIyejUZ)$EfmF1nW98! z$r~U9m+vf^gSM|&P<0ZA2ifjgM4dn|wIHst?OV0&T`b6IrcvRfX=B6e0ejUcd8&O$ zwcd(=8+JG1eA}*K&!I+$yb?~~arxzY8sM1JDI%ZdKh!w^pig&n_b`W61~7&xjLmw= zALyPW-_SD)I?p@X_FUF^{ZX*PK6kKq1xlFjn2C@t`_Nst!`oMPsdgLZt~p488v=5q zTAl~E!&_8TyRf6n)VuHZjIUNKR9^nmXAe3gCHuRpjhbLp$X0fd@ds8xV~ zwja63I?IK>pN9&wd>eho=8^HdmWSL84f;b9K$D}3AEFhuzeB}KNA8;kBwMJ$68MYl z=ql;!S#I9@a{)wyGSbEp<7SC%RQza;ZT{2IT`eAYc_rL7D;+6R{^#-lBXQ}IHMs2I zbC){ePv19Lnt9=2Ntasoul~?yH~#7*2MsNpip)1pOF0J8{ka1{=KB<`o~pFFZO;;P zc80Hb{KceQ47eduY!_sNXl49c8;wvYmT%yagrphxk7~dR%>2OaU3t8@!3$O1e@+cf zLGK0WtN2H8|7j#A&+d`4hLd`X^rgE%Xir$OD;f();j6UJ{pZJntkE81tub zJwH3<2{6WAZkJz@1=r@KBZ205HSia7bTWq1@}|Ce9IZViaL7h!h7!p%7c^$}g3EVF zQdFCiR~8u$wXJSLVyL4Ble1j-DEXL17h{W$ZoGWh_~2!5okva>n!XG+P20qMreE82NGW-lz0 zi|S9~HZI!!{Uru8TK;qehHC20Id-G3afAarRY(!_1KnVAhRBW3$G8K@ia05EVtBa* zDF56#qugf)SCFEeqAwhKTFX<`cdUUIbHkblS$_^`3GTPJ~UwmV}s{={=J-!+u+kX z@`c9h(Ne}*Od|81ICaKwUf1CHN~<=qk%B(=GIbZc3;sA>9)HFfouf3GF)Vi|zFkoZ z)2!AiKV=I8t{b&eyh_#%Wy^5EiI4I8=vL~GyHDSyjVnAJAx}$w zAo3;;ZtWcbH^Uqxg}T!yqVSK~CN0BRcL$9#>#100zdc*0PW_uy#vZu#hNBKo2_03h zK2!vd_g4p(&9hC~+^}OL*w~e03nSqFllsF@(&M&WU%VgQ0nhMtIqcNdnLjQ-1e4+J z=KNSKF-n(od?x}QM5W%oY+KVE<4x1XM|*g0Cyf*DI{d`=QgrJK{mqd^tqoy>k7E$OrfJ`piy<%KK6eAX2B(- literal 0 HcmV?d00001 diff --git a/native-assets/token/.gitignore b/native-assets/native-asset/.gitignore similarity index 100% rename from native-assets/token/.gitignore rename to native-assets/native-asset/.gitignore diff --git a/native-assets/token/README.md b/native-assets/native-asset/README.md similarity index 71% rename from native-assets/token/README.md rename to native-assets/native-asset/README.md index c0ba14e63..9ba3b4a17 100644 --- a/native-assets/token/README.md +++ b/native-assets/native-asset/README.md @@ -1,7 +1,7 @@

- - light theme + + light theme

@@ -16,19 +16,19 @@ ## Overview -A fungible token is a [Native Asset](https://docs.fuel.network/docs/sway/blockchain-development/native_assets) on the Fuel Network. +A fungible asset is a [Native Asset](https://docs.fuel.network/docs/sway/blockchain-development/native_assets) on the Fuel Network. -In this project, there are a maximum of 100,000,000 tokens for each asset that may be minted. There is no limit on the total individual assets a user may mint. +In this project, there are a maximum of 100,000,000 coins for each asset that may be minted. There is no limit on the total individual assets a user may mint. ## Standards Implementations -The project implements and follows the [SRC-20; Token](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) and [SRC-3; Mint and Burn](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_3) standards. It also uses the [Token Library](https://github.com/FuelLabs/sway-libs/tree/master/libs/token) to implement the basic functionality behind the standards. +The project implements and follows the [SRC-20; Native Asset](https://github.com/FuelLabs/sway-standards/tree/master/standards/src20-native-asset) and [SRC-3; Mint and Burn](https://github.com/FuelLabs/sway-standards/tree/master/standards/src3-mint-burn) standards. It also uses the [Native Asset Library](https://github.com/FuelLabs/sway-libs/blob/master/libs/native_assets) to implement the basic functionality behind the standards. ### SRC-20 Set functions for name, symbol, and decimals have been provided to the user. While traditionally name, symbol, and decimals are written into the contract rather than storage, this contract is open to mint new types of assets. This means that every asset minted by this contract may contain a different name and symbol. -The [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) ABI defined below has also been implemented. +The [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src20-native-asset) ABI defined below has also been implemented. ```sway abi SRC20 { @@ -65,10 +65,10 @@ The project consists of a smart contract. ```sh -token +native-asset ├── project │   ├── contracts -│   │   └── token-contract +│   │   └── native-asset-contract │   │   └──src/main.sw │   └── SPECIFICATION.md ├── ui @@ -84,7 +84,7 @@ TODO: The user interface does not currently exist therefore its [SPECIFICATION.m ### Project -In order to run the subsequent commands change into the following directory `/path/to/token/project/`. +In order to run the subsequent commands change into the following directory `/path/to/native-asset/project/`. #### Program compilation diff --git a/native-assets/token/project/Cargo.lock b/native-assets/native-asset/project/Cargo.lock similarity index 81% rename from native-assets/token/project/Cargo.lock rename to native-assets/native-asset/project/Cargo.lock index 4d9c76fc1..414d9b882 100644 --- a/native-assets/token/project/Cargo.lock +++ b/native-assets/native-asset/project/Cargo.lock @@ -3,5 +3,5 @@ version = 3 [[package]] -name = "token-contract" +name = "native-asset-contract" version = "0.0.0" diff --git a/native-assets/token/project/Cargo.toml b/native-assets/native-asset/project/Cargo.toml similarity index 50% rename from native-assets/token/project/Cargo.toml rename to native-assets/native-asset/project/Cargo.toml index c56892047..3121967f0 100644 --- a/native-assets/token/project/Cargo.toml +++ b/native-assets/native-asset/project/Cargo.toml @@ -1,5 +1,5 @@ [workspace] resolver = "2" members = [ - "./contracts/token-contract", + "./contracts/native-asset-contract", ] diff --git a/native-assets/token/project/Forc.lock b/native-assets/native-asset/project/Forc.lock similarity index 96% rename from native-assets/token/project/Forc.lock rename to native-assets/native-asset/project/Forc.lock index 9716a6763..e67a419c1 100644 --- a/native-assets/token/project/Forc.lock +++ b/native-assets/native-asset/project/Forc.lock @@ -10,6 +10,16 @@ dependencies = [ name = "core" source = "path+from-root-C3992B43B72ADB8C" +[[package]] +name = "native-asset-contract" +source = "member" +dependencies = [ + "asset", + "src20", + "src3", + "std", +] + [[package]] name = "src20" source = "git+https://github.com/FuelLabs/sway-standards?tag=v0.3.3#4198b4b07449ad16104cc8a0501f3013670fdcfd" @@ -29,13 +39,3 @@ dependencies = ["std"] name = "std" source = "git+https://github.com/fuellabs/sway?tag=v0.49.1#2ac7030570f22510b0ac2a7b5ddf7baa20bdc0e1" dependencies = ["core"] - -[[package]] -name = "token-contract" -source = "member" -dependencies = [ - "asset", - "src20", - "src3", - "std", -] diff --git a/native-assets/native-asset/project/Forc.toml b/native-assets/native-asset/project/Forc.toml new file mode 100644 index 000000000..fb2befe6b --- /dev/null +++ b/native-assets/native-asset/project/Forc.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["./contracts/native-asset-contract"] diff --git a/native-assets/token/project/SPECIFICATION.md b/native-assets/native-asset/project/SPECIFICATION.md similarity index 86% rename from native-assets/token/project/SPECIFICATION.md rename to native-assets/native-asset/project/SPECIFICATION.md index e90eddf3a..9d8f23d65 100644 --- a/native-assets/token/project/SPECIFICATION.md +++ b/native-assets/native-asset/project/SPECIFICATION.md @@ -1,7 +1,7 @@ Table of Contents - [Overview](#overview) - [Use Cases](#use-cases) -- [Token Contract](#token-contract) +- [Asset Contract](#asset-contract) - [SRC-20 Functionality](#src-20-functionality) - [`total_assets()`](#total_assets) - [`total_supply()`](#total_supply) @@ -27,7 +27,7 @@ This section contains general information about the functionality of the applica If you are interested in a functional overview then this is the section for you. -# Token Contract +# Asset Contract ## SRC-20 Functionality @@ -37,7 +37,7 @@ This function will return the total number of individual assets for a contract. ### `total_supply()` -This function will return the total supply of tokens for an asset. +This function will return the total supply of coins for an asset. ### `name()` @@ -67,8 +67,8 @@ This function will set the decimals of an asset. ### `mint()` -This function will mint new tokens using a sub-identifier. +This function will mint new asset using a sub-identifier. ### `burn()` -This function will burn tokens with the given sub-identifier. +This function will burn assets with the given sub-identifier. diff --git a/native-assets/token/project/contracts/token-contract/Cargo.toml b/native-assets/native-asset/project/contracts/native-asset-contract/Cargo.toml similarity index 86% rename from native-assets/token/project/contracts/token-contract/Cargo.toml rename to native-assets/native-asset/project/contracts/native-asset-contract/Cargo.toml index 9447eda23..cbaea9029 100644 --- a/native-assets/token/project/contracts/token-contract/Cargo.toml +++ b/native-assets/native-asset/project/contracts/native-asset-contract/Cargo.toml @@ -1,5 +1,5 @@ [project] -name = "token-contract" +name = "native-asset-contract" version = "0.0.0" authors = ["Fuel Labs "] edition = "2021" diff --git a/native-assets/token/project/contracts/token-contract/Forc.toml b/native-assets/native-asset/project/contracts/native-asset-contract/Forc.toml similarity index 91% rename from native-assets/token/project/contracts/token-contract/Forc.toml rename to native-assets/native-asset/project/contracts/native-asset-contract/Forc.toml index cd66a953a..4d3ef941b 100644 --- a/native-assets/token/project/contracts/token-contract/Forc.toml +++ b/native-assets/native-asset/project/contracts/native-asset-contract/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "token-contract" +name = "native-asset-contract" [dependencies] asset = { git = "https://github.com/FuelLabs/sway-libs", tag = "v0.18.0" } diff --git a/native-assets/token/project/contracts/token-contract/src/errors.sw b/native-assets/native-asset/project/contracts/native-asset-contract/src/errors.sw similarity index 100% rename from native-assets/token/project/contracts/token-contract/src/errors.sw rename to native-assets/native-asset/project/contracts/native-asset-contract/src/errors.sw diff --git a/native-assets/token/project/contracts/token-contract/src/main.sw b/native-assets/native-asset/project/contracts/native-asset-contract/src/main.sw similarity index 94% rename from native-assets/token/project/contracts/token-contract/src/main.sw rename to native-assets/native-asset/project/contracts/native-asset-contract/src/main.sw index d76299e3b..92d1dc0aa 100644 --- a/native-assets/token/project/contracts/token-contract/src/main.sw +++ b/native-assets/native-asset/project/contracts/native-asset-contract/src/main.sw @@ -27,7 +27,7 @@ use std::{call_frames::contract_id, hash::Hash, storage::storage_string::*, stri storage { /// The total number of unique assets minted by this contract. total_assets: u64 = 0, - /// The total number of tokens minted for a particular asset. + /// The total number of coins minted for a particular asset. total_supply: StorageMap = StorageMap {}, /// The name associated with a particular asset. name: StorageMap = StorageMap {}, @@ -64,7 +64,7 @@ impl SRC20 for Contract { _total_assets(storage.total_assets) } - /// Returns the total supply of tokens for an asset. + /// Returns the total supply of coins for an asset. /// /// # Arguments /// @@ -72,7 +72,7 @@ impl SRC20 for Contract { /// /// # Returns /// - /// * [Option] - The total supply of tokens for `asset`. + /// * [Option] - The total supply of coins for `asset`. /// /// # Number of Storage Accesses /// @@ -158,7 +158,7 @@ impl SRC20 for Contract { /// /// # Additional Information /// - /// e.g. 8, means to divide the token amount by 100000000 to get its user interface representation. + /// e.g. 8, means to divide the coin amount by 100000000 to get its user interface representation. /// /// # Arguments /// @@ -190,17 +190,17 @@ impl SRC20 for Contract { } impl SRC3 for Contract { - /// Mints new tokens using the `sub_id` sub-identifier. + /// Mints new assets using the `sub_id` sub-identifier. /// /// # Arguments /// - /// * `recipient`: [Identity] - The user to which the newly minted tokens are transferred to. - /// * `sub_id`: [SubId] - The sub-identifier of the newly minted token. - /// * `amount`: [u64] - The quantity of tokens to mint. + /// * `recipient`: [Identity] - The user to which the newly minted assets are transferred to. + /// * `sub_id`: [SubId] - The sub-identifier of the newly minted asset. + /// * `amount`: [u64] - The quantity of coins to mint. /// /// # Reverts /// - /// * When more than 100,000,000 tokens have been minted. + /// * When more than 100,000,000 coinss have been minted. /// /// # Number of Storage Accesses /// @@ -238,7 +238,7 @@ impl SRC3 for Contract { amount, ); } - /// Burns tokens sent with the given `sub_id`. + /// Burns assets sent with the given `sub_id`. /// /// # Additional Information /// @@ -247,8 +247,8 @@ impl SRC3 for Contract { /// /// # Arguments /// - /// * `sub_id`: [SubId] - The sub-identifier of the token to burn. - /// * `amount`: [u64] - The quantity of tokens to burn. + /// * `sub_id`: [SubId] - The sub-identifier of the asset to burn. + /// * `amount`: [u64] - The quantity of coins to burn. /// /// # Number of Storage Accesses /// @@ -295,7 +295,7 @@ impl SetAssetAttributes for Contract { /// # Examples /// /// ```sway - /// use token::SetAssetAttributes; + /// use asset::SetAssetAttributes; /// use src20::SRC20; /// use std::string::String; /// @@ -338,7 +338,7 @@ impl SetAssetAttributes for Contract { /// # Examples /// /// ```sway - /// use token::SetAssetAttributes; + /// use asset::SetAssetAttributes; /// use src20::SRC20; /// use std::string::String; /// @@ -381,7 +381,7 @@ impl SetAssetAttributes for Contract { /// # Examples /// /// ```sway - /// use token::SetAssetAttributes; + /// use asset::SetAssetAttributes; /// use src20::SRC20; /// /// fn foo(asset: AssetId) { @@ -474,7 +474,7 @@ fn test_name() { let attributes_abi = abi(SetAssetAttributes, CONTRACT_ID); let sub_id = ZERO_B256; let asset_id = AssetId::new(ContractId::from(CONTRACT_ID), sub_id); - let name = String::from_ascii_str("Fuel Token"); + let name = String::from_ascii_str("Fuel Asset"); assert(src20_abi.name(asset_id).is_none()); attributes_abi.set_name(asset_id, name); assert(src20_abi.name(asset_id).unwrap().as_bytes() == name.as_bytes()); @@ -485,7 +485,7 @@ fn test_revert_set_name_twice() { let attributes_abi = abi(SetAssetAttributes, CONTRACT_ID); let sub_id = ZERO_B256; let asset_id = AssetId::new(ContractId::from(CONTRACT_ID), sub_id); - let name = String::from_ascii_str("Fuel Token"); + let name = String::from_ascii_str("Fuel Asset"); attributes_abi.set_name(asset_id, name); attributes_abi.set_name(asset_id, name); } diff --git a/native-assets/token/project/contracts/token-contract/tests/harness.rs b/native-assets/native-asset/project/contracts/native-asset-contract/tests/harness.rs similarity index 100% rename from native-assets/token/project/contracts/token-contract/tests/harness.rs rename to native-assets/native-asset/project/contracts/native-asset-contract/tests/harness.rs diff --git a/native-assets/token/project/fuel-toolchain.toml b/native-assets/native-asset/project/fuel-toolchain.toml similarity index 100% rename from native-assets/token/project/fuel-toolchain.toml rename to native-assets/native-asset/project/fuel-toolchain.toml diff --git a/native-assets/token/ui/SPECIFICATION.md b/native-assets/native-asset/ui/SPECIFICATION.md similarity index 100% rename from native-assets/token/ui/SPECIFICATION.md rename to native-assets/native-asset/ui/SPECIFICATION.md diff --git a/native-assets/token/.docs/token-logo-dark-theme.png b/native-assets/token/.docs/token-logo-dark-theme.png deleted file mode 100644 index 91431ace1e32b8ca76e0dae470bae8a0a58d2001..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14693 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 X=8YA>kHz5gN{F$cxk1@U*GvBkV?iV} diff --git a/native-assets/token/project/Forc.toml b/native-assets/token/project/Forc.toml deleted file mode 100644 index 54524debd..000000000 --- a/native-assets/token/project/Forc.toml +++ /dev/null @@ -1,2 +0,0 @@ -[workspace] -members = ["./contracts/token-contract"] diff --git a/oracle/project/contracts/oracle-contract/src/events.sw b/oracle/project/contracts/oracle-contract/src/events.sw index 0de1dc3dc..f6a8ff7a0 100644 --- a/oracle/project/contracts/oracle-contract/src/events.sw +++ b/oracle/project/contracts/oracle-contract/src/events.sw @@ -1,6 +1,6 @@ library; -/// Event for when the price of a token is updated. +/// Event for when the price of an asset is updated. pub struct PriceUpdateEvent { /// Updated price. price: u64,