> For the complete documentation index, see [llms.txt](https://docs.pylon.money/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.pylon.money/contract-specification/core/pool.md).

# Pool

**Deployed at:** [**`terra1z5j60wct88yz62ylqa4t8p8239cwx9kjlghkg2`**](https://finder.terra.money/columbus-4/address/terra1z5j60wct88yz62ylqa4t8p8239cwx9kjlghkg2)

### **`config.rs`**

Stores all relevant contract parameters.

```rust
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Config {
    pub this: CanonicalAddr,
    pub owner: CanonicalAddr,
    pub beneficiary: CanonicalAddr,
    pub moneymarket: CanonicalAddr,
    pub atoken: CanonicalAddr,
    pub stable_denom: String,
    pub dp_token: CanonicalAddr,
}
```

`this`: the address of this pool contract.

`owner`: the owner address of this pool contract.

`beneficiary`: the address of which all interest collected from principal deposits are sent to. could be a single address, or a contract address that oversees additional distribution logic.

`moneymarket`: the address of the Anchor money market contract to accept deposits.

`atoken`: the address of the aUST token contract.

`stable_denom`: base Terra stablecoin denomination of this pool to be deposited to Anchor, i.e. `uusd`.

`dp_token`: the address of the DP token contract minted by this pool.

### **`contract.rs`**

Defines logic entry points for `InitMsg`, `HandleMsg` and `QueryMsg` calls.

```rust
pub fn init<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    env: Env,
    msg: InitMsg,
) -> StdResult<InitResponse> {
    let sender = env.message.sender;
    let raw_sender = deps.api.canonical_address(&sender)?;

    let mut config = config::Config {
        this: deps.api.canonical_address(&env.contract.address)?,
        owner: raw_sender,
        beneficiary: deps.api.canonical_address(&msg.beneficiary)?,
        fee_collector: deps.api.canonical_address(&msg.fee_collector)?,
        exchange_rate_feeder: deps.api.canonical_address(&msg.exchange_rate_feeder)?,
        moneymarket: deps.api.canonical_address(&msg.moneymarket)?,
        stable_denom: String::default(),
        atoken: CanonicalAddr::default(),
        dp_token: CanonicalAddr::default(),
    };

    let market_config = querier::anchor::config(deps, &config.moneymarket)?;

    config.stable_denom = market_config.stable_denom.clone();
    config.atoken = deps.api.canonical_address(&market_config.aterra_contract)?;

    config::store(&mut deps.storage, &config)?;

    Ok(InitResponse {
        messages: vec![CosmosMsg::Wasm(WasmMsg::Instantiate {
            code_id: msg.dp_code_id,
            send: vec![],
            label: None,
            msg: to_binary(&Cw20InitMsg {
                name: format!("Deposit Token - {}", msg.pool_name),
                symbol: "PylonDP".to_string(),
                decimals: 6u8,
                initial_balances: vec![],
                mint: Some(MinterResponse {
                    minter: env.contract.address.clone(),
                    cap: None,
                }),
                init_hook: Some(Cw20InitHook {
                    contract_addr: env.contract.address,
                    msg: to_binary(&HandleMsg::RegisterDPToken {})?,
                }),
            })?,
        })],
        log: vec![],
    })
}
```

Initializes a new pool contract. Updates data storage as defined with `config.rs`, and initializes a new DP token contract linked to this pool contract.

```rust
pub fn handle<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    env: Env,
    msg: HandleMsg,
) -> StdResult<HandleResponse> {
    match msg {
        HandleMsg::Receive(msg) => CoreHandler::receive(deps, env, msg),
        HandleMsg::Deposit {} => CoreHandler::deposit(deps, env),
        HandleMsg::ClaimReward {} => CoreHandler::claim_reward(deps, env),
        HandleMsg::RegisterDPToken {} => CoreHandler::register_dp_token(deps, env),
    }
}

```

Defines `HandleMsg` endpoints. Calls the following functions per `HandleMsg`:

* `Receive(msg)` : calls `receive(deps, env, msg)` defined under `handler_exec.rs`.
* `Deposit {}` : calls `deposit(deps, env)` defined under `handler_exec.rs`.
* `ClaimReward {}` : calls `claim_reward(deps, env)` defined under `handler_exec.rs`.
* **\[INTERNAL]** `RegisterDPToken {}` : calls `register_dp_token(deps, env)` defined under `handler_exec.rs`.

```rust
pub fn query<S: Storage, A: Api, Q: Querier>(
    deps: &Extern<S, A, Q>,
    msg: QueryMsg,
) -> StdResult<Binary> {
    match msg {
        QueryMsg::DepositAmountOf { owner } => QueryHandler::deposit_amount(deps, owner), // dp_token.balanceOf(msg.sender)
        QueryMsg::TotalDepositAmount {} => QueryHandler::total_deposit_amount(deps), // dp_token.totalSupply()
        QueryMsg::Config {} => QueryHandler::config(deps),                           // config
        QueryMsg::ClaimableReward {} => QueryHandler::claimable_reward(deps), // config.strategy.reward()
    }
}

```

Defines `QueryMsg` endpoints. Calls the following functions per `QueryMsg`:

* `DepositAmountOf { owner }` : calls `deposit_amount(deps, owner)` defined under `handler_query.rs`; returns the current DP token balance of the sender of this message.
* `TotalDepositAmount {}` : calls `total_deposit_amount(deps)` defined under `handler_query.rs`; returns the total DP token balanced linked to this pool contract.
* `Config {}` : calls `config(deps)` defined under `handler/query.rs`; returns the following:
  * `beneficiary`: returns the current beneficiary address set for this pool contract.
  * `moneymarket`: returns the Anchor money market contract set for this pool contract to call for `deposit_stable` and `redeem_stable` messages. For further information regarding logic of the Anchor money market, please refer to Anchor Protocol's official documentation.
  * `stable_denom`: returns the current Terra stablecoin denomination that the underlying Anchor money market contract accepts.
  * `anchor_token`: returns the aToken contract address that the underlying Anchor money market contract returns on deposits.
  * `dp_token`: returns the DP token contract address minted by this pool contract on new deposits.
* `GetClaimableReward {}` : calls `claimable_reward(deps)` defined under `handler_query.rs`; returns all claimable UST rewards for all UST deposits held by this pool.

### **`handler/core.rs`**

Defines core contract execution logic. Functions are as follows:

* `receive`: defines a CW-20 token contract **receive hook**, which is executed when a Pylon DP token is sent to this Pylon pool.
* `deposit`: deposits UST to this Pylon pool, deposits them to Anchor, and mints Pylon DP tokens back to the depositor.
* `redeem`: consecutively called on a CW-20 `receive` call. Burns received DP tokens, retrieves equivalent amounts of UST from Anchor, and returns principal UST deposits excluding any interest generated.
* `claim_reward`: claims any remaining interest remaining in the pool, and sends them over to the beneficiary address. Interest is calculated as `(total_aust_amount * exchange_rate) - (total_dp_balance)`
* `register_dp_token`: registers a DP token contract controlled by this Pylon deposit pool for new DP token mints/burns on deposits/redemptions.

```rust
pub fn receive<S: Storage, A: Api, Q: Querier>(
    deps: &Extern<S, A, Q>,
    env: Env,
    cw20_msg: Cw20ReceiveMsg,
) -> StdResult<HandleResponse> {
    let sender = env.message.sender.clone();
    if let Some(msg) = cw20_msg.msg {
        match from_binary(&msg)? {
            Cw20HookMsg::Redeem {} => {
                // only asset contract can execute this message
                let config: config::Config = config::read(&deps.storage)?;
                if deps.api.canonical_address(&sender)? != config.dp_token {
                    return Err(StdError::unauthorized());
                }

                redeem(deps, env, cw20_msg.sender, cw20_msg.amount)
            }
        }
    } else {
        Err(StdError::generic_err(
            "Invalid request: \"redeem\" message not included in request",
        ))
    }
}

```

If a CW-20 transfer to this contract includes a `Redeem {}` `Cw20HookMsg`:

* checks if the sender of this `HookMsg` is the registered DP token address (i.e. not any other token contract address being sent to this pool) - return `unauthorized()` error if not, else continue
* if passed, call `redeem(deps, _env, cw20_msg.sender, cw20_msg.amount)`

If a `Redeem {}` message is not included with this function call, return an `invalid_request` error.

```rust
pub fn deposit<S: Storage, A: Api, Q: Querier>(
    deps: &Extern<S, A, Q>,
    env: Env,
) -> StdResult<HandleResponse> {
    let config = config::read(&deps.storage)?;

    // check deposit
    let received: Uint256 = env
        .message
        .sent_funds
        .iter()
        .find(|c| c.denom == config.stable_denom)
        .map(|c| Uint256::from(c.amount))
        .unwrap_or_else(Uint256::zero);

    if received.is_zero() {
        return Err(StdError::generic_err(format!(
            "Pool: insufficient token amount {}",
            config.stable_denom,
        )));
    }

    let deposit_amount = deduct_tax(
        deps,
        Coin {
            denom: config.stable_denom.clone(),
            amount: received.into(),
        },
    )?
    .amount;

    Ok(HandleResponse {
        messages: [
            querier::feeder::update_msg(deps, &config.exchange_rate_feeder, &config.dp_token)?,
            querier::anchor::deposit_stable_msg(
                deps,
                &config.moneymarket,
                &config.stable_denom,
                deposit_amount,
            )?,
            vec![CosmosMsg::Wasm(WasmMsg::Execute {
                contract_addr: deps.api.human_address(&config.dp_token)?,
                msg: to_binary(&Cw20HandleMsg::Mint {
                    recipient: env.message.sender.clone(),
                    amount: deposit_amount,
                })?,
                send: vec![],
            })],
        ]
        .concat(),
        log: vec![
            log("action", "deposit"),
            log("sender", env.message.sender),
            log("amount", deposit_amount.to_string()),
        ],
        data: None,
    })
}

```

Sending native Terra stablecoins (UST) with this `MsgExecuteContract` call:

* Check how much deposits have been made to this pool contract for `stable_denom`.
  * If there are no deposits, return a `generic_err`.
* Issue a `HandleResponse` issuing the following messages:
  * call `deposit_stable` from the Anchor money market contract for `deposit_amount` units of `stable_denom`(e.g. 100 UST). aUST will be returned from the Anchor money market contract to this pool contract.
  * issue another `MsgExecuteContract` call that mints `deposit_amount` units of Pylon DP tokens for this particular pool to the caller.

```rust
pub fn redeem<S: Storage, A: Api, Q: Querier>(
    deps: &Extern<S, A, Q>,
    env: Env,
    sender: HumanAddr,
    amount: Uint128,
) -> StdResult<HandleResponse> {
    let config = config::read(&deps.storage)?;

    let (market_redeem_amount, pool_redeem_amount, _) =
        querier::pool::calculate_return_amount(deps, &config, Uint256::from(amount))?;

    Ok(HandleResponse {
        messages: [
            querier::feeder::update_msg(deps, &config.exchange_rate_feeder, &config.dp_token)?,
            vec![CosmosMsg::Wasm(WasmMsg::Execute {
                contract_addr: deps.api.human_address(&config.dp_token)?,
                msg: to_binary(&Cw20HandleMsg::Burn { amount })?,
                send: vec![],
            })],
            querier::anchor::redeem_stable_msg(
                deps,
                &config.moneymarket,
                &config.atoken,
                market_redeem_amount.into(),
            )?,
            vec![CosmosMsg::Bank(BankMsg::Send {
                from_address: env.contract.address,
                to_address: sender,
                amount: vec![pool_redeem_amount.clone()],
            })],
        ]
        .concat(),
        log: vec![
            log("action", "redeem"),
            log("sender", env.message.sender),
            log("amount", pool_redeem_amount.amount),
        ],
        data: None,
    })
}

```

When a `Redeem {}` `Cw20HookMsg` is called:

* Query the current `epoch_state` from the Anchor money market.
* Calculate how much aUST needs to be redeemed back to UST to maintain principle: `dp_token_balance / epoch_state.exchange_rate`
* Calculate how much Terra tax is charged during redemptions. As tax is charged for every Terra stablecoin `MsgSend`s on the Terra blockchain, `deduct_tax` should be called twice, as there are two cases when Terra tax is charged for UST transfers during redemptions:
  * when UST is transferred from the Anchor money market to this Pylon pool contract
  * when UST is transferred from this Pylon pool contract to the user's wallet
* Issue a `HandleResponse` containing the following messages:
  * burn `amount` units of DP tokens for this Pylon pool.
  * redeem `market_redeem_amount` aUST (calculated as `dp_token_balance / epoch_state.exchange_rate`) for `pool_redeem_amount` UST.
  * `MsgSend`s `pool_redeem_amount` back to the caller of this contract

```rust
pub fn claim_reward<S: Storage, A: Api, Q: Querier>(
    deps: &Extern<S, A, Q>,
    env: Env,
) -> StdResult<HandleResponse> {
    // calculate (total_aust_amount * exchange_rate) - (total_dp_balance)
    let config = config::read(&deps.storage)?;
    if config.beneficiary != deps.api.canonical_address(&env.message.sender)? {
        return Err(StdError::unauthorized());
    }

    let (reward_amount, fee_amount) =
        querier::pool::calculate_reward_amount(deps, &config, Option::from(env.block.time))?;
    let (market_redeem_amount, _, _) =
        querier::pool::calculate_return_amount(deps, &config, reward_amount.add(fee_amount))?;
    let (_, beneficiary_redeem_amount, _) =
        querier::pool::calculate_return_amount(deps, &config, reward_amount)?;
    let (_, collector_redeem_amount, _) =
        querier::pool::calculate_return_amount(deps, &config, fee_amount)?;

    Ok(HandleResponse {
        messages: [
            querier::feeder::update_msg(deps, &config.exchange_rate_feeder, &config.dp_token)?,
            querier::anchor::redeem_stable_msg(
                deps,
                &config.moneymarket,
                &config.atoken,
                market_redeem_amount.into(),
            )?,
            vec![
                CosmosMsg::Bank(BankMsg::Send {
                    from_address: env.contract.address.clone(),
                    to_address: deps.api.human_address(&config.beneficiary)?,
                    amount: vec![beneficiary_redeem_amount.clone()],
                }),
                CosmosMsg::Bank(BankMsg::Send {
                    from_address: env.contract.address.clone(),
                    to_address: deps.api.human_address(&config.fee_collector)?,
                    amount: vec![collector_redeem_amount.clone()],
                }),
            ],
        ]
        .concat(),
        log: vec![
            log("action", "claim_reward"),
            log("sender", env.message.sender),
            log("amount", beneficiary_redeem_amount.amount),
            log("fee", collector_redeem_amount.amount),
        ],
        data: None,
    })
}

```

On a `ClaimReward {}` `HandleMsg` call:

* calculate how much aUST should be redeemed: `(total_aust_amount * exchange_rate) - (total_dp_balance)`
* apply a **virtual exchange rate** queryable from the **Pylon** **Exchange Rate contract**. This effectively re-calculates how much UST should be claimed **excluding MINE token buybacks**, which is sent to the **Collector** contract.
* calculates how much UST should be redeemed for:
  * `market_redeem_amount` : amount of aUST for redemptions **before** Terra blockchain tax for both `beneficiary` and `collector`. returns `Uint256`.
  * `beneficiary_redeem_amount` : amount of aUST for redemptions **after** Terra blockchain tax for `beneficiary`. returns a `Coin` object.
  * `collector_redeem_amount` : amount of aUST for redemptions **after** Terra blockchain tax for `collector`, sent to the **Collector** contract for buybacks. returns a `Coin` object.
* Issue a `HandleResponse` that includes the following messages:
  * update **virtual exchange rate**
  * redeem `market_redeem_amount` aUST from Anchor
  * send `beneficiary_redeem_amount` to beneficiary account
  * send `collector_redeem_amount` to **Collector contract**
