Skip to main content

Incentives

Overview​

The Incentives contract (formerly the Generator) is where LP tokens are staked to earn rewards. Rewards are distributed per second, pro rata to the LP tokens each staker has in a pool. It supports CW20 and tokenfactory LP tokens.

Under long-term support:

  • There are no ASTRO emissions. astro_per_second is 0, there is no generator controller, and every Vesting schedule that funded emissions has ended. The emissions endpoints (setup_pools, set_tokens_per_second) are owner-only and unused.
  • Anyone can add external incentive schedules to any pool registered in the factory, in any token that isn't blocked. A schedule that adds a reward token new to the pool pays the incentivization fee.
  • yASTRO forwards pools' yASTRO rewards here (forward_pool_rewards) as one-week schedules for the pools' LP stakers. On Terra, yASTRO is exempt from the incentivization fee.

The legacy Generator 2.3.2 contracts still exist on both chains, but emissions ended and they are not part of the protocol. See the Retired addresses.

Fee exemptions (update_fee_exemptions, the fee_exemptions query and the sender field of is_fee_expected) were added in 1.5.0, so they exist on Terra only. Everything else on this page applies to both chains.

Concepts​

Schedules and periods​

Reward schedules are counted in periods of one week. Each period starts on Monday 00:00 UTC. A new schedule starts right away and lasts until the next Monday plus duration_periods weeks, so the shortest schedule lasts between 7 days and 1 second and 14 days, depending on the day it's added. A schedule lasts at most 25 periods (about 6 months).

The reward is spread evenly over the schedule: rps = amount / (end - now). It must be at least 1 unit per second, otherwise incentivize fails. Overlapping schedules for the same reward token are added up.

A pool can have at most 5 external reward tokens at a time. A reward token whose schedules end is removed from the pool, and its next schedule counts as a new reward token again, so incentivizers are encouraged to keep schedules running without breaks.

Incentivization fee​

