🖨️Generator

Contract that distributes ASTRO emissions to LP stakers and allows other teams to incentivize their pairs

1. Overview

The Generator contract distributes token rewards (ASTRO) based on locked LP token amounts for each eligible Astroport pool. The Generator also supports proxy staking via 3rd party contracts so that stakers can receive dual rewards.

The Generator contract code can be found here.

2. Variables & Functions

Constants

Name
Description

CONFIG

Stores the contract configuration

POOL_INFO

Contains information about all generators

TMP_USER_ACTION

Used to temporarily store data about a user action

USER_INFO

Stores information about all stakers in every generator

MAX_LIMIT

The maximum amount of users that can be read at once from USER_INFO

DEFAULT_LIMIT

The default amount of users to read from USER_INFO

OWNERSHIP_PROPOSAL

Contains the proposal to change contract ownership

CONTRACT_NAME

Contract name

CONTRACT_VERSION

Contract version

Structs

Name
Description
Contains

InstantiateMsg

This struct holds parameters used to instantiate the Generator contract

  • owner: String - Address that can change contract settings

  • astro_token: String - ASTRO token contract address

  • tokens_per_block: Uint128 - Amount of ASTRO distributed per block among all pairs

  • start_block: Uint64 - Start block for distributing ASTRO

  • allowed_reward_proxies: Vec<String> - Dual rewards proxy contracts allowed to interact with the Generator

  • vesting_contract: String - The ASTRO vesting contract that drips ASTRO rewards

PoolLengthResponse

This structure holds the response returned when querying the total length of the array that keeps track of instantiated generators

  • length: usize - The total length of the generator array

PendingTokenResponse

This structure holds the response returned when querying the amount of pending rewards that can be withdrawn from a 3rd party rewards contract

  • pending: Uint128 - The amount of pending ASTRO

  • pending_on_proxy: Option<Uint128> - The amount of pending 3rd party reward tokens

RewardInfoResponse

This structure holds the response returned when querying for the token addresses used to reward a specific generator

  • base_reward_token: Addr - The address of the base reward token

  • proxy_reward_token: Option<Addr> - The address of the 3rd party reward token

PoolInfoResponse

This structure holds the response returned when querying for a pool's information

  • alloc_point: Uint64 - The slice of ASTRO that this pool's generator gets per block

  • astro_tokens_per_block: Uint128 - Amount of ASTRO tokens being distributed per block to this LP pool

  • last_reward_block: u64 - The last block when token emissions were snapshotted (distributed)

  • current_block: u64 - Current block number. Useful for computing APRs off-chain

  • accumulated_rewards_per_share: Decimal - Total amount of ASTRO rewards already accumulated per LP token staked

  • pending_astro_rewards: Uint128 - Pending amount of total ASTRO rewards which are claimable by stakers right now

  • reward_proxy: Option<Addr> - The address of the 3rd party reward proxy contract

  • pending_proxy_rewards: Option<Uint128> - Pending amount of total proxy rewards which are claimable by stakers right now

  • accumulated_proxy_rewards_per_share: Decimal - Total amount of 3rd party token rewards already accumulated per LP token staked

  • proxy_reward_balance_before_update: Uint128 - Reward balance for the dual rewards proxy before updating accrued rewards

  • orphan_proxy_rewards: Uint128 - The amount of orphan proxy rewards which are left behind by emergency withdrawals and not yet transferred out

  • lp_supply: Uint128 - Total amount of lp tokens staked in the pool's generator

ConfigResponse

This structure holds the response returned when querying the contract for general parameters

  • owner: Addr - Address that's allowed to change contract parameters

  • astro_token: Addr - ASTRO token contract address

  • tokens_per_block: Uint128 - Total amount of ASTRO distributed per block

  • total_alloc_point: Uint64 - Sum of total allocation points across all active generators

  • start_block: Uint64 - Start block for ASTRO incentives

  • allowed_reward_proxies: Vec<Addr> - List of 3rd party reward proxies allowed to interact with the Generator contract

  • vesting_contract: Addr - The ASTRO vesting contract address

StakerResponse

