Facing multiple errors, including traits not being implemented for UnorderedSet<AccountId> and mismatched types

Running into an issue while working on a smart contract. Facing multiple errors, including traits not being implemented for UnorderedSet<AccountId> and mismatched types.

code -

use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::store::{LookupMap, UnorderedMap, UnorderedSet};
use near_sdk::serde::{Deserialize, Serialize};
use near_sdk::{env, near_bindgen, require, AccountId, BorshStorageKey, PanicOnDefault, NearToken};

#[derive(BorshStorageKey, BorshSerialize)]
enum StorageKey {
    Tokens,
    TokenOwners,
    Proposals,
    ProposalVoters { proposal_id: u64 },
}

#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct Contract {
    tokens: LookupMap<AccountId, Token>,
    token_owners: UnorderedSet<AccountId>,
    proposals: UnorderedMap<u64, Proposal>,
    next_proposal_id: u64,
}

#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone)]
#[serde(crate = "near_sdk::serde")]
pub struct Token {
    owner_id: AccountId,
    metadata: TokenMetadata,
}

#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone)]
#[serde(crate = "near_sdk::serde")]
pub struct TokenMetadata {
    title: Option<String>,
    description: Option<String>,
    governance_role: String,
}

#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone)]
#[serde(crate = "near_sdk::serde")]
pub struct Proposal {
    id: u64,
    title: String,
    description: String,
    proposer: AccountId,
    votes_for: NearToken,
    votes_against: NearToken,
    #[serde(skip)]
    voters: UnorderedSet<AccountId>,
    status: ProposalStatus,
}

#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, PartialEq, Clone)]
#[serde(crate = "near_sdk::serde")]
pub enum ProposalStatus {
    Active,
    Passed,
    Rejected,
}

#[near_bindgen]
impl Contract {
    #[init]
    pub fn new() -> Self {
        Self {
            tokens: LookupMap::new(StorageKey::Tokens),
            token_owners: UnorderedSet::new(StorageKey::TokenOwners),
            proposals: UnorderedMap::new(StorageKey::Proposals),
            next_proposal_id: 0,
        }
    }

    pub fn mint(&mut self, account_id: AccountId, metadata: TokenMetadata) {
        require!(!self.tokens.contains_key(&account_id), "Token already exists for this account");
        
        let token = Token {
            owner_id: account_id.clone(),
            metadata,
        };
        
        self.tokens.insert(account_id, token);
        self.token_owners.insert(account_id);
    }

    pub fn token_metadata(&self, account_id: AccountId) -> Option<TokenMetadata> {
        self.tokens.get(account_id).map(|token| token.metadata.clone())
    }

    pub fn is_token_owner(&self, account_id: AccountId) -> bool {
        self.token_owners.contains(&account_id)
    }

    pub fn governance_role(&self, account_id: AccountId) -> Option<String> {
        self.tokens.get(&account_id).map(|token| token.metadata.governance_role.clone())
    }

    pub fn create_proposal(&mut self, title: String, description: String) -> u64 {
        let account_id = env::predecessor_account_id();
        require!(self.is_token_owner(account_id.clone()), "Only holders can create proposals");
        
        let proposal_id = self.next_proposal_id;
        self.next_proposal_id += 1;

        let mut proposal = Proposal {
            id: proposal_id,
            title,
            description,
            proposer: account_id,
            votes_for: NearToken::from_near(0),
            votes_against: NearToken::from_near(0),
            voters: UnorderedSet::new(StorageKey::ProposalVoters { proposal_id }),
            status: ProposalStatus::Active,
        };

        self.proposals.insert(proposal_id, proposal);

        proposal_id
    }

