The hold module serves as a fundamental building block for more complex financial operations on the Provenance blockchain, enabling secure and flexible fund management while maintaining the principles of user ownership and system security.
ConceptsSummaryHoldsManaging HoldsLocked CoinsStateOverviewState ArchitectureKey-Value Store DesignHoldsRecord FormatKey Structure ComponentsType ByteAddress LengthAccount AddressDenominationValue StructureAmount StorageMessagesSummaryGovernance EndpointsUnlockVestingAccountsMsgUnlockVestingAccountsRequestMsgUnlockVestingAccountsResponseEventsSummaryEventHoldAddedAttributesExampleEventHoldReleasedAttributesExampleQueriesSummaryGetHoldsRequestResponseGetAllHoldsRequestResponseRelated StructuresParams
Concepts
Summary
The x/hold module provides a mechanism for other modules to lock funds in place within accounts by creating hold records that prevent funds from being spent, sent, or delegated while keeping them in the owner's account, with hold management available only through keeper functions and integration with the bank module to properly reflect locked coins in spendable balance calculations.
Holds
"Holds" are an amount of funds in an account that must not be moved out of the account.
When a hold is placed on some funds, a record of them is created in the x/hold module. When funds are released from a hold, those records are updated appropriately.
Funds with a hold on them remain in the owners account but cannot be spent, sent, delegated or otherwise removed from the account until they are released from hold.
A hold can only be placed on funds that would otherwise be spendable. E.g. you can place a hold on vested funds, but not unvested funds.
Managing Holds
The x/hold module does not have any Msg or Tx endpoints for managing holds.
Putting holds on funds and releasing holds are actions that are only available via keeper functions. It is expected that other modules will use the keeper functions (e.g.
AddHold
and ReleaseHold
) as needed.Locked Coins
The x/hold module injects a
GetLockedCoinsFn
into the bank keeper in order to tell it which funds have a hold on them.This allows the bank module and keeper functions to take holds into account when reporting bank account information.
Specifically, the bank keeper functions,
LockedCoins
, and SpendableCoins
will reflect holds, as well as the SpendableBalances
query.The
AllBalances
query and similar keeper functions will still include the held funds though, since the funds actually are still in the account.State
Overview
The x/hold module uses key/value pairs to store hold-related data in state. The state management is designed for efficient storage and retrieval of hold information while maintaining optimal performance for fund restriction operations.
State Architecture
Key-Value Store Design
The hold module employs a simple yet efficient key-value storage pattern that enables quick lookups and updates of hold information. This design minimizes storage overhead while providing fast access to hold data.
Holds
Holds on funds are recorded by address and denom using a specific record format that ensures efficient storage and retrieval.
Record Format
The hold module uses a structured key format that enables efficient queries and updates:
plain text0x00 | len(<address>) | <address> | <denom> -> <amount>
This format provides a hierarchical organization that supports both specific and range queries efficiently.
Key Structure Components
Type Byte
Position: First byte of the key
Value:
0x00
Purpose: Identifies the record type within the module's state spaceComponent | Value | Description |
Type Byte | 0x00 | Fixed value of 0 for hold records |
Address Length
Position: Second byte of the key
Format: Single byte containing the length of the address
Encoding: 8-bit byte in big-endian order
Component | Format | Purpose |
len(<address>) | Single byte (8-bit) | Length of the following address |
Account Address
Position: Third component of the key
Format: Raw bytes of the account address
Length: Variable, as specified by the length byte
Component | Format | Description |
<address> | Raw address bytes | Account that owns the held funds |
Denomination
Position: Fourth component of the key
Format: String representation of the coin denomination
Encoding: UTF-8 string bytes
Component | Format | Description |
<denom> | String bytes | Denomination of the held coins |
Value Structure
Amount Storage
Format: String representation of the numerical amount being held
Storage: Direct string storage for precision and compatibility
Component | Format | Purpose |
<amount> | String | Numerical amount of held funds |
Messages
Summary
The Hold module provides a single governance-controlled message endpoint for unlocking vesting accounts, allowing the governance module authority to convert one or more vesting accounts back to base accounts by removing their vesting restrictions and returning full control of funds to the account holders.
Governance Endpoints
The Hold module contains governance-proposal-only endpoints that require authority from the governance module account.
UnlockVestingAccounts
Unlock one or more vesting accounts, converting them back to base accounts and removing vesting restrictions.
The
authority
must be the governance module account to execute this operation.It is expected to fail if:
- The provided
authority
is not the governance module's account
- One or more
addresses
are not valid bech32 address strings
- One or more
addresses
do not correspond to existing vesting accounts
MsgUnlockVestingAccountsRequest
protobuf// MsgUnlockVestingAccountsRequest defines the request for unlocking vesting accounts message MsgUnlockVestingAccountsRequest { option (cosmos.msg.v1.signer) = "authority"; option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; // authority is the address that can execute this message (governance module account) string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // addresses is the list of vesting account addresses to convert back to base accounts repeated string addresses = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; }
MsgUnlockVestingAccountsResponse
protobuf// MsgUnlockVestingAccountsResponse defines the response for unlocking vesting accounts message MsgUnlockVestingAccountsResponse {}
Events
Summary
The x/hold module in Provenance emits two specific events to track fund holds: EventHoldAdded when funds are placed on hold with an account address, amount, and reason, and EventHoldReleased when held funds are released back to the account, both providing essential audit trails for fund management operations within the blockchain ecosystem.
EventHoldAdded
This event is emitted when a hold is placed on some funds.
Type:
provenance.hold.v1.EventHoldAdded
Attributes
Attribute Key | Attribute Value |
address | bech32 string of account with the funds |
amount | string of coins newly placed on hold |
reason | human readable string |
All values are wrapped in double quotes.
Example
json{ "type": "provenance.hold.v1.EventHoldAdded", "attributes": [ {"key": "address", "value": "\"pb1v9jxgun9wde476twta6xse2lv4mx2mn56s5hm4\""}, {"key": "amount", "value": "\"1000000000nhash,5000musdf\""}, {"key": "reason", "value": "\"order 66\""} ] }
EventHoldReleased
This event is emitted when some held funds are released.
Type:
provenance.hold.v1.EventHoldReleased
Attributes
Attribute Key | Attribute Value |
address | bech32 string of account with the funds |
amount | string of the coins just released |
Both values are wrapped in double quotes.
Example
json{ "type": "provenance.hold.v1.EventHoldReleased", "attributes": [ {"key": "address", "value": "\"pb1v9jxgun9wde476twta6xse2lv4mx2mn56s5hm4\""}, {"key": "amount", "value": "\"1000000000nhash,5000musdf\""} ] }
Queries
Summary
The x/hold module provides two query endpoints for retrieving hold-related data: GetHolds for looking up funds on hold for a specific account address, and GetAllHolds for retrieving all funds on hold across all accounts with pagination support, enabling comprehensive monitoring and auditing of held funds within the Provenance blockchain ecosystem.
GetHolds
Look up the funds on hold for a specific account. The query takes in an address and returns a coins amount.
GitHub Repository: provenance/proto/provenance/hold/v1/query.proto#L28-L35
Request
protobuf// GetHoldsRequest defines the request structure for the GetHolds query message GetHoldsRequest { // address is the bech32 address string of the account to get holds for string address = 1; }
Response
GitHub Repository: provenance/proto/provenance/hold/v1/query.proto#L37-L45
protobuf// GetHoldsResponse defines the response structure for the GetHolds query message GetHoldsResponse { // amount is the total coins on hold for the requested address repeated cosmos.base.v1beta1.Coin amount = 1; }
Expected failures:
- Invalid or missing address
Behavior:
- If the account doesn't exist, or no coins are on hold for the account, the amount will be empty
GetAllHolds
Get all funds on hold for all accounts. The query takes in pagination parameters and returns a list of address/amount pairs.
GitHub Repository: provenance/proto/provenance/hold/v1/query.proto#L47-L54
Request
protobuf// GetAllHoldsRequest defines the request structure for the GetAllHolds query message GetAllHoldsRequest { // pagination defines an optional pagination for the request cosmos.base.query.v1beta1.PageRequest pagination = 1; }
Response
GitHub Repository: provenance/proto/provenance/hold/v1/query.proto#L56-L62
protobuf// GetAllHoldsResponse defines the response structure for the GetAllHolds query message GetAllHoldsResponse { // holds is the list of all account holds repeated AccountHold holds = 1; // pagination defines the pagination in the response cosmos.base.query.v1beta1.PageResponse pagination = 2; }
Related Structures
GitHub Repository: provenance/proto/provenance/hold/v1/hold.proto#L12-L19
protobuf// AccountHold defines an account address and the coins on hold for that account message AccountHold { // address is the bech32 address string of the account string address = 1; // amount is the coins on hold for the account repeated cosmos.base.v1beta1.Coin amount = 2; }
Expected failures:
- Invalid pagination parameters
Params
No param restrictions exist for the hold module.