Skip to main content
Version: Next

Treasury Module

Overview

The Treasury module offers an API for fee collection, and a scheduling system for managing those collected fees.

Concepts

Fee Collection

Every module within the PRYZM can levy a protocol fee on its operations. The Treasury module account aggregates these fees. Each fee collection operation must specify an amount and a fee type. The type is a string defined by the modules. For instance, "refractor-refract" is used by the Refractor module to impose a protocol fee on refract operations. The Treasury Keeper provides a suite of methods for the fee collection process:

  1. CollectFeeByRatio allows users to collect fees based on a specified ratio of the transacted amount. It requires the sender's address, the ratio, the total amount, and the fee type as input parameters. It returns the collected fees and the remaining amount.
  2. ComputeFeeByRatio calculates the fees based on the ratio and total amount, but doesn't collect the amount. Input parameters are the total amount and the ratio. It returns the computed fees and the remaining amount.
  3. CollectFee collects the fees from the sender's account and transfers them to the fee pool. It requires the sender's address, the fees to be collected, and the fee type as input.

Treasury Actions

The Treasury module empowers governance to schedule the execution of specific actions on the collected fees. The actions may include:

  • Hold: Retain the collected fees without any action.
  • Burn: Obliterate PRYZM tokens, thereby reducing their circulation and causing deflation of the native token.
  • Distribute To Stakers: Transfer PRYZM tokens to the feeCollector account for delegators' and validators' rewards.
  • Distribute To Community Pool: Allocate funds to the community pool, which can then be utilized through distribution module governance proposals.

All actions (except 'Hold') apply only to PRYZM tokens. For fees collected in other tokens, a flow-trade is created to exchange them for PRYZM tokens, and then the action is executed on the PRYZM tokens.

The action structure is defined as follows:

message Action {
ActionType action_type = 1;
google.protobuf.Timestamp occurrence = 2 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = true
];
// if expiration is not set, then the action will never expire and is executed forever unless gov decides to set another action.
google.protobuf.Timestamp expiration = 3 [
(gogoproto.nullable) = true,
(gogoproto.stdtime) = true
];
// if period is nil, then the action is only executed at the first occurrence and then replaced with a HOLD/NOOP action.
google.protobuf.Duration period = 4 [
(gogoproto.nullable) = true,
(gogoproto.stdduration) = true
];

// this is nil if the action is of type HOLD
ActionFlowTradeSettings flow_trade_settings = 5 [(gogoproto.nullable) = true];

// denoms in this list will not be affected by the action
repeated string excluded_denoms = 6;
}

// FeeType enumerates the valid types for feeType.
enum ActionType {
option (gogoproto.goproto_enum_prefix) = false;
ACTION_TYPE_HOLD = 0 [(gogoproto.enumvalue_customname) = "HoldActionType"];
ACTION_TYPE_BURN = 1 [(gogoproto.enumvalue_customname) = "BurnActionType"];
ACTION_TYPE_DISTRIBUTE_TO_STAKERS = 2 [(gogoproto.enumvalue_customname) = "DistributeToStakersActionType"];
ACTION_TYPE_DISTRIBUTE_TO_COMMUNITY_POOL = 3 [(gogoproto.enumvalue_customname) = "DistributeToCommunityPoolActionType"];
}

message ActionFlowTradeSettings {
// given the occurrence of an action, this is used to compute the start of the flow
// NOTE: the flowtrade library has a parameter for minimum start delay
google.protobuf.Duration start_delay = 1 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true
];

// given the start of the flow, this is used to compute the end of the flow
google.protobuf.Duration duration = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true
];

// the interval in which the distribution index is updated and hence tokens are swapped
// if dist_interval is 0, the flow is updated every time in or out tokens are increased or decreased
// if dist_interval is equal to the duration of flow, it means that all of the tokens are swapped once after the flow ends
google.protobuf.Duration dist_interval = 3 [
(gogoproto.stdduration) = true,
(gogoproto.nullable) = false
];

// the minimum price for the token-out in terms of token-in.
// in each swap interval, if the calculated price is less than this limit, the swap doesn't happen in that turn
string limit_price = 4 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];

// the duration of the exit window before swap interval, in which users can only exit the flow and joining is not permitted
// this duration is used to protect joiners from buying the token-out with a higher price when someone joins with a huge amount of token-in
google.protobuf.Duration exit_window_duration = 5 [
(gogoproto.stdduration) = true,
(gogoproto.nullable) = false
];
}

The ActionType defines action types, while ActionFlowTradeSettings determines how flow-trades for non-pryzm tokens sold for pryzm tokens are created. To execute an action, iterate through the treasury tokens and perform the appropriate action based on the token denomination:

  1. If the denom is in the excluded_denoms list, skip it.
  2. If the denom matches the staking module's BondDenom, execute the token action.
  3. If the denom is an expired yAsset, burn the worthless token immediately.
  4. Otherwise, create a flow-trade to sell the token for BondDenom according to the provided settings. Once the flow ends, execute the action on the outcome.

Action Scheduling: The occurrence, expiration, and period properties control action execution:

  • occurrence: Defines the next action execution time. When current time equals occurrence time, execute the action and calculate the next occurrence time using the period property. All action types, except HoldActionType, have this property.
  • expiration: Specifies when an action expires and is replaced by a HoldAction. If an action lacks an expiration time, it remains active until governance replaces it.
  • period: Defines the duration between two consecutive action occurrences. If an action lacks a period, it isn't rescheduled after execution and is replaced by a HoldAction. If it has a period, the next occurrence time is calculated based on current time and the period property.

