# 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**


---

# 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://docs.pylon.money/contract-specification/core/pool.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.
