Search code examples
nearprotocol

String attribute set in init method always returns empty string


I have the following struct with impl:

#[near_bindgen]
#[derive(Default, Serialize, Deserialize, BorshDeserialize, BorshSerialize, Debug)]
pub struct MyStruct {
    owner: String
}

#[near_bindgen(init => new)]
impl MyStruct {
    fn new() -> Self {
        Self {
             owner: "bob".to_string()
        }
    }

    fn get_owner(&self) -> String {
         return self.owner;
    }
}

Then I deploy the contract using near deploy my_contract --masterAccount myAccount

If I call get_owner using near-shell: near call my_contract get_owner --accountId=myAccount It always returns "" instead of the expected "bob".

It seems like the new method might not get called on deployment.


Solution

  • Initializer doesn't automatically get called on deploy. deploy just deploys the code and doesn't call anything on the contract. We should probably add a new method to shell, that does deploy_and_call. But for now just call new manually.

    The reason why we don't initialize automatically is that initializer might take additional arguments. You can pass an owner to new method. Here is an example how to use initializer with custom arguments and as well as how to make sure a contract can't be called without initialization:

    #[near_bindgen]
    #[derive(BorshDeserialize, BorshSerialize)]
    pub struct FunToken {
        /// AccountID -> Account details.
        pub accounts: Map<AccountId, Account>,
    
        /// Total supply of the all token.
        pub total_supply: Balance,
    }
    
    impl Default for FunToken {
        fn default() -> Self {
            env::panic(b"Not initialized");
            unreachable!();
        }
    }
    
    #[near_bindgen(init => new)]
    impl FunToken {
        pub fn new(owner_id: AccountId, total_supply: Balance) -> Self {
            let mut ft = Self { accounts: Map::new(b"a".to_vec()), total_supply };
            let mut account = ft.get_account(&owner_id);
            account.balance = total_supply;
            ft.accounts.insert(&owner_id, &account);
            ft
        }
    }
    

    From here: https://github.com/nearprotocol/near-bindgen/blob/master/examples/fun-token/src/lib.rs#L52-L77

    Basically it panics during Default call, so non initialized contract can't be called.