    pub fn vote(&mut self, proposal_id: u64, vote: bool) {
        let account_id = env::predecessor_account_id();
        require!(self.is_token_owner(account_id.clone()), "Only holders can vote");
        
        let mut proposal = self.proposals.get(&proposal_id).expect("Proposal not found");
        require!(proposal.status == ProposalStatus::Active, "Proposal is not active");
        require!(!proposal.voters.contains(&account_id), "Account has already voted");

        if vote {
            proposal.votes_for = proposal.votes_for.saturating_add(NearToken::from_near(1));
        } else {
            proposal.votes_against = proposal.votes_against.saturating_add(NearToken::from_near(1));
        }

        proposal.voters.insert(account_id);

        let total_votes = proposal.votes_for.as_near() + proposal.votes_against.as_near();
        if total_votes >= (self.token_owners.len() / 2 + 1) as u128 {
            if proposal.votes_for > proposal.votes_against {
                proposal.status = ProposalStatus::Passed;
            } else {
                proposal.status = ProposalStatus::Rejected;
            }
        }

        self.proposals.insert(proposal_id, &proposal);
    }

    pub fn get_proposal(&self, proposal_id: u64) -> Option<Proposal> {
        self.proposals.get(&proposal_id)
    }

    pub fn get_all_proposals(&self) -> Vec<Proposal> {
        self.proposals.values().collect()
    }

    pub fn transfer(&mut self, _from: AccountId, _to: AccountId) {
        //the transfer function
    }
}

errors -

error[E0277]: the trait bound `UnorderedSet<AccountId>: Default` is not satisfied
  --> src/lib.rs:38:55
   |
38 | #[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
   |                                                       ^^^^^^^^^^^ the trait `Default` is not implemented for `UnorderedSet<AccountId>`
   |
   = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
   --> src/lib.rs:144:44
    |
144 |         self.proposals.insert(proposal_id, proposal);
    |                        ------              ^^^^^^^^ expected `Proposal`, found `&Proposal`
    |                        |
    |                        arguments to this method are incorrect
    |
help: the return type of this call is `&Proposal` due to the type of the argument passed
   --> src/lib.rs:144:9
    |
144 |         self.proposals.insert(proposal_id, proposal);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------^
    |                                            |
    |                                            this argument influences the return type of `insert`
note: method defined here
   --> /home/akash/.cargo/registry/src/index.crates.io-6f17d22bba15001f/near-sdk-5.5.0/src/store/unordered_map/mod.rs:487:12
    |
487 |     pub fn insert(&mut self, k: K, value: V) -> Option<V>
    |            ^^^^^^

error[E0308]: mismatched types
   --> src/lib.rs:148:9
    |
