# Exchange Rate

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

### **`state.rs`**

Stores all relevant contract parameters.

```rust
pub struct Config {
    pub owner: HumanAddr,
}

```

`owner`: the owner address of this contract.

```rust
pub struct Token {
    pub status: Status,
    pub exchange_rate: Decimal256,
    pub epoch_period: u64,
    pub weight: Decimal256,
    pub last_updated_at: u64,
}

```

`status`: virtual exchange rate enforcement status - `Neutral`, `Running`, or `Stopped`

* `Neutral`: logic not yet initialized, throws an error when queried
* `Running`: exchange rate calculations valid, returns current `exchange_rate` when queried & executes update
* `Stopped`: exchange rate no longer updating, returns a constant value when queried

`exchange_rate`: current virtual exchange rate for this pool

`epoch_period`: minimum time gap between `update()` calls.

### **`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,
    _: InitMsg,
) -> StdResult<InitResponse> {
    state::store_config(
        &mut deps.storage,
        &state::Config {
            owner: env.message.sender,
        },
    )?;

    Ok(InitResponse::default())
}

```

Initializes a new Exchange Rate 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::Update { token } => Ok(ExecHandler::update(deps, env, token)?),
        HandleMsg::ConfigToken {
            token,
            exchange_rate,
            epoch_period,
            weight,
        } => Ok(ExecHandler::config_token(
            deps,
            env,
            token,
            exchange_rate,
            epoch_period,
            weight,
        )?),
        HandleMsg::AddToken {
            token,
            base_rate,
            period,
            weight,
        } => Ok(ExecHandler::add_token(
            deps, env, token, base_rate, period, weight,
        )?),
        HandleMsg::Start { tokens } => Ok(ExecHandler::start(deps, env, tokens)?),
        HandleMsg::Stop { tokens } => Ok(ExecHandler::stop(deps, env, tokens)?),
    }
}

```

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

`Update { token }` : calls `update(deps, env, token)` defined under `handler_exec.rs`.

`ConfigToken { token, exchange_rate, epoch_period, weight, }` : calls `config_token(deps, env, token, exchange_rate, epoch_period, weight, )` defined under `handler_exec.rs`.

`AddToken { token, base_rate, period, weight, }` : calls `add_token(deps, env, token, base_rate, period, weight, )` defined under `handler_exec.rs`.

`Start { tokens }` : calls `start(deps, env, tokens)` defined under `handler_exec.rs`.

`Stop { tokens }` : calls `stop(deps, env, tokens)` 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::ExchangeRateOf { token, blocktime } => {
            Ok(QueryHandler::exchange_rate_of(deps, &token, blocktime)?)
        }
    }
}

```

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

`ExchangeRateOf { token, blocktime }` : calls `exchange_rate_of(deps, &token, blocktime)` defined under `handler_query.rs`; Queries the current `exchange_rate` for `token`.

### **`handler_exec.rs`**

Defines core contract execution logic. Functions are as follows:

`update`: recalculates the current virtual exchange rate for `token`.

`config_token`: updates target `token` profile for calculating virtual exchange rate.

`add_token`: adds a new target `token` profile for calculating virtual exchange rate.

`start`: enables virtual exchange rate calculation.

`stop`: disables virtual exchange rate calculation.

```rust
pub fn update<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    env: Env,
    token: HumanAddr,
) -> StdResult<HandleResponse> {
    let token_addr: CanonicalAddr = deps.api.canonical_address(&token)?;

    let mut token: state::Token = state::read_token(&deps.storage, &token_addr)?;
    if token.status.ne(&state::Status::Running) {
        return Err(StdError::unauthorized());
    }

    let elapsed = env.block.time.sub(token.last_updated_at);
    if elapsed < token.epoch_period {
        return Ok(HandleResponse::default());
    }

    let exchange_rate_before = token.exchange_rate;
    let pow_count = elapsed.div(token.epoch_period);
    for _ in 0..pow_count {
        token.exchange_rate = token.exchange_rate.mul(token.weight);
    }

    token.last_updated_at = env.block.time;

    state::store_token(&mut deps.storage, &token_addr, &token)?;

    Ok(HandleResponse {
        messages: vec![],
        log: vec![
            log("action", "update"),
            log("sender", env.message.sender),
            log("er_before", exchange_rate_before),
            log("er_after", token.exchange_rate),
        ],
        data: None,
    })
}