This structure holdes the parameters used to return information about a staked in a specific generator

  • account: String - The staker's address

  • amount: Uint128 - The amount that the staker currently has in the generator

UserInfo

This structure provides information for an address staked in a specific generator

  • amount: Uint128 - An amount of staked LP tokens

  • reward_debt: Uint128 - A reward amount an address already received or that the address is not eligible for; used for proper reward calculation

  • reward_debt_proxy: Uint128 - Proxy reward amount an address already received or is not eligible for; used for proper reward calculation

PoolInfo

This structure provides information for a pool

  • alloc_point: Uint64 - Allocation points are used to control reward distribution among eligible pools; a pool is eligible is its generator has a non-zero alloc_point

  • last_reward_block: Uint64 - Accumulated amount of rewards per share unit. Used for correct reward calculations

  • accumulated_rewards_per_share: Decimal - This is the accrued amount of rewards up to the latest checkpoint

  • reward_proxy: Option - The 3rd party proxy reward contract

  • accumulated_proxy_rewards_per_share: Decimal - This is the accrued amount of 3rd party rewards up to the latest checkpoint

  • proxy_reward_balance_before_update: Uint128 - This is the balance of 3rd party proxy rewards that the proxy had before a reward snapshot

  • orphan_proxy_rewards: Uint128 - The orphaned proxy rewards which are left behind by emergency withdrawals

  • has_asset_rewards: bool - Whether a generator receives 3rd party rewards or not

Config

This structure returns the main configuration for the Generator contract

  • owner: Addr - Address used to change contract settings

  • astro_token: Addr - The ASTRO token address

  • tokens_per_block: Uint128 - Total amount of ASTRO rewards per block split between all active generators

  • total_alloc_point: Uint64 - The total (summed up) allocation points for all active generators

  • start_block: Uint64 - The block number when ASTRO mining started

  • allowed_reward_proxies - The list of allowed reward proxy contracts

  • vesting_contract: Addr - The vesting contract from which ASTRO rewards are distributed

Functions

Function
Params
Description

instantiate

(deps: DepsMut, _env: Env, _info: MessageInfo, msg: InstantiateMsg) -> <Response, ContractError>

Initializes the generator contract using provided parameters

execute