147 |     pub fn get_proposal(&self, proposal_id: u64) -> Option<Proposal> {
    |                                                     ---------------- expected `std::option::Option<Proposal>` because of return type
148 |         self.proposals.get(&proposal_id)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Option<Proposal>`, found `Option<&Proposal>`
    |
    = note: expected enum `std::option::Option<Proposal>`
               found enum `std::option::Option<&Proposal>`

error[E0277]: a value of type `Vec<Proposal>` cannot be built from an iterator over elements of type `&Proposal`
    --> src/lib.rs:152:33
     |
152  |         self.proposals.values().collect()
     |                                 ^^^^^^^ value of type `Vec<Proposal>` cannot be built from `std::iter::Iterator<Item=&Proposal>`
     |
     = help: the trait `FromIterator<&Proposal>` is not implemented for `Vec<Proposal>`
     = help: the trait `FromIterator<Proposal>` is implemented for `Vec<Proposal>`
     = help: for that trait implementation, expected `Proposal`, found `&Proposal`
note: the method call chain might not have had the expected associated types
    --> src/lib.rs:152:24
     |
152  |         self.proposals.values().collect()
     |         -------------- ^^^^^^^^ `Iterator::Item` is `&Proposal` here
     |         |
     |         this expression has type `UnorderedMap<u64, Proposal>`
note: required by a bound in `collect`
    --> /home/akash/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2001:19
     |
2001 |     fn collect<B: FromIterator<Self::Item>>(self) -> B
     |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`

error[E0382]: use of moved value: `account_id`
  --> src/lib.rs:80:28
   |
72 |     pub fn mint(&mut self, account_id: AccountId, metadata: TokenMetadata) {
   |                            ---------- move occurs because `account_id` has type `AccountId`, which does not implement the `Copy` trait
...
76 |             owner_id: account_id,
   |                       ---------- value moved here
...
80 |         self.tokens.insert(account_id, token);
   |                            ^^^^^^^^^^ value used here after move
   |
help: consider cloning the value if the performance cost is acceptable
   |
76 |             owner_id: account_id.clone(),
   |                                 ++++++++

error[E0382]: use of moved value: `account_id`
  --> src/lib.rs:81:34
   |
72 |     pub fn mint(&mut self, account_id: AccountId, metadata: TokenMetadata) {
   |                            ---------- move occurs because `account_id` has type `AccountId`, which does not implement the `Copy` trait
...
80 |         self.tokens.insert(account_id, token);
   |                            ---------- value moved here
81 |         self.token_owners.insert(account_id);
   |                                  ^^^^^^^^^^ value used here after move
   |
help: consider cloning the value if the performance cost is acceptable
   |
80 |         self.tokens.insert(account_id.clone(), token);
   |                                      ++++++++

error[E0507]: cannot move out of `token.metadata` which is behind a shared reference
  --> src/lib.rs:85:50
   |
85 |         self.tokens.get(&account_id).map(|token| token.metadata)
   |                                                  ^^^^^^^^^^^^^^ move occurs because `token.metadata` has type `TokenMetadata`, which does not implement the `Copy` trait
   |
help: consider cloning the value if the performance cost is acceptable
   |
85 |         self.tokens.get(&account_id).map(|token| token.metadata.clone())
   |                                                                ++++++++

error[E0507]: cannot move out of `token.metadata.governance_role` which is behind a shared reference
  --> src/lib.rs:93:50
   |
93 |         self.tokens.get(&account_id).map(|token| token.metadata.governance_role)
   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `token.metadata.governance_role` has type `std::string::String`, which does not implement the `Copy` trait
   |
help: consider cloning the value if the performance cost is acceptable
   |
93 |         self.tokens.get(&account_id).map(|token| token.metadata.governance_role.clone())
   |                                                                                ++++++++

error[E0382]: use of moved value: `account_id`
   --> src/lib.rs:107:23
    |
97  |         let account_id = env::predecessor_account_id();
    |             ---------- move occurs because `account_id` has type `AccountId`, which does not implement the `Copy` trait
98  |         require!(self.is_token_owner(account_id), "Only SHLD holders can create proposals");
    |                                      ---------- value moved here
...
107 |             proposer: account_id,
    |                       ^^^^^^^^^^ value used here after move
    |
note: consider changing this parameter type in method `is_token_owner` to borrow instead if owning the value isn't necessary
   --> src/lib.rs:88:46
    |
88  |     pub fn is_token_owner(&self, account_id: AccountId) -> bool {
    |            -------------- in this method     ^^^^^^^^^ this parameter takes ownership of the value
help: consider cloning the value if the performance cost is acceptable
    |
98  |         require!(self.is_token_owner(account_id.clone()), "Only SHLD holders can create proposals");
    |                                                ++++++++

Regarding your first error:
serde docs

#[serde(skip)]
Skip this field: do not serialize or deserialize it.
When deserializing, Serde will use Default::default() or the function given by default = "..." to get a default value for this field.

You wrote #[serde(skip)] above UnorderedSet<AccountId>, even though it doesn't have an implementation of Default::default(). I'm not familiar with UnorderedSet unfortunately so I don't know what the solution is.

I'm a bit confused by the second error. Your code says

        self.proposals.insert(proposal_id, &proposal);

on line 144 but the error message has no & on line 144!

Yea exactly even I'm confused on the second error

I guess it means - proposal is already a borrowed type, or is returned borrowed from where it is defined

Maybe it means you forgot to save your file before compiling?

oh no i did cross-check lol

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.