The first schedule of a reward token in a pool (a token the pool doesn't currently have as a reward) pays the incentivization fee. On both chains the fee is 1,500 ASTRO (1500000000 units of ASTRO), sent to the Maker. Attach it to the incentivize call next to the reward.

No fee is due when:

  • the pool already has the reward token,
  • the reward is ASTRO,
  • the sender is on the fee exemption list (Terra 1.5.0 only; yASTRO is on it).

Use is_fee_expected to check before sending.

Staking LP tokens​

Any LP token of a pool registered in the factory can be staked, whether or not the pool has rewards. Rewards are claimed automatically on every deposit and withdraw, or with claim_rewards. When a pool's provide_liquidity is called with auto_stake: true, the pool stakes the new LP tokens here for the provider.

Rewards that accrue while nobody is staked in a pool are "orphaned". The owner can collect them with claim_orphaned_rewards.

InstantiateMsg​

json
incentives.rs
Copy

_18
{
_18
"owner": "terra1k9j8rcyk87v5jvfla2m9wp200azegjz0eshl7n2pwv852a7ssceqsnn7pq",
_18
"factory": "terra14x9fr055x5hvr48hzy2t4q7kvjvfttsvxusa4xsdcy702mnzsvuqprer8r",
_18
"astro_token": {
_18
"native_token": {
_18
"denom": "ibc/8D8A7F7253615E5F76CB6252A1E1BD921D5EDB7BBAAF8913FB1C77FF125D9995"
_18
}
_18
},
_18
"vesting_contract": "terra1qyuarnzcc6uuft9n9mltraprreke4v8gvxd8u3nslngxhflhru9qw34nc3",
_18
"incentivization_fee_info": {
_18
"fee_receiver": "terra1ygcvxp9s054q8u2q4hvl52ke393zvgj0sllahlycm4mj8dm96zjsa45rzk",
_18
"fee": {
_18
"denom": "ibc/8D8A7F7253615E5F76CB6252A1E1BD921D5EDB7BBAAF8913FB1C77FF125D9995",
_18
"amount": "1500000000"
_18
}
_18
},
_18
"guardian": null
_18
}

ParamsTypeDescription
ownerStringAddress allowed to change contract parameters
factoryStringThe factory. Only pools registered in it can be staked in and incentivized
astro_tokenAssetInfoASTRO
vesting_contractStringThe Vesting contract that funded ASTRO emissions
incentivization_fee_infoOption<IncentivizationFeeInfo>The fee (a native coin) and its receiver
guardianOption<String>Address that can also update the blocked tokens list

The example uses the Terra deployment's values.

ExecuteMsg​

deposit​

Stakes the attached tokenfactory LP tokens, on behalf of recipient if set (otherwise the sender). Pending rewards are claimed first.


_5
{
_5
"deposit": {
_5
"recipient": "terra1..."
_5
}
_5
}

receive​

Stakes CW20 LP tokens. Send them to the Incentives contract with a CW20 send whose msg is the base64 of the hook below.

json
incentives.rs
Copy

_7
{
_7
"send": {
_7
"contract": "terra1eywh4av8sln6r45pxq45ltj798htfy0cfcf7fy3pxc2gcv6uc07se4ch9x",
_7
"amount": "1000000",
_7
"msg": "eyJkZXBvc2l0Ijp7fX0="
_7
}
_7
}

eyJkZXBvc2l0Ijp7fX0= is {"deposit":{}}. deposit_for is kept for older pool contracts.

withdraw​

Unstakes amount of an LP token. Pending rewards are claimed first.


_6
{
_6
"withdraw": {
_6
"lp_token": "terra1s275y73lfupag0g03nglxaedfnsw5z4m5zc9wk66guy503zuw5ss889tlx",
_6
"amount": "1000000"
_6
}
_6
}

lp_token is the CW20 address or the tokenfactory denom of the LP token.

claim_rewards​

Claims every pending reward for the listed LP tokens.


_7
{
_7
"claim_rewards": {
_7
"lp_tokens": [
_7
"terra1s275y73lfupag0g03nglxaedfnsw5z4m5zc9wk66guy503zuw5ss889tlx"
_7
]
_7
}
_7
}

incentivize​

Adds a reward schedule to a pool. Anyone can call it. Attach the reward (a native coin) and, if it's due, the incentivization fee. For a CW20 reward, first give the Incentives contract an allowance for the amount; it pulls the tokens with transfer_from.

This example adds a 4-week USDC.inj schedule to the Terra LUNA/USDC pool's LP token:

json
incentives.rs
Copy

_16
{
_16
"incentivize": {
_16
"lp_token": "terra1s275y73lfupag0g03nglxaedfnsw5z4m5zc9wk66guy503zuw5ss889tlx",
_16
"schedule": {
_16
"reward": {
_16
"info": {
_16
"native_token": {
_16
"denom": "ibc/E8481AD838C31D4FC12A504B10F9B4E2F830F8818D2735C2FFC707579B5FA60B"
_16
}
_16
},
_16
"amount": "5000000000"
_16
},
_16
"duration_periods": 4
_16
}
_16
}
_16
}

ParamsTypeDescription
lp_tokenStringThe pool's LP token: a CW20 address or a tokenfactory denom
rewardAssetThe reward token and the total amount for the whole schedule
duration_periodsu64Whole weeks after the next Monday, from 1 to 25

incentivize_many​

Same as incentivize for several pools in one call. Takes a list of [lp_token, schedule] pairs.


_18
{
_18
"incentivize_many": [
_18
[
_18
"terra1s275y73lfupag0g03nglxaedfnsw5z4m5zc9wk66guy503zuw5ss889tlx",
_18
{
_18
"reward": {
_18
"info": {
_18
"native_token": {
_18
"denom": "ibc/E8481AD838C31D4FC12A504B10F9B4E2F830F8818D2735C2FFC707579B5FA60B"
_18
}
_18
},
_18
"amount": "5000000000"
_18
},
_18
"duration_periods": 4
_18
}
_18
]
_18
]
_18
}

Owner messages​

MessageWhoWhat
update_config { astro_token?, vesting_contract?, generator_controller?, guardian?, incentivization_fee_info?, token_transfer_gas_limit? }ownerChanges general settings. token_transfer_gas_limit is between 400,000 and 1,500,000
update_fee_exemptions { add, remove }ownerAdds or removes senders that never pay the incentivization fee. Terra 1.5.0 only
update_blocked_tokens_list { add, remove }owner or guardianBlocked tokens can't be used as rewards, and pools containing them can't get ASTRO emissions
remove_reward_from_pool { lp_token, reward, bypass_upcoming_schedules, receiver }ownerRemoves a reward token from a pool and sends its remaining rewards to receiver
claim_orphaned_rewards { limit?, receiver }ownerSends orphaned rewards to receiver
setup_pools { pools }, set_tokens_per_second { amount }owner (or generator controller for setup_pools)ASTRO emissions. Unused: emissions are zero
deactivate_pool { lp_token }factoryCalled when the factory deregisters a pool
deactivate_blocked_pools {}anyoneRemoves active pools whose pair type is blocked
propose_new_owner, drop_ownership_proposal, claim_ownershipowner / proposed ownerTwo-step ownership transfer

On Terra, yASTRO is exempt from the fee:


_8
{
_8
"update_fee_exemptions": {
_8
"add": [
_8
"terra1fe8uj96z7f4jfsnkrdxhchxdhdtx8alr9zjqze76hm2ga6tpxjjq5rdjw7"
_8
],
_8
"remove": []
_8
}
_8
}

QueryMsg​

config​

Returns the contract configuration. Live Terra response:


_22
{
_22
"owner": "terra1k9j8rcyk87v5jvfla2m9wp200azegjz0eshl7n2pwv852a7ssceqsnn7pq",
_22
"factory": "terra14x9fr055x5hvr48hzy2t4q7kvjvfttsvxusa4xsdcy702mnzsvuqprer8r",
_22
"generator_controller": null,
_22
"astro_token": {
_22
"native_token": {
_22
"denom": "ibc/8D8A7F7253615E5F76CB6252A1E1BD921D5EDB7BBAAF8913FB1C77FF125D9995"
_22
}
_22
},
_22
"astro_per_second": "0",
_22
"total_alloc_points": "0",
_22
"vesting_contract": "terra1qyuarnzcc6uuft9n9mltraprreke4v8gvxd8u3nslngxhflhru9qw34nc3",
_22
"guardian": null,
_22
"incentivization_fee_info": {
_22
"fee_receiver": "terra1ygcvxp9s054q8u2q4hvl52ke393zvgj0sllahlycm4mj8dm96zjsa45rzk",
_22
"fee": {
_22
"denom": "ibc/8D8A7F7253615E5F76CB6252A1E1BD921D5EDB7BBAAF8913FB1C77FF125D9995",
_22
"amount": "1500000000"
_22
}
_22
},
_22
"token_transfer_gas_limit": 600000
_22
}

deposit​

The amount of an LP token a user has staked, as a Uint128.


_6
{
_6
"deposit": {
_6
"lp_token": "terra1s275y73lfupag0g03nglxaedfnsw5z4m5zc9wk66guy503zuw5ss889tlx",
_6
"user": "terra1..."
_6
}
_6
}

pending_rewards​

The rewards a user can claim for an LP token, as a list of Assets.


_6
{
_6
"pending_rewards": {
_6
"lp_token": "terra1s275y73lfupag0g03nglxaedfnsw5z4m5zc9wk66guy503zuw5ss889tlx",
_6
"user": "terra1..."
_6
}
_6
}

pool_info​

Total LP staked, every reward with its rate and index, and the last update time.

json
incentives.rs
Copy

_5
{
_5
"pool_info": {
_5
"lp_token": "terra1s275y73lfupag0g03nglxaedfnsw5z4m5zc9wk66guy503zuw5ss889tlx"
_5
}
_5
}

Each reward is either {"int": <AssetInfo>} (ASTRO emissions, no longer used) or {"ext": {"info": <AssetInfo>, "next_update_ts": ...}} (an external schedule). reward_info { lp_token } returns the same Vec<RewardInfo> on its own.

external_reward_schedules​

The schedules of one reward token in a pool: rps, start_ts and end_ts for each.


_8
{
_8
"external_reward_schedules": {
_8
"reward": "ibc/E8481AD838C31D4FC12A504B10F9B4E2F830F8818D2735C2FFC707579B5FA60B",
_8
"lp_token": "terra1s275y73lfupag0g03nglxaedfnsw5z4m5zc9wk66guy503zuw5ss889tlx",
_8
"start_after": null,
_8
"limit": 10
_8
}
_8
}

is_fee_expected​

Whether adding a schedule of reward to the pool would pay the incentivization fee. Returns a bool. Pass sender to account for fee exemptions (Terra 1.5.0 only).


_7
{
_7
"is_fee_expected": {
_7
"lp_token": "terra1s275y73lfupag0g03nglxaedfnsw5z4m5zc9wk66guy503zuw5ss889tlx",
_7
"reward": "ibc/E8481AD838C31D4FC12A504B10F9B4E2F830F8818D2735C2FFC707579B5FA60B",
_7
"sender": "terra1..."
_7
}
_7
}

fee_exemptions​

The addresses that don't pay the incentivization fee, paginated (Terra 1.5.0 only). On Terra it returns ["terra1fe8uj96z7f4jfsnkrdxhchxdhdtx8alr9zjqze76hm2ga6tpxjjq5rdjw7"] (yASTRO).


_6
{
_6
"fee_exemptions": {
_6
"start_after": null,
_6
"limit": 50
_6
}
_6
}

Other queries​

QueryReturns
pool_stakers { lp_token, start_after?, limit? }[address, amount] pairs of a pool's stakers
blocked_tokens_list { start_after?, limit? }The blocked tokens, as AssetInfos
list_pools { start_after?, limit? }Every LP token ever incentivized
active_pools {}Pools receiving ASTRO emissions, with their allocation points. Empty: emissions are zero

Page limits are at most 50.