(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> Result<Response, ContractError>

Exposes execute functions available in the contract

execute_update_config

execute_update_config(deps: DepsMut, info: MessageInfo, vesting_contract: Option<String>) -> Result<Response, ContractError>

Sets a new Generator vesting contract address

add

add(mut deps: DepsMut, env: Env, lp_token: Addr, alloc_point: Uint64, has_asset_rewards: bool, reward_proxy: Option<String>) -> Result<Response, ContractError>

Creates a new generator and adds it to POOL_INFO (if it does not exist yet) and updates total allocation points (in Config)

set

set(mut deps: DepsMut, env: Env, lp_token: Addr, alloc_point: Uint64, has_asset_rewards: bool) -> Result<Response, ContractError>

Updates the given generator's ASTRO allocation points

reply

reply(deps: DepsMut, env: Env, _msg: Reply) -> Result<Response, ContractError>

The entry point to the contract for processing replies from submessages

mass_update_pools

mass_update_pools(mut deps: DepsMut, env: Env) -> Result<Response, ContractError>

Updates the amount of accrued rewards for all generators

update_pool

update_pool(mut deps: DepsMut, env: Env, lp_token: Addr) -> Result<Response, ContractError>

Updates the amount of accrued rewards for a specific generator

accumulate_rewards_per_share

accumulate_rewards_per_share(deps: DepsMut, env: &Env, lp_token: &Addr, pool: &mut PoolInfo, cfg: &Config, deposited: Option<Uint128>) -> StdResult<()>

Accrues the amount of rewards distributed for each staked LP token in a specific generator. Update reward variables for the given generator

receive_cw20

(deps: DepsMut, env: Env, info: MessageInfo, cw20_msg: Cw20ReceiveMsg) -> Result<Response, ContractError>

Receives a message of type [Cw20ReceiveMsg] and processes it depending on the received template

send_pending_rewards

send_pending_rewards(cfg: &Config, pool: &PoolInfo, user: &UserInfo, to: &Addr) -> Result<Vec, ContractError>

Distributes pending proxy rewards for a specific staker

deposit

deposit(mut deps: DepsMut, env: Env, lp_token: Addr, beneficiary: Addr, amount: Uint128) -> Result<Response, ContractError>

Deposit LP tokens in a generator to receive token emissions

withdraw

withdraw(mut deps: DepsMut, env: Env, lp_token: Addr, account: Addr, amount: Uint128) -> Result<Response, ContractError>

Withdraw LP tokens from a generator

emergency_withdraw

emergency_withdraw(deps: DepsMut, _env: Env, info: MessageInfo, lp_token: String) -> Result<Response, ContractError>

Withdraw LP tokens without caring about rewards. To be used in emergency cases only

set_allowed_reward_proxies

set_allowed_reward_proxies(deps: DepsMut, info: MessageInfo, proxies: Vec<String>) -> Result<Response, ContractError>

Sets the allowed reward proxies that can interact with the Generator contract

send_orphan_proxy_rewards

send_orphan_proxy_rewards(deps: DepsMut, info: MessageInfo, recipient: String, lp_token: String) -> Result<Response, ContractError>

Sends orphaned proxy rewards (which are left behind by emergency withdrawals) to another address. Can only be called by the owner

migrate

migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError>

Used for contract migration

query

query(deps: Deps, env: Env, msg: QueryMsg) -> Result<Binary, ContractError>

Exposes all the queries available in the contract

pool_length

pool_length(deps: Deps) -> Result<PoolLengthResponse, ContractError>

Returns the amount of instantiated generators

query_deposit

query_deposit(deps: Deps, lp_token: String, user: String) -> Result<Uint128, ContractError>

Returns the amount of LP tokens a user staked in a specific generator

pending_token

pending_token(deps: Deps, env: Env, lp_token: String, user: String) -> Result<PendingTokenResponse, ContractError>

Calculates and returns pending token rewards for a specific user

query_config

query_config(deps: Deps) -> Result<ConfigResponse, ContractError>

Returns information about a generator's configuration

query_reward_info

query_reward_info(deps: Deps, lp_token: String) -> Result<RewardInfoResponse, ContractError>

Returns reward information for a specific generator

query_orphan_proxy_rewards

query_orphan_proxy_rewards(deps: Deps, lp_token: String) -> Result<Uint128, ContractError>

Returns the amount of orphaned proxy rewards for a specific generator

query_pool_info

query_pool_info(deps: Deps, env: Env, lp_token: String) -> Result<PoolInfoResponse, ContractError>

Returns a generator's configuration

query_simulate_future_reward

query_simulate_future_reward(deps: Deps, env: Env, lp_token: String, future_block: u64) -> Result<Uint128, ContractError>

Returns the total amount of ASTRO tokens distributed for a specific generator up to a certain block in the future

query_list_of_stakers

query_list_of_stakers(deps: Deps, lp_token: String, start_after: Option<String>, limit: Option<u32>) -> Result<Vec<StakerResponse>, ContractError>

Returns a list of stakers that currently have funds in a specific generator

calculate_rewards

calculate_rewards(env: &Env, pool: &PoolInfo, cfg: &Config) -> StdResult<Uint128>

Calculates and returns the amount of accrued rewards since the last reward checkpoint for a specific generator

3. Reward Distribution

The Generator reward distribution is controlled by several variables:

Variable
Description

tokens_per_block

The total amount of ASTRO rewards that will be distributed every block among all active generators

alloc_point

A distribution ratio set per individual generator

total_alloc_point

The sum of alloc_point for each active generator

The formula for reward distribution (for every generator) is the following:

astro_to_distribute = blocks_since_last_reward * tokens_per_block * alloc_point / total_alloc_point

For example, if there are three active generators, and the alloc_point for each generator is 1000, the total_alloc_point would equal 3000 (1000 * 3). All three pools will get an equal amount of rewards. But what happens if we want to add another pool? Let's add one more pool and set its alloc_point to 3000.

Note, that doing this will change the distribution for all existing pools, as it will affect the total_alloc_point variable. After adding the new pool, the total_alloc_point would be 6000. This new pool will now receive 50% of rewards (3000 is 50% of 6000) and the other 50% will be evenly distributed between the initial three pools (because each of their alloc_points is 1000). In order to maintain the same reward allocations for existing pools, it is required to update each of their alloc_points.

4. Walkthrough

The following are examples and descriptions of core functions that can be called by anyone to interact with the Generator contract.

Execute Functions

deposit

Stakes LP tokens in a specific generator (inside the Generator contract). In order to stake in the Generator contract, you should execute this message inside the contract of the LP token you want to stake.

{
  "send": {
    "contract": <GeneratorContractAddress>,
    "amount": 999,
    "msg": "base64-encodedStringOfWithdrawMsg"
  }
}

Inside send.msg, you may encode this JSON string into base64 encoding:

{
  "Deposit": {}
}

depositFor

Stakes LP tokens in the Generator on behalf of another address. In order to stake in the Generator contract, you should execute this message inside the LP token you want to stake.

{
  "send": {
    "contract": <GeneratorContractAddress>,
    "amount": 999,
    "msg": "base64-encodedStringOfWithdrawMsg"
  }
}

In send.msg, you may encode this JSON string into base64 encoding:

{
  "DepositFor": "terra..."
}

withdraw

Unstakes LP tokens from the Generator contract and claims outstanding token emissions. An address can also claim rewards without unstaking from a generator: call the withdraw function and specify amount as 0 (you don’t withdraw any LP tokens, only claim rewards).

  "withdraw": {
    "lp_token": "terra...",
    "amount": "123"
  }
}