```

Recalculates virtual exchange rate for a particular `token`.

`exchange_rate` is calculated as:

* count how many epochs have elapsed since `last_updated_at`
  * do nothing if at least one epoch has not passed
* `exchange_rate = exchange_rate * weight ^ epochs_passed`

```rust
pub fn config_token<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    env: Env,
    token: HumanAddr,
    exchange_rate: Option<Decimal256>,
    epoch_period: Option<u64>,
    weight: Option<Decimal256>,
) -> StdResult<HandleResponse> {
    check_owner(deps, &env.message.sender)?;

    let token_addr: CanonicalAddr = deps.api.canonical_address(&token)?;
    let mut token: state::Token = state::read_token(&deps.storage, &token_addr)?;

    if let Some(er) = exchange_rate {
        if token.exchange_rate.gt(&er) {
            return Err(StdError::unauthorized());
        }
        token.exchange_rate = er;
    }
    if let Some(ep) = epoch_period {
        token.epoch_period = ep;
    }
    if let Some(w) = weight {
        token.weight = w;
    }

    state::store_token(&mut deps.storage, &token_addr, &token)?;

    Ok(HandleResponse::default())
}

```

Updates virtual exchange rate parameters for `token`. Accepts:

* `token`: address of the target token subject to exchange rate updates.
* `exchange_rate`: initial exchange rate parameter to be used as a baseline. should be reset on significant deviation.
* `epoch_period`: time length of a single epoch used for `update` calls.
* `weight`: exchange rate delta enforced per `epoch`.

```rust
pub fn add_token<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    env: Env,
    token: HumanAddr,
    base_rate: Decimal256,
    period: u64,
    weight: Decimal256,
) -> StdResult<HandleResponse> {
    check_owner(deps, &env.message.sender)?;

    let token_addr: CanonicalAddr = deps.api.canonical_address(&token)?;

    state::store_token(
        &mut deps.storage,
        &token_addr,
        &state::Token {
            exchange_rate: base_rate,
            epoch_period: period,
            status: state::Status::Neutral,
            weight,
            last_updated_at: env.block.time,
        },
    )?;

    Ok(HandleResponse::default())
}
```

Adds a new `token` target profile for calculating `exchange_rate`. Accepts:

* `token`: address of the target token subject to exchange rate updates.
* `exchange_rate`: initial exchange rate parameter to be used as a baseline. should be reset on significant deviation.
* `epoch_period`: time length of a single epoch used for `update` calls.
* `weight`: exchange rate delta enforced per `epoch`.

```rust
pub fn start<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    env: Env,
    tokens: Vec<HumanAddr>,
) -> StdResult<HandleResponse> {
    check_owner(deps, &env.message.sender)?;
    for token in tokens {
        _start(deps, &token, &env.block.time)?;
    }
    Ok(HandleResponse::default())
}

fn _start<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    token: &HumanAddr,
    block_time: &u64,
) -> StdResult<()> {
    let token_addr: CanonicalAddr = deps.api.canonical_address(&token)?;
    let mut token: state::Token = state::read_token(&deps.storage, &token_addr)?;

    token.status = state::Status::Running;
    token.last_updated_at = *block_time;

    Ok(())
}

```

Changes `token.status` to `Running` for all tokens registered with the Exchange Rate contract.

```rust
pub fn stop<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    env: Env,
    tokens: Vec<HumanAddr>,
) -> StdResult<HandleResponse> {
    check_owner(deps, &env.message.sender)?;
    for token in tokens {
        _stop(deps, token)?;
    }

    Ok(HandleResponse {
        messages: vec![],
        log: vec![log("action", "stop"), log("sender", env.message.sender)],
        data: None,
    })
}

fn _stop<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    token: HumanAddr,
) -> StdResult<()> {
    let token_addr: CanonicalAddr = deps.api.canonical_address(&token)?;
    let mut token: state::Token = state::read_token(&deps.storage, &token_addr)?;

    token.status = state::Status::Stopped;

    Ok(())
}

```

Changes `token.status` to `Stopped` for all tokens registered with the Exchange Rate 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/exchange-rate.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.
