> 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/exchange-rate.md).

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