emergency_withdraw

Unstakes LP tokens without caring about rewards. To be used only in emergencies such as a critical bug found in the Generator contract.

{
  "emergency_withdraw": {
    "lp_token": "terra..."
  }
}

auto_stake

An address can provide liquidity and stake in the Generator in one transaction using the Swap Pairs contracts. Calling the provide_liquidity operation with auto_stake astrue allows LP tokens to automatically be staked in the Generator contract (if the LP tokens currently get ASTRO or 3rd party emissions). If auto_stake is not specified, LP tokens will just be minted for the recipient.

{
  "provide_liquidity": {
    "assets": [
      {
        "info": {
          "token": {
            "contract_addr": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"
          }
        },
        "amount": "1000000"
      },
      {
        "info": {
          "native_token": {
            "denom": "uusd"
          }
        },
        "amount": "1000000"
      }
    ],
    "slippage_tolerance": "0.01",
    "auto_stake": true,
    "receiver": "terra..."
  }
}

Query Functions

deposit

Returns the amount of a specific LP token that a user currently has staked in the Generator.

{
  "deposit": {
    "lp_token": "terra...",
    "user": "terra..."
  }
}

pending_token

Returns the amount of pending ASTRO and 3rd party token rewards that can be claimed by a user that staked a specific LP token.

{
  "pending_token": {
    "lp_token": "terra...",
    "user": "terra..."
  }
}

reward_info

{
  "reward_info": {
    "lp_token": "terra..."
  }
}

orphan_proxy_rewards

{
  "orphan_proxy_rewards": {
    "lp_token": "terra..."
  }
}

simulate_future_reward

Returns the amount of ASTRO that will be distributed up to a future block and for a specific LP token.

{
  "simulate_future_reward": {
    "lp_token": "terra...",
    "future_block": "999"
  }
}

list_of_stakers

Returns a list of stakers that currently have funds in a specific generator.

{
  "list_of_stakers": {
    "lp_token": "terra...",
    "start_after": "terra...",
    "limit": 5
  }
}

5. Risks

  1. alloc_point miscalculation can lead to specific pools not getting the initially intended ASTRO emissions.

  2. If owner is compromised, it can drain the Generator of all staked LP tokens.

  3. Dual rewards proxy misconfiguration can block addresses from staking in specific generators.

Last updated

Was this helpful?