In summary, occurrence, expiration, and period automate treasury module action execution. Occurrence schedules action execution, expiration states when an action should be replaced by a HoldAction, and period schedules the next action occurrence time.

Transitions

End Block

The Treasury module has two end-of-block functions:

  1. Claim Ended Flows: The Treasury module trades tokens for BondDenom tokens through flow-trade to enact a particular action. These flows have a scheduled end-time. Once each block reaches its conclusion, the Treasury module scans the ended flows list, claims the tokens, and executes the appropriate action. This procedure ensures the tokens are utilized for their intended purpose and the flow-trade concludes as planned.
  2. Execute and Update Action: The Treasury module also evaluates the occurrence time of the current action at each block. If the time has arrived, the action is executed. If the action is periodic, the module updates the occurrence time for future execution. If the action has expired, it is replaced with a HoldActionType. This mechanism ensures that the Treasury module automates the execution of treasury actions following the predefined schedule and conditions.

In summary, the Treasury claims ended flows to execute actions on tokens and ensures the appropriate use of these tokens. It also automates the execution of treasury actions based on the established schedule and conditions.

Parameters

The Treasury module does not have any parameters.

Messages

MsgUpdateParams

This message can be used to update module parameters through governance.

message MsgUpdateParams {
string authority = 1;
Params params = 2 [(gogoproto.nullable) = false];
}
message MsgUpdateParamsResponse {}

MsgSetAction

This message can be sent through governance to designate an action to be executed on the collected fees:

message MsgSetAction {
string authority = 1;
Action action = 2 [(gogoproto.nullable) = false];
}

The response contains no properties:

message MsgSetActionResponse {}

Queries

Params

This query fetches the current module parameters.

// QueryParamsRequest is request type for the Query/Params RPC method.
message QueryParamsRequest {}

// QueryParamsResponse is response type for the Query/Params RPC method.
message QueryParamsResponse {
// params holds all the parameters of this module.
Params params = 1 [(gogoproto.nullable) = false];
}

QueryGetAction

This query fetches the current action.

message QueryGetActionRequest {}

message QueryGetActionResponse {
Action action = 1 [(gogoproto.nullable) = false];
}

The corresponding CLI command is:

pryzmd query treasury action

Flow Trades

This query fetches a list of flow-trade objects. Each flow-trade object represents a flow created to sell a token to execute an action. Each object contains the flow's end time and the action type to be executed.

message QueryAllFlowTradeRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}

message QueryAllFlowTradeResponse {
repeated FlowTrade flow_trade = 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

The corresponding CLI command is:

pryzmd query treasury list-flow-trade

Flow Trade

This query fetches a specific flow-trade object. Each object represents a flow created to sell a token to execute an action, and includes the flow's end time and the action type to be executed.

message QueryGetFlowTradeRequest {
uint64 flow_id = 1;
}

message QueryGetFlowTradeResponse {
FlowTrade flow_trade = 1 [(gogoproto.nullable) = false];
}

The corresponding CLI command is:

pryzmd query show-flow-trade [flow-id]

Events

EventTreasuryCollectFee

The EventTreasuryCollectFee event is triggered when the treasury keeper collects a fee. The event provides information about the fee, including its type, the collected amount, and the source.

message EventTreasuryCollectFee {
string fee_type = 1;
string amount = 2;
string from = 3;
}

EventCreateFlowForAmount

The EventCreateFlowForAmount event is fired when a flow trade starts to exchange fee tokens for stakeDenom. This initiates an associated action.

message EventCreateFlowForAmount {
uint64 flow_id = 1;
ActionType action_type = 2;
cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
}

EventExecuteActionForAmount

EventExecuteActionForAmount is activated when a specific treasury action is enacted for a certain fee amount.

message EventExecuteActionForAmount {
ActionType action_type = 1;
cosmos.base.v1beta1.Coin amount = 2 [(gogoproto.nullable) = false];
}

EventSetAction

EventSetAction is activated when a new action is assigned to the treasury via a government proposal or an automated procedure. This event records the details of the added action and can track modifications to existing actions, such as rescheduling or substituting them with a Hold action.

message EventSetAction {
Action action = 1 [(gogoproto.nullable) = false];
}

EventSetFlowTrade

EventSetFlowTrade is activated when a flow-trade is established in the store, either through updating an existing object or creating a new one.

message EventSetFlowTrade {
FlowTrade flow_trade = 1 [(gogoproto.nullable) = false];
}

EventRemoveFlowTrade

EventRemoveFlowTrade is activated when a flow-trade object is deleted from the store.

message EventRemoveFlowTrade {
google.protobuf.Timestamp end_time = 1 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false
];
uint64 flow_id = 2;
}

State

Parameters

Parameters are stored with this store key:

(
[]byte("v1/params/")
) -> ProtoBuf(Params)

Flow Trade

The FlowTrade objects are stored with the following key:

[]byte("v1/flow-trade/") |
[]byte(endTime) |
[]byte(flowId)

Action

The treasury Action is stored with the following key:

[]byte("v1/action/")

Parameters

This module's only parameter is the gas_fee_take_ratio, which is used in an ante handler when deducting fees for transactions. For each transaction we send a portion of the gas fees to the treasury module, and the rest is sent to the fee collector.

message Params {
string gas_fee_take_ratio = 1 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

Genesis

The genesis state of the module comprises the action and a list of unfinished flow-trades created for previous actions.

// GenesisState defines the treasury module's genesis state.
message GenesisState {
Action action = 1 [(gogoproto.nullable) = false];
repeated FlowTrade flow_trade_list = 2 [(gogoproto.nullable) = false];
// this line is used by starport scaffolding # genesis/proto/state
}