# Staking Module

* Staking contract: Lock up tokens, participate in network.
* Rewards: Earn additional tokens, gain governance rights.
* Incentives: Encourage engagement, secure the network.
* Benefits: Active participation, increased token value.
* Smart contract: Defines staking rules, ensures transparency.

```rust
module my_addrx::BasicTokens{
    use std::error;
    use std::signer;

    /// Error codes
    const ENOT_MODULE_OWNER: u64 = 0;
    const EINSUFFICIENT_BALANCE: u64 = 1;
    const EALREADY_HAS_BALANCE: u64 = 2;
    const EALREADY_INITIALIZED: u64 = 3;
    const EEQUAL_ADDR: u64 = 4;

    struct Coin has store,drop {
        value: u64
    }

    struct Balance has key {
        coin: Coin
    }

    public fun createCoin(v:u64): Coin
    {
        let coin = Coin {
            value:v
        };
        return coin
    }


    public fun publish_balance(account: &signer) {
        let empty_coin = Coin { value: 0 };
        assert!(!exists<Balance>(signer::address_of(account)), error::already_exists(EALREADY_HAS_BALANCE));
        move_to(account, Balance { coin:  empty_coin });
    }

    public fun mint<CoinType: drop>(mint_addr: address, amount: u64) acquires Balance {
        deposit(mint_addr, Coin{ value: amount });
    }

    public fun burn(burn_addr: address, amount: u64) acquires Balance {
        let Coin { value: _ } = withdraw(burn_addr, amount);
    }

    public fun balance_of(owner: address): u64 acquires Balance {
        borrow_global<Balance>(owner).coin.value
    }


    public fun transfer(from: &signer, to: address, amount: u64) acquires Balance {
        let from_addr = signer::address_of(from);
        assert!(from_addr != to, EEQUAL_ADDR);
        let check = withdraw(from_addr, amount);
        deposit(to, check);
    }

    public fun withdraw(addr: address, amount: u64) : Coin acquires Balance {
        let balance = balance_of(addr);
        assert!(balance >= amount, EINSUFFICIENT_BALANCE);
        let balance_ref = &mut borrow_global_mut<Balance>(addr).coin.value;
        *balance_ref = balance - amount;
        Coin { value: amount }
    }

    public fun deposit(addr: address, check: Coin) acquires Balance{
        let balance = balance_of(addr);
        let balance_ref = &mut borrow_global_mut<Balance>(addr).coin.value;
        let Coin { value } = check;
        *balance_ref = balance + value;
    }

}


module my_addrx::Staking { 
    use std::signer;
    use aptos_framework::account;
    /// Error codes
    const EINSUFFICIENT_STAKE: u64 = 0;
    const EALREADY_STAKED: u64 = 1;
    const EINVALID_UNSTAKE_AMOUNT: u64 = 2;
    const EINVALID_REWARD_AMOUNT: u64 = 3;
    const EINVALID_APY: u64 = 4;
    const EINSUFFICIENT_BALANCE: u64 = 5;
    const DEFAULT_APY:u64 = 1000;//10% APY per year

    struct StakedBalance has store, key {
        staked_balance: u64,

    }

    public fun stake(acc_own: &signer,amount: u64) {
        let from = signer::address_of(acc_own);
        let balance = my_addrx::BasicTokens::balance_of(from);
        assert!(balance >= amount, EINSUFFICIENT_BALANCE);
        assert!(!exists<StakedBalance>(from), EALREADY_STAKED);
        my_addrx::BasicTokens::withdraw(from, amount);
        let staked_balance = StakedBalance {
            staked_balance: amount
        };
        move_to(acc_own, staked_balance);
    }

    public fun unstake(acc_own: &signer,amount: u64) acquires StakedBalance {
        let from = signer::address_of(acc_own);
        let staked_balance = borrow_global_mut<StakedBalance>(from);
        let staked_amount = staked_balance.staked_balance;
        assert!(staked_amount >= amount, EINVALID_UNSTAKE_AMOUNT);
        let coins = my_addrx::BasicTokens::createCoin(staked_amount);
        my_addrx::BasicTokens::deposit(from, coins);
        staked_balance.staked_balance = staked_balance.staked_balance - amount;
    }

    public fun claim_rewards(acc_own: &signer) acquires StakedBalance {
        let from = signer::address_of(acc_own);
        let staked_balance = borrow_global_mut<StakedBalance>(from);
        let staked_amount = staked_balance.staked_balance;
        assert!(staked_amount > 0, EINSUFFICIENT_STAKE);
        let apy = DEFAULT_APY;
        let reward_amount = (staked_amount * apy) / (10000);
        let coins = my_addrx::BasicTokens::createCoin(reward_amount);
        my_addrx::BasicTokens::deposit(from, coins);
    }

    #[test(alice=@0x11,bob=@0x2)]
    public entry fun test_staking(alice : signer, bob : signer)  acquires StakedBalance{

        account::create_account_for_test(signer::address_of(&alice));
        account::create_account_for_test(signer::address_of(&bob));

        // Publish balance for Alice and Bob
        my_addrx::BasicTokens::publish_balance(&alice);
        my_addrx::BasicTokens::publish_balance(&bob);

        // Mint some tokens to Alice
        my_addrx::BasicTokens::mint<my_addrx::BasicTokens::Coin>(signer::address_of(&bob), 1000);
        my_addrx::BasicTokens::mint<my_addrx::BasicTokens::Coin>(signer::address_of(&alice), 1000);

        // Alice stakes some tokens
        stake(&alice, 500);
        

        // Check that Alice's staked balance is correct
        let alice_resource = borrow_global<StakedBalance>(signer::address_of(&alice));
        assert!(alice_resource.staked_balance == 500, 100);

        // // Alice tries to stake again (should fail)
        // stake(&alice, 500);

        // // Bob tries to unstake from Alice's account (should fail)
        // unstake(&bob, 200);
        
        // // Alice unstakes some tokens
        unstake(&alice, 200);

        // Check that Alice's staked balance is correct
        let alice_resource = borrow_global<StakedBalance>(signer::address_of(&alice));
        assert!(alice_resource.staked_balance == 300, 100);

        // // Alice claims rewards
        claim_rewards(&alice);
    }

}



```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://move-developers-dao.gitbook.io/aptos-move-by-example/applications/staking.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
