mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 10:37:26 +00:00 
			
		
		
		
	Add savings strategy (#1290)
* Add basic savings strategy Supports ukava * Use clearer error message for ErrInvalidVaultStrategy * Add invariants * Separate specific vault/all vaults query, update depositor inconsistencies * Update swagger * Use single bkava AllowedVault for all bkava variants * Do not use allowedVault.Denom for value * Fix vault balance query * Update query to list bkava vaults * Add vaults query doc * Update grpc query test with no supply * Add earn hooks * Handle errors * Update outdated doc comments, make getAllowedVault_Raw private * Fix outdated comments, lints * Fix comment maths * Use AccAddressFromBech32 to validate message addresses
This commit is contained in:
		
							parent
							
								
									8593d26c24
								
							
						
					
					
						commit
						ded692d2f4
					
				@ -6962,7 +6962,7 @@ paths:
 | 
				
			|||||||
        - Committee
 | 
					        - Committee
 | 
				
			||||||
  /kava/earn/v1beta1/deposits:
 | 
					  /kava/earn/v1beta1/deposits:
 | 
				
			||||||
    get:
 | 
					    get:
 | 
				
			||||||
      summary: Deposits queries deposit details based on owner address and vault
 | 
					      summary: Deposits queries deposit details based on depositor address and vault
 | 
				
			||||||
      operationId: EarnDeposits
 | 
					      operationId: EarnDeposits
 | 
				
			||||||
      responses:
 | 
					      responses:
 | 
				
			||||||
        '200':
 | 
					        '200':
 | 
				
			||||||
@ -7067,8 +7067,8 @@ paths:
 | 
				
			|||||||
                      type: string
 | 
					                      type: string
 | 
				
			||||||
                      format: byte
 | 
					                      format: byte
 | 
				
			||||||
      parameters:
 | 
					      parameters:
 | 
				
			||||||
        - name: owner
 | 
					        - name: depositor
 | 
				
			||||||
          description: owner optionally filters deposits by owner.
 | 
					          description: depositor optionally filters deposits by depositor.
 | 
				
			||||||
          in: query
 | 
					          in: query
 | 
				
			||||||
          required: false
 | 
					          required: false
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
@ -7237,9 +7237,9 @@ paths:
 | 
				
			|||||||
                      format: byte
 | 
					                      format: byte
 | 
				
			||||||
      tags:
 | 
					      tags:
 | 
				
			||||||
        - Earn
 | 
					        - Earn
 | 
				
			||||||
  /kava/earn/v1beta1/vaults/{denom}:
 | 
					  /kava/earn/v1beta1/vaults:
 | 
				
			||||||
    get:
 | 
					    get:
 | 
				
			||||||
      summary: Vaults queries vaults based on vault denom
 | 
					      summary: Vaults queries all vaults
 | 
				
			||||||
      operationId: EarnVaults
 | 
					      operationId: EarnVaults
 | 
				
			||||||
      responses:
 | 
					      responses:
 | 
				
			||||||
        '200':
 | 
					        '200':
 | 
				
			||||||
@ -7336,6 +7336,105 @@ paths:
 | 
				
			|||||||
                    value:
 | 
					                    value:
 | 
				
			||||||
                      type: string
 | 
					                      type: string
 | 
				
			||||||
                      format: byte
 | 
					                      format: byte
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - Earn
 | 
				
			||||||
 | 
					  /kava/earn/v1beta1/vaults/{denom}:
 | 
				
			||||||
 | 
					    get:
 | 
				
			||||||
 | 
					      summary: Vault queries a single vault based on the vault denom
 | 
				
			||||||
 | 
					      operationId: EarnVault
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        '200':
 | 
				
			||||||
 | 
					          description: A successful response.
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: object
 | 
				
			||||||
 | 
					            properties:
 | 
				
			||||||
 | 
					              vault:
 | 
				
			||||||
 | 
					                type: object
 | 
				
			||||||
 | 
					                properties:
 | 
				
			||||||
 | 
					                  denom:
 | 
				
			||||||
 | 
					                    type: string
 | 
				
			||||||
 | 
					                    title: denom represents the denom of the vault
 | 
				
			||||||
 | 
					                  strategies:
 | 
				
			||||||
 | 
					                    type: array
 | 
				
			||||||
 | 
					                    items:
 | 
				
			||||||
 | 
					                      type: string
 | 
				
			||||||
 | 
					                      enum:
 | 
				
			||||||
 | 
					                        - STRATEGY_TYPE_UNSPECIFIED
 | 
				
			||||||
 | 
					                        - STRATEGY_TYPE_HARD
 | 
				
			||||||
 | 
					                        - STRATEGY_TYPE_SAVINGS
 | 
				
			||||||
 | 
					                      default: STRATEGY_TYPE_UNSPECIFIED
 | 
				
			||||||
 | 
					                      description: >-
 | 
				
			||||||
 | 
					                        StrategyType is the type of strategy that a vault uses
 | 
				
			||||||
 | 
					                        to optimize yields.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                         - STRATEGY_TYPE_UNSPECIFIED: STRATEGY_TYPE_UNSPECIFIED represents an unspecified or invalid strategy type.
 | 
				
			||||||
 | 
					                         - STRATEGY_TYPE_HARD: STRATEGY_TYPE_HARD represents the strategy that deposits assets in the Hard
 | 
				
			||||||
 | 
					                        module.
 | 
				
			||||||
 | 
					                         - STRATEGY_TYPE_SAVINGS: STRATEGY_TYPE_SAVINGS represents the strategy that deposits assets in the
 | 
				
			||||||
 | 
					                        Savings module.
 | 
				
			||||||
 | 
					                    description: VaultStrategy is the strategy used for this vault.
 | 
				
			||||||
 | 
					                  is_private_vault:
 | 
				
			||||||
 | 
					                    type: boolean
 | 
				
			||||||
 | 
					                    format: boolean
 | 
				
			||||||
 | 
					                    description: >-
 | 
				
			||||||
 | 
					                      IsPrivateVault is true if the vault only allows depositors
 | 
				
			||||||
 | 
					                      contained in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      AllowedDepositors.
 | 
				
			||||||
 | 
					                  allowed_depositors:
 | 
				
			||||||
 | 
					                    type: array
 | 
				
			||||||
 | 
					                    items:
 | 
				
			||||||
 | 
					                      type: string
 | 
				
			||||||
 | 
					                    description: >-
 | 
				
			||||||
 | 
					                      AllowedDepositors is a list of addresses that are allowed
 | 
				
			||||||
 | 
					                      to deposit to
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      this vault if IsPrivateVault is true. Addresses not
 | 
				
			||||||
 | 
					                      contained in this list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      are not allowed to deposit into this vault. If
 | 
				
			||||||
 | 
					                      IsPrivateVault is false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      this should be empty and ignored.
 | 
				
			||||||
 | 
					                  total_shares:
 | 
				
			||||||
 | 
					                    type: string
 | 
				
			||||||
 | 
					                    description: >-
 | 
				
			||||||
 | 
					                      TotalShares is the total amount of shares issued to
 | 
				
			||||||
 | 
					                      depositors.
 | 
				
			||||||
 | 
					                  total_value:
 | 
				
			||||||
 | 
					                    type: string
 | 
				
			||||||
 | 
					                    description: >-
 | 
				
			||||||
 | 
					                      TotalValue is the total value of denom coins supplied to
 | 
				
			||||||
 | 
					                      the vault if the
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      vault were to be liquidated.
 | 
				
			||||||
 | 
					                description: VaultResponse is the response type for a vault.
 | 
				
			||||||
 | 
					                title: vault represents the queried earn module vault
 | 
				
			||||||
 | 
					            description: >-
 | 
				
			||||||
 | 
					              QueryVaultResponse is the response type for the Query/Vault RPC
 | 
				
			||||||
 | 
					              method.
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					          description: An unexpected error response
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: object
 | 
				
			||||||
 | 
					            properties:
 | 
				
			||||||
 | 
					              error:
 | 
				
			||||||
 | 
					                type: string
 | 
				
			||||||
 | 
					              code:
 | 
				
			||||||
 | 
					                type: integer
 | 
				
			||||||
 | 
					                format: int32
 | 
				
			||||||
 | 
					              message:
 | 
				
			||||||
 | 
					                type: string
 | 
				
			||||||
 | 
					              details:
 | 
				
			||||||
 | 
					                type: array
 | 
				
			||||||
 | 
					                items:
 | 
				
			||||||
 | 
					                  type: object
 | 
				
			||||||
 | 
					                  properties:
 | 
				
			||||||
 | 
					                    type_url:
 | 
				
			||||||
 | 
					                      type: string
 | 
				
			||||||
 | 
					                    value:
 | 
				
			||||||
 | 
					                      type: string
 | 
				
			||||||
 | 
					                      format: byte
 | 
				
			||||||
      parameters:
 | 
					      parameters:
 | 
				
			||||||
        - name: denom
 | 
					        - name: denom
 | 
				
			||||||
          description: vault filters vault by denom
 | 
					          description: vault filters vault by denom
 | 
				
			||||||
@ -54527,6 +54626,70 @@ definitions:
 | 
				
			|||||||
    description: >-
 | 
					    description: >-
 | 
				
			||||||
      QueryParamsResponse defines the response type for querying x/earn
 | 
					      QueryParamsResponse defines the response type for querying x/earn
 | 
				
			||||||
      parameters.
 | 
					      parameters.
 | 
				
			||||||
 | 
					  kava.earn.v1beta1.QueryVaultResponse:
 | 
				
			||||||
 | 
					    type: object
 | 
				
			||||||
 | 
					    properties:
 | 
				
			||||||
 | 
					      vault:
 | 
				
			||||||
 | 
					        type: object
 | 
				
			||||||
 | 
					        properties:
 | 
				
			||||||
 | 
					          denom:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            title: denom represents the denom of the vault
 | 
				
			||||||
 | 
					          strategies:
 | 
				
			||||||
 | 
					            type: array
 | 
				
			||||||
 | 
					            items:
 | 
				
			||||||
 | 
					              type: string
 | 
				
			||||||
 | 
					              enum:
 | 
				
			||||||
 | 
					                - STRATEGY_TYPE_UNSPECIFIED
 | 
				
			||||||
 | 
					                - STRATEGY_TYPE_HARD
 | 
				
			||||||
 | 
					                - STRATEGY_TYPE_SAVINGS
 | 
				
			||||||
 | 
					              default: STRATEGY_TYPE_UNSPECIFIED
 | 
				
			||||||
 | 
					              description: >-
 | 
				
			||||||
 | 
					                StrategyType is the type of strategy that a vault uses to
 | 
				
			||||||
 | 
					                optimize yields.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                 - STRATEGY_TYPE_UNSPECIFIED: STRATEGY_TYPE_UNSPECIFIED represents an unspecified or invalid strategy type.
 | 
				
			||||||
 | 
					                 - STRATEGY_TYPE_HARD: STRATEGY_TYPE_HARD represents the strategy that deposits assets in the Hard
 | 
				
			||||||
 | 
					                module.
 | 
				
			||||||
 | 
					                 - STRATEGY_TYPE_SAVINGS: STRATEGY_TYPE_SAVINGS represents the strategy that deposits assets in the
 | 
				
			||||||
 | 
					                Savings module.
 | 
				
			||||||
 | 
					            description: VaultStrategy is the strategy used for this vault.
 | 
				
			||||||
 | 
					          is_private_vault:
 | 
				
			||||||
 | 
					            type: boolean
 | 
				
			||||||
 | 
					            format: boolean
 | 
				
			||||||
 | 
					            description: >-
 | 
				
			||||||
 | 
					              IsPrivateVault is true if the vault only allows depositors
 | 
				
			||||||
 | 
					              contained in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              AllowedDepositors.
 | 
				
			||||||
 | 
					          allowed_depositors:
 | 
				
			||||||
 | 
					            type: array
 | 
				
			||||||
 | 
					            items:
 | 
				
			||||||
 | 
					              type: string
 | 
				
			||||||
 | 
					            description: >-
 | 
				
			||||||
 | 
					              AllowedDepositors is a list of addresses that are allowed to
 | 
				
			||||||
 | 
					              deposit to
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              this vault if IsPrivateVault is true. Addresses not contained in
 | 
				
			||||||
 | 
					              this list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              are not allowed to deposit into this vault. If IsPrivateVault is
 | 
				
			||||||
 | 
					              false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              this should be empty and ignored.
 | 
				
			||||||
 | 
					          total_shares:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            description: TotalShares is the total amount of shares issued to depositors.
 | 
				
			||||||
 | 
					          total_value:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            description: >-
 | 
				
			||||||
 | 
					              TotalValue is the total value of denom coins supplied to the vault
 | 
				
			||||||
 | 
					              if the
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              vault were to be liquidated.
 | 
				
			||||||
 | 
					        description: VaultResponse is the response type for a vault.
 | 
				
			||||||
 | 
					        title: vault represents the queried earn module vault
 | 
				
			||||||
 | 
					    description: QueryVaultResponse is the response type for the Query/Vault RPC method.
 | 
				
			||||||
  kava.earn.v1beta1.QueryVaultsResponse:
 | 
					  kava.earn.v1beta1.QueryVaultsResponse:
 | 
				
			||||||
    type: object
 | 
					    type: object
 | 
				
			||||||
    properties:
 | 
					    properties:
 | 
				
			||||||
 | 
				
			|||||||
@ -199,6 +199,8 @@
 | 
				
			|||||||
    - [QueryDepositsResponse](#kava.earn.v1beta1.QueryDepositsResponse)
 | 
					    - [QueryDepositsResponse](#kava.earn.v1beta1.QueryDepositsResponse)
 | 
				
			||||||
    - [QueryParamsRequest](#kava.earn.v1beta1.QueryParamsRequest)
 | 
					    - [QueryParamsRequest](#kava.earn.v1beta1.QueryParamsRequest)
 | 
				
			||||||
    - [QueryParamsResponse](#kava.earn.v1beta1.QueryParamsResponse)
 | 
					    - [QueryParamsResponse](#kava.earn.v1beta1.QueryParamsResponse)
 | 
				
			||||||
 | 
					    - [QueryVaultRequest](#kava.earn.v1beta1.QueryVaultRequest)
 | 
				
			||||||
 | 
					    - [QueryVaultResponse](#kava.earn.v1beta1.QueryVaultResponse)
 | 
				
			||||||
    - [QueryVaultsRequest](#kava.earn.v1beta1.QueryVaultsRequest)
 | 
					    - [QueryVaultsRequest](#kava.earn.v1beta1.QueryVaultsRequest)
 | 
				
			||||||
    - [QueryVaultsResponse](#kava.earn.v1beta1.QueryVaultsResponse)
 | 
					    - [QueryVaultsResponse](#kava.earn.v1beta1.QueryVaultsResponse)
 | 
				
			||||||
    - [VaultResponse](#kava.earn.v1beta1.VaultResponse)
 | 
					    - [VaultResponse](#kava.earn.v1beta1.VaultResponse)
 | 
				
			||||||
@ -2967,7 +2969,7 @@ QueryDepositsRequest is the request type for the Query/Deposits RPC method.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
| Field | Type | Label | Description |
 | 
					| Field | Type | Label | Description |
 | 
				
			||||||
| ----- | ---- | ----- | ----------- |
 | 
					| ----- | ---- | ----- | ----------- |
 | 
				
			||||||
| `owner` | [string](#string) |  | owner optionally filters deposits by owner |
 | 
					| `depositor` | [string](#string) |  | depositor optionally filters deposits by depositor |
 | 
				
			||||||
| `denom` | [string](#string) |  | denom optionally filters deposits by vault denom |
 | 
					| `denom` | [string](#string) |  | denom optionally filters deposits by vault denom |
 | 
				
			||||||
| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) |  | pagination defines an optional pagination for the request. |
 | 
					| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) |  | pagination defines an optional pagination for the request. |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3017,10 +3019,10 @@ QueryParamsResponse defines the response type for querying x/earn parameters.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<a name="kava.earn.v1beta1.QueryVaultsRequest"></a>
 | 
					<a name="kava.earn.v1beta1.QueryVaultRequest"></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### QueryVaultsRequest
 | 
					### QueryVaultRequest
 | 
				
			||||||
QueryVaultsRequest is the request type for the Query/Vault RPC method.
 | 
					QueryVaultRequest is the request type for the Query/Vault RPC method.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Field | Type | Label | Description |
 | 
					| Field | Type | Label | Description |
 | 
				
			||||||
@ -3032,6 +3034,31 @@ QueryVaultsRequest is the request type for the Query/Vault RPC method.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<a name="kava.earn.v1beta1.QueryVaultResponse"></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### QueryVaultResponse
 | 
				
			||||||
 | 
					QueryVaultResponse is the response type for the Query/Vault RPC method.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Field | Type | Label | Description |
 | 
				
			||||||
 | 
					| ----- | ---- | ----- | ----------- |
 | 
				
			||||||
 | 
					| `vault` | [VaultResponse](#kava.earn.v1beta1.VaultResponse) |  | vault represents the queried earn module vault |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<a name="kava.earn.v1beta1.QueryVaultsRequest"></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### QueryVaultsRequest
 | 
				
			||||||
 | 
					QueryVaultsRequest is the request type for the Query/Vaults RPC method.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<a name="kava.earn.v1beta1.QueryVaultsResponse"></a>
 | 
					<a name="kava.earn.v1beta1.QueryVaultsResponse"></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### QueryVaultsResponse
 | 
					### QueryVaultsResponse
 | 
				
			||||||
@ -3081,8 +3108,9 @@ Query defines the gRPC querier service for earn module
 | 
				
			|||||||
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
 | 
					| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
 | 
				
			||||||
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
 | 
					| ----------- | ------------ | ------------- | ------------| ------- | -------- |
 | 
				
			||||||
| `Params` | [QueryParamsRequest](#kava.earn.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#kava.earn.v1beta1.QueryParamsResponse) | Params queries all parameters of the earn module. | GET|/kava/earn/v1beta1/params|
 | 
					| `Params` | [QueryParamsRequest](#kava.earn.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#kava.earn.v1beta1.QueryParamsResponse) | Params queries all parameters of the earn module. | GET|/kava/earn/v1beta1/params|
 | 
				
			||||||
| `Vaults` | [QueryVaultsRequest](#kava.earn.v1beta1.QueryVaultsRequest) | [QueryVaultsResponse](#kava.earn.v1beta1.QueryVaultsResponse) | Vaults queries vaults based on vault denom | GET|/kava/earn/v1beta1/vaults/{denom}|
 | 
					| `Vaults` | [QueryVaultsRequest](#kava.earn.v1beta1.QueryVaultsRequest) | [QueryVaultsResponse](#kava.earn.v1beta1.QueryVaultsResponse) | Vaults queries all vaults | GET|/kava/earn/v1beta1/vaults|
 | 
				
			||||||
| `Deposits` | [QueryDepositsRequest](#kava.earn.v1beta1.QueryDepositsRequest) | [QueryDepositsResponse](#kava.earn.v1beta1.QueryDepositsResponse) | Deposits queries deposit details based on owner address and vault | GET|/kava/earn/v1beta1/deposits|
 | 
					| `Vault` | [QueryVaultRequest](#kava.earn.v1beta1.QueryVaultRequest) | [QueryVaultResponse](#kava.earn.v1beta1.QueryVaultResponse) | Vault queries a single vault based on the vault denom | GET|/kava/earn/v1beta1/vaults/{denom}|
 | 
				
			||||||
 | 
					| `Deposits` | [QueryDepositsRequest](#kava.earn.v1beta1.QueryDepositsRequest) | [QueryDepositsResponse](#kava.earn.v1beta1.QueryDepositsResponse) | Deposits queries deposit details based on depositor address and vault | GET|/kava/earn/v1beta1/deposits|
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 <!-- end services -->
 | 
					 <!-- end services -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,12 +20,17 @@ service Query {
 | 
				
			|||||||
    option (google.api.http).get = "/kava/earn/v1beta1/params";
 | 
					    option (google.api.http).get = "/kava/earn/v1beta1/params";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Vaults queries vaults based on vault denom
 | 
					  // Vaults queries all vaults
 | 
				
			||||||
  rpc Vaults(QueryVaultsRequest) returns (QueryVaultsResponse) {
 | 
					  rpc Vaults(QueryVaultsRequest) returns (QueryVaultsResponse) {
 | 
				
			||||||
 | 
					    option (google.api.http).get = "/kava/earn/v1beta1/vaults";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Vault queries a single vault based on the vault denom
 | 
				
			||||||
 | 
					  rpc Vault(QueryVaultRequest) returns (QueryVaultResponse) {
 | 
				
			||||||
    option (google.api.http).get = "/kava/earn/v1beta1/vaults/{denom}";
 | 
					    option (google.api.http).get = "/kava/earn/v1beta1/vaults/{denom}";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Deposits queries deposit details based on owner address and vault
 | 
					  // Deposits queries deposit details based on depositor address and vault
 | 
				
			||||||
  rpc Deposits(QueryDepositsRequest) returns (QueryDepositsResponse) {
 | 
					  rpc Deposits(QueryDepositsRequest) returns (QueryDepositsResponse) {
 | 
				
			||||||
    option (google.api.http).get = "/kava/earn/v1beta1/deposits";
 | 
					    option (google.api.http).get = "/kava/earn/v1beta1/deposits";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -40,11 +45,8 @@ message QueryParamsResponse {
 | 
				
			|||||||
  Params params = 1 [(gogoproto.nullable) = false];
 | 
					  Params params = 1 [(gogoproto.nullable) = false];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// QueryVaultsRequest is the request type for the Query/Vault RPC method.
 | 
					// QueryVaultsRequest is the request type for the Query/Vaults RPC method.
 | 
				
			||||||
message QueryVaultsRequest {
 | 
					message QueryVaultsRequest {}
 | 
				
			||||||
  // vault filters vault by denom
 | 
					 | 
				
			||||||
  string denom = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// QueryVaultsResponse is the response type for the Query/Vaults RPC method.
 | 
					// QueryVaultsResponse is the response type for the Query/Vaults RPC method.
 | 
				
			||||||
message QueryVaultsResponse {
 | 
					message QueryVaultsResponse {
 | 
				
			||||||
@ -52,6 +54,18 @@ message QueryVaultsResponse {
 | 
				
			|||||||
  repeated VaultResponse vaults = 1 [(gogoproto.nullable) = false];
 | 
					  repeated VaultResponse vaults = 1 [(gogoproto.nullable) = false];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// QueryVaultRequest is the request type for the Query/Vault RPC method.
 | 
				
			||||||
 | 
					message QueryVaultRequest {
 | 
				
			||||||
 | 
					  // vault filters vault by denom
 | 
				
			||||||
 | 
					  string denom = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// QueryVaultResponse is the response type for the Query/Vault RPC method.
 | 
				
			||||||
 | 
					message QueryVaultResponse {
 | 
				
			||||||
 | 
					  // vault represents the queried earn module vault
 | 
				
			||||||
 | 
					  VaultResponse vault = 1 [(gogoproto.nullable) = false];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// VaultResponse is the response type for a vault.
 | 
					// VaultResponse is the response type for a vault.
 | 
				
			||||||
message VaultResponse {
 | 
					message VaultResponse {
 | 
				
			||||||
  // denom represents the denom of the vault
 | 
					  // denom represents the denom of the vault
 | 
				
			||||||
@ -84,8 +98,8 @@ message VaultResponse {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// QueryDepositsRequest is the request type for the Query/Deposits RPC method.
 | 
					// QueryDepositsRequest is the request type for the Query/Deposits RPC method.
 | 
				
			||||||
message QueryDepositsRequest {
 | 
					message QueryDepositsRequest {
 | 
				
			||||||
  // owner optionally filters deposits by owner
 | 
					  // depositor optionally filters deposits by depositor
 | 
				
			||||||
  string owner = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
 | 
					  string depositor = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // denom optionally filters deposits by vault denom
 | 
					  // denom optionally filters deposits by vault denom
 | 
				
			||||||
  string denom = 2;
 | 
					  string denom = 2;
 | 
				
			||||||
 | 
				
			|||||||
@ -32,6 +32,7 @@ func GetQueryCmd() *cobra.Command {
 | 
				
			|||||||
	cmds := []*cobra.Command{
 | 
						cmds := []*cobra.Command{
 | 
				
			||||||
		queryParamsCmd(),
 | 
							queryParamsCmd(),
 | 
				
			||||||
		queryVaultsCmd(),
 | 
							queryVaultsCmd(),
 | 
				
			||||||
 | 
							queryVaultCmd(),
 | 
				
			||||||
		queryDepositsCmd(),
 | 
							queryDepositsCmd(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -71,13 +72,11 @@ func queryParamsCmd() *cobra.Command {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func queryVaultsCmd() *cobra.Command {
 | 
					func queryVaultsCmd() *cobra.Command {
 | 
				
			||||||
	return &cobra.Command{
 | 
						return &cobra.Command{
 | 
				
			||||||
		Use:   "vaults",
 | 
							Use:     "vaults",
 | 
				
			||||||
		Short: "get the earn vaults",
 | 
							Short:   "get all earn vaults",
 | 
				
			||||||
		Long:  "Get the earn module vaults.",
 | 
							Long:    "Get all earn module vaults.",
 | 
				
			||||||
		Args:  cobra.MaximumNArgs(1),
 | 
							Args:    cobra.NoArgs,
 | 
				
			||||||
		Example: fmt.Sprintf(`%[1]s q %[2]s vaults
 | 
							Example: fmt.Sprintf(`%[1]s q %[2]s vaults`, version.AppName, types.ModuleName),
 | 
				
			||||||
%[1]s q %[2]s vaults
 | 
					 | 
				
			||||||
%[1]s q %[2]s vaults usdx`, version.AppName, types.ModuleName),
 | 
					 | 
				
			||||||
		RunE: func(cmd *cobra.Command, args []string) error {
 | 
							RunE: func(cmd *cobra.Command, args []string) error {
 | 
				
			||||||
			clientCtx, err := client.GetClientQueryContext(cmd)
 | 
								clientCtx, err := client.GetClientQueryContext(cmd)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
@ -86,13 +85,34 @@ func queryVaultsCmd() *cobra.Command {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			queryClient := types.NewQueryClient(clientCtx)
 | 
								queryClient := types.NewQueryClient(clientCtx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			vaultDenom := ""
 | 
								req := types.NewQueryVaultsRequest()
 | 
				
			||||||
			if len(args) > 1 {
 | 
								res, err := queryClient.Vaults(context.Background(), req)
 | 
				
			||||||
				vaultDenom = args[0]
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			req := types.NewQueryVaultsRequest(vaultDenom)
 | 
								return clientCtx.PrintProto(res)
 | 
				
			||||||
			res, err := queryClient.Vaults(context.Background(), req)
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func queryVaultCmd() *cobra.Command {
 | 
				
			||||||
 | 
						return &cobra.Command{
 | 
				
			||||||
 | 
							Use:     "vault",
 | 
				
			||||||
 | 
							Short:   "get a earn vault",
 | 
				
			||||||
 | 
							Long:    "Get a specific earn module vault by denom.",
 | 
				
			||||||
 | 
							Args:    cobra.ExactArgs(1),
 | 
				
			||||||
 | 
							Example: fmt.Sprintf(`%[1]s q %[2]s vault usdx`, version.AppName, types.ModuleName),
 | 
				
			||||||
 | 
							RunE: func(cmd *cobra.Command, args []string) error {
 | 
				
			||||||
 | 
								clientCtx, err := client.GetClientQueryContext(cmd)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								queryClient := types.NewQueryClient(clientCtx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req := types.NewQueryVaultRequest(args[0])
 | 
				
			||||||
 | 
								res, err := queryClient.Vault(context.Background(), req)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
				
			|||||||
@ -63,7 +63,8 @@ func (k *Keeper) Deposit(
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get VaultShareRecord for account, create if not exist
 | 
						// Get VaultShareRecord for account, create if account has no deposits.
 | 
				
			||||||
 | 
						// This can still be found if the account has deposits for other vaults.
 | 
				
			||||||
	vaultShareRecord, found := k.GetVaultShareRecord(ctx, depositor)
 | 
						vaultShareRecord, found := k.GetVaultShareRecord(ctx, depositor)
 | 
				
			||||||
	if !found {
 | 
						if !found {
 | 
				
			||||||
		// Create a new empty VaultShareRecord with 0 supply
 | 
							// Create a new empty VaultShareRecord with 0 supply
 | 
				
			||||||
@ -75,6 +76,12 @@ func (k *Keeper) Deposit(
 | 
				
			|||||||
		return fmt.Errorf("failed to convert assets to shares: %w", err)
 | 
							return fmt.Errorf("failed to convert assets to shares: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isNew := vaultShareRecord.Shares.AmountOf(amount.Denom).IsZero()
 | 
				
			||||||
 | 
						if !isNew {
 | 
				
			||||||
 | 
							// If deposits for this vault already exists
 | 
				
			||||||
 | 
							k.BeforeVaultDepositModified(ctx, amount.Denom, depositor, vaultRecord.TotalShares.Amount)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Increment VaultRecord total shares and account shares
 | 
						// Increment VaultRecord total shares and account shares
 | 
				
			||||||
	vaultRecord.TotalShares = vaultRecord.TotalShares.Add(shares)
 | 
						vaultRecord.TotalShares = vaultRecord.TotalShares.Add(shares)
 | 
				
			||||||
	vaultShareRecord.Shares = vaultShareRecord.Shares.Add(shares)
 | 
						vaultShareRecord.Shares = vaultShareRecord.Shares.Add(shares)
 | 
				
			||||||
@ -83,6 +90,11 @@ func (k *Keeper) Deposit(
 | 
				
			|||||||
	k.SetVaultRecord(ctx, vaultRecord)
 | 
						k.SetVaultRecord(ctx, vaultRecord)
 | 
				
			||||||
	k.SetVaultShareRecord(ctx, vaultShareRecord)
 | 
						k.SetVaultShareRecord(ctx, vaultShareRecord)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if isNew {
 | 
				
			||||||
 | 
							// If first deposit in this vault
 | 
				
			||||||
 | 
							k.AfterVaultDepositCreated(ctx, amount.Denom, depositor, shares.Amount)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Deposit to the strategy
 | 
						// Deposit to the strategy
 | 
				
			||||||
	if err := strategy.Deposit(ctx, amount); err != nil {
 | 
						if err := strategy.Deposit(ctx, amount); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
 | 
				
			|||||||
@ -167,3 +167,27 @@ func (suite *depositTestSuite) TestDeposit_PrivateVault() {
 | 
				
			|||||||
	err = suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
	suite.Require().NoError(err, "private vault should allow deposits from allowed addresses")
 | 
						suite.Require().NoError(err, "private vault should allow deposits from allowed addresses")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *depositTestSuite) TestDeposit_bKava() {
 | 
				
			||||||
 | 
						vaultDenom := "bkava"
 | 
				
			||||||
 | 
						coinDenom := vaultDenom + "-kavavaloper16xyempempp92x9hyzz9wrgf94r6j9h5f2w4n2l"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(coinDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(coinDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// vault denom is only "bkava" which has it's own special handler
 | 
				
			||||||
 | 
						suite.CreateVault(
 | 
				
			||||||
 | 
							vaultDenom,
 | 
				
			||||||
 | 
							types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS},
 | 
				
			||||||
 | 
							false,
 | 
				
			||||||
 | 
							[]sdk.AccAddress{},
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(
 | 
				
			||||||
 | 
							err,
 | 
				
			||||||
 | 
							"should be able to deposit bkava derivative denom in bkava vault",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -51,50 +51,96 @@ func (s queryServer) Vaults(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	sdkCtx := sdk.UnwrapSDKContext(ctx)
 | 
						sdkCtx := sdk.UnwrapSDKContext(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var queriedAllowedVaults types.AllowedVaults
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if req.Denom != "" {
 | 
					 | 
				
			||||||
		// Only 1 vault
 | 
					 | 
				
			||||||
		allowedVault, found := s.keeper.GetAllowedVault(sdkCtx, req.Denom)
 | 
					 | 
				
			||||||
		if !found {
 | 
					 | 
				
			||||||
			return nil, status.Errorf(codes.NotFound, "vault not found with specified denom")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		queriedAllowedVaults = types.AllowedVaults{allowedVault}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		// All vaults
 | 
					 | 
				
			||||||
		queriedAllowedVaults = s.keeper.GetAllowedVaults(sdkCtx)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vaults := []types.VaultResponse{}
 | 
						vaults := []types.VaultResponse{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, allowedVault := range queriedAllowedVaults {
 | 
						var vaultRecordsErr error
 | 
				
			||||||
		vaultTotalShares, found := s.keeper.GetVaultTotalShares(sdkCtx, allowedVault.Denom)
 | 
					
 | 
				
			||||||
 | 
						// Iterate over vault records instead of AllowedVaults to get all bkava-*
 | 
				
			||||||
 | 
						// vaults
 | 
				
			||||||
 | 
						s.keeper.IterateVaultRecords(sdkCtx, func(record types.VaultRecord) bool {
 | 
				
			||||||
 | 
							allowedVault, found := s.keeper.GetAllowedVault(sdkCtx, record.TotalShares.Denom)
 | 
				
			||||||
		if !found {
 | 
							if !found {
 | 
				
			||||||
			// No supply yet, no error just zero
 | 
								vaultRecordsErr = fmt.Errorf("vault record not found for vault record denom %s", record.TotalShares.Denom)
 | 
				
			||||||
			vaultTotalShares = types.NewVaultShare(allowedVault.Denom, sdk.ZeroDec())
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		totalValue, err := s.keeper.GetVaultTotalValue(sdkCtx, allowedVault.Denom)
 | 
							totalValue, err := s.keeper.GetVaultTotalValue(sdkCtx, record.TotalShares.Denom)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								vaultRecordsErr = err
 | 
				
			||||||
 | 
								// Stop iterating if error
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		vaults = append(vaults, types.VaultResponse{
 | 
							vaults = append(vaults, types.VaultResponse{
 | 
				
			||||||
			Denom:             allowedVault.Denom,
 | 
								Denom:             record.TotalShares.Denom,
 | 
				
			||||||
			Strategies:        allowedVault.Strategies,
 | 
								Strategies:        allowedVault.Strategies,
 | 
				
			||||||
			IsPrivateVault:    allowedVault.IsPrivateVault,
 | 
								IsPrivateVault:    allowedVault.IsPrivateVault,
 | 
				
			||||||
			AllowedDepositors: addressSliceToStringSlice(allowedVault.AllowedDepositors),
 | 
								AllowedDepositors: addressSliceToStringSlice(allowedVault.AllowedDepositors),
 | 
				
			||||||
			TotalShares:       vaultTotalShares.Amount.String(),
 | 
								TotalShares:       record.TotalShares.Amount.String(),
 | 
				
			||||||
			TotalValue:        totalValue.Amount,
 | 
								TotalValue:        totalValue.Amount,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if vaultRecordsErr != nil {
 | 
				
			||||||
 | 
							return nil, vaultRecordsErr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Does not include vaults that have no deposits, only iterates over vault
 | 
				
			||||||
 | 
						// records which exists only for those with deposits.
 | 
				
			||||||
	return &types.QueryVaultsResponse{
 | 
						return &types.QueryVaultsResponse{
 | 
				
			||||||
		Vaults: vaults,
 | 
							Vaults: vaults,
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Vaults implements the gRPC service handler for querying x/earn vaults.
 | 
				
			||||||
 | 
					func (s queryServer) Vault(
 | 
				
			||||||
 | 
						ctx context.Context,
 | 
				
			||||||
 | 
						req *types.QueryVaultRequest,
 | 
				
			||||||
 | 
					) (*types.QueryVaultResponse, error) {
 | 
				
			||||||
 | 
						if req == nil {
 | 
				
			||||||
 | 
							return nil, status.Errorf(codes.InvalidArgument, "empty request")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdkCtx := sdk.UnwrapSDKContext(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if req.Denom == "" {
 | 
				
			||||||
 | 
							return nil, status.Errorf(codes.InvalidArgument, "empty denom")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Only 1 vault
 | 
				
			||||||
 | 
						allowedVault, found := s.keeper.GetAllowedVault(sdkCtx, req.Denom)
 | 
				
			||||||
 | 
						if !found {
 | 
				
			||||||
 | 
							return nil, status.Errorf(codes.NotFound, "vault not found with specified denom")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Must be req.Denom and not allowedVault.Denom to get full "bkava" denom
 | 
				
			||||||
 | 
						vaultRecord, found := s.keeper.GetVaultRecord(sdkCtx, req.Denom)
 | 
				
			||||||
 | 
						if !found {
 | 
				
			||||||
 | 
							// No supply yet, no error just set it to zero
 | 
				
			||||||
 | 
							vaultRecord.TotalShares = types.NewVaultShare(req.Denom, sdk.ZeroDec())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						totalValue, err := s.keeper.GetVaultTotalValue(sdkCtx, req.Denom)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vault := types.VaultResponse{
 | 
				
			||||||
 | 
							// VaultRecord denom instead of AllowedVault.Denom for full bkava denom
 | 
				
			||||||
 | 
							Denom:             vaultRecord.TotalShares.Denom,
 | 
				
			||||||
 | 
							Strategies:        allowedVault.Strategies,
 | 
				
			||||||
 | 
							IsPrivateVault:    allowedVault.IsPrivateVault,
 | 
				
			||||||
 | 
							AllowedDepositors: addressSliceToStringSlice(allowedVault.AllowedDepositors),
 | 
				
			||||||
 | 
							TotalShares:       vaultRecord.TotalShares.Amount.String(),
 | 
				
			||||||
 | 
							TotalValue:        totalValue.Amount,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &types.QueryVaultResponse{
 | 
				
			||||||
 | 
							Vault: vault,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Deposits implements the gRPC service handler for querying x/earn deposits.
 | 
					// Deposits implements the gRPC service handler for querying x/earn deposits.
 | 
				
			||||||
func (s queryServer) Deposits(
 | 
					func (s queryServer) Deposits(
 | 
				
			||||||
	ctx context.Context,
 | 
						ctx context.Context,
 | 
				
			||||||
@ -107,17 +153,17 @@ func (s queryServer) Deposits(
 | 
				
			|||||||
	sdkCtx := sdk.UnwrapSDKContext(ctx)
 | 
						sdkCtx := sdk.UnwrapSDKContext(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 1. Specific account and specific vault
 | 
						// 1. Specific account and specific vault
 | 
				
			||||||
	if req.Owner != "" && req.Denom != "" {
 | 
						if req.Depositor != "" && req.Denom != "" {
 | 
				
			||||||
		return s.getAccountVaultDeposit(sdkCtx, req)
 | 
							return s.getAccountVaultDeposit(sdkCtx, req)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 2. All accounts, specific vault
 | 
						// 2. All accounts, specific vault
 | 
				
			||||||
	if req.Owner == "" && req.Denom != "" {
 | 
						if req.Depositor == "" && req.Denom != "" {
 | 
				
			||||||
		return s.getVaultAllDeposits(sdkCtx, req)
 | 
							return s.getVaultAllDeposits(sdkCtx, req)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 3. Specific account, all vaults
 | 
						// 3. Specific account, all vaults
 | 
				
			||||||
	if req.Owner != "" && req.Denom == "" {
 | 
						if req.Depositor != "" && req.Denom == "" {
 | 
				
			||||||
		return s.getAccountAllDeposits(sdkCtx, req)
 | 
							return s.getAccountAllDeposits(sdkCtx, req)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -131,12 +177,12 @@ func (s queryServer) getAccountVaultDeposit(
 | 
				
			|||||||
	ctx sdk.Context,
 | 
						ctx sdk.Context,
 | 
				
			||||||
	req *types.QueryDepositsRequest,
 | 
						req *types.QueryDepositsRequest,
 | 
				
			||||||
) (*types.QueryDepositsResponse, error) {
 | 
					) (*types.QueryDepositsResponse, error) {
 | 
				
			||||||
	owner, err := sdk.AccAddressFromBech32(req.Owner)
 | 
						depositor, err := sdk.AccAddressFromBech32(req.Depositor)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, status.Error(codes.InvalidArgument, "Invalid address")
 | 
							return nil, status.Error(codes.InvalidArgument, "Invalid address")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	shareRecord, found := s.keeper.GetVaultShareRecord(ctx, owner)
 | 
						shareRecord, found := s.keeper.GetVaultShareRecord(ctx, depositor)
 | 
				
			||||||
	if !found {
 | 
						if !found {
 | 
				
			||||||
		return nil, status.Error(codes.NotFound, "No deposit found for owner")
 | 
							return nil, status.Error(codes.NotFound, "No deposit found for owner")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -145,7 +191,7 @@ func (s queryServer) getAccountVaultDeposit(
 | 
				
			|||||||
		return nil, status.Error(codes.NotFound, fmt.Sprintf("No deposit for denom %s found for owner", req.Denom))
 | 
							return nil, status.Error(codes.NotFound, fmt.Sprintf("No deposit for denom %s found for owner", req.Denom))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	value, err := getAccountValue(ctx, s.keeper, owner, shareRecord.Shares)
 | 
						value, err := getAccountValue(ctx, s.keeper, depositor, shareRecord.Shares)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, status.Error(codes.InvalidArgument, err.Error())
 | 
							return nil, status.Error(codes.InvalidArgument, err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -153,7 +199,7 @@ func (s queryServer) getAccountVaultDeposit(
 | 
				
			|||||||
	return &types.QueryDepositsResponse{
 | 
						return &types.QueryDepositsResponse{
 | 
				
			||||||
		Deposits: []types.DepositResponse{
 | 
							Deposits: []types.DepositResponse{
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Depositor: owner.String(),
 | 
									Depositor: depositor.String(),
 | 
				
			||||||
				Shares:    shareRecord.Shares,
 | 
									Shares:    shareRecord.Shares,
 | 
				
			||||||
				Value:     value,
 | 
									Value:     value,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@ -225,25 +271,25 @@ func (s queryServer) getAccountAllDeposits(
 | 
				
			|||||||
	ctx sdk.Context,
 | 
						ctx sdk.Context,
 | 
				
			||||||
	req *types.QueryDepositsRequest,
 | 
						req *types.QueryDepositsRequest,
 | 
				
			||||||
) (*types.QueryDepositsResponse, error) {
 | 
					) (*types.QueryDepositsResponse, error) {
 | 
				
			||||||
	owner, err := sdk.AccAddressFromBech32(req.Owner)
 | 
						depositor, err := sdk.AccAddressFromBech32(req.Depositor)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, status.Error(codes.InvalidArgument, "Invalid address")
 | 
							return nil, status.Error(codes.InvalidArgument, "Invalid address")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	deposits := []types.DepositResponse{}
 | 
						deposits := []types.DepositResponse{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	accountShare, found := s.keeper.GetVaultShareRecord(ctx, owner)
 | 
						accountShare, found := s.keeper.GetVaultShareRecord(ctx, depositor)
 | 
				
			||||||
	if !found {
 | 
						if !found {
 | 
				
			||||||
		return nil, status.Error(codes.NotFound, "No deposit found for owner")
 | 
							return nil, status.Error(codes.NotFound, "No deposit found for depositor")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	value, err := getAccountValue(ctx, s.keeper, owner, accountShare.Shares)
 | 
						value, err := getAccountValue(ctx, s.keeper, depositor, accountShare.Shares)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, status.Error(codes.InvalidArgument, err.Error())
 | 
							return nil, status.Error(codes.InvalidArgument, err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	deposits = append(deposits, types.DepositResponse{
 | 
						deposits = append(deposits, types.DepositResponse{
 | 
				
			||||||
		Depositor: owner.String(),
 | 
							Depositor: depositor.String(),
 | 
				
			||||||
		Shares:    accountShare.Shares,
 | 
							Shares:    accountShare.Shares,
 | 
				
			||||||
		Value:     value,
 | 
							Value:     value,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
				
			|||||||
@ -63,9 +63,8 @@ func (suite *grpcQueryTestSuite) TestVaults_ZeroSupply() {
 | 
				
			|||||||
	suite.CreateVault("busd", types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
						suite.CreateVault("busd", types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Run("single", func() {
 | 
						suite.Run("single", func() {
 | 
				
			||||||
		res, err := suite.queryClient.Vaults(context.Background(), types.NewQueryVaultsRequest("usdx"))
 | 
							res, err := suite.queryClient.Vault(context.Background(), types.NewQueryVaultRequest("usdx"))
 | 
				
			||||||
		suite.Require().NoError(err)
 | 
							suite.Require().NoError(err)
 | 
				
			||||||
		suite.Require().Len(res.Vaults, 1)
 | 
					 | 
				
			||||||
		suite.Require().Equal(
 | 
							suite.Require().Equal(
 | 
				
			||||||
			types.VaultResponse{
 | 
								types.VaultResponse{
 | 
				
			||||||
				Denom:             "usdx",
 | 
									Denom:             "usdx",
 | 
				
			||||||
@ -75,69 +74,66 @@ func (suite *grpcQueryTestSuite) TestVaults_ZeroSupply() {
 | 
				
			|||||||
				TotalShares:       sdk.NewDec(0).String(),
 | 
									TotalShares:       sdk.NewDec(0).String(),
 | 
				
			||||||
				TotalValue:        sdk.NewInt(0),
 | 
									TotalValue:        sdk.NewInt(0),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			res.Vaults[0],
 | 
								res.Vault,
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Run("all", func() {
 | 
						suite.Run("all", func() {
 | 
				
			||||||
		res, err := suite.queryClient.Vaults(context.Background(), types.NewQueryVaultsRequest(""))
 | 
							res, err := suite.queryClient.Vaults(context.Background(), types.NewQueryVaultsRequest())
 | 
				
			||||||
		suite.Require().NoError(err)
 | 
							suite.Require().NoError(err)
 | 
				
			||||||
		suite.Require().Len(res.Vaults, 2)
 | 
							suite.Require().Empty(res.Vaults)
 | 
				
			||||||
		suite.Require().ElementsMatch(
 | 
					 | 
				
			||||||
			[]types.VaultResponse{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Denom:             "usdx",
 | 
					 | 
				
			||||||
					Strategies:        []types.StrategyType{types.STRATEGY_TYPE_HARD},
 | 
					 | 
				
			||||||
					IsPrivateVault:    false,
 | 
					 | 
				
			||||||
					AllowedDepositors: nil,
 | 
					 | 
				
			||||||
					TotalShares:       sdk.NewDec(0).String(),
 | 
					 | 
				
			||||||
					TotalValue:        sdk.NewInt(0),
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Denom:             "busd",
 | 
					 | 
				
			||||||
					Strategies:        []types.StrategyType{types.STRATEGY_TYPE_HARD},
 | 
					 | 
				
			||||||
					IsPrivateVault:    false,
 | 
					 | 
				
			||||||
					AllowedDepositors: nil,
 | 
					 | 
				
			||||||
					TotalShares:       sdk.NewDec(0).String(),
 | 
					 | 
				
			||||||
					TotalValue:        sdk.NewInt(0),
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			res.Vaults,
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (suite *grpcQueryTestSuite) TestVaults_WithSupply() {
 | 
					func (suite *grpcQueryTestSuite) TestVaults_WithSupply() {
 | 
				
			||||||
	vaultDenom := "usdx"
 | 
						vaultDenom := "usdx"
 | 
				
			||||||
 | 
						vault2Denom := "bkava-kavavaloper16xyempempp92x9hyzz9wrgf94r6j9h5f2w4n2l"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
					 | 
				
			||||||
	depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
						depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
				
			||||||
 | 
						deposit2Amount := sdk.NewInt64Coin(vault2Denom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
						suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
 | 
						suite.CreateVault("bkava", types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
						acc := suite.CreateAccount(sdk.NewCoins(
 | 
				
			||||||
 | 
							sdk.NewInt64Coin(vaultDenom, 1000),
 | 
				
			||||||
 | 
							sdk.NewInt64Coin(vault2Denom, 1000),
 | 
				
			||||||
 | 
						), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
	suite.Require().NoError(err)
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res, err := suite.queryClient.Vaults(context.Background(), types.NewQueryVaultsRequest("usdx"))
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), deposit2Amount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
	suite.Require().NoError(err)
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
	suite.Require().Len(res.Vaults, 1)
 | 
					
 | 
				
			||||||
	suite.Require().Equal(
 | 
						res, err := suite.queryClient.Vaults(context.Background(), types.NewQueryVaultsRequest())
 | 
				
			||||||
		types.VaultResponse{
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
			Denom:             "usdx",
 | 
						suite.Require().Len(res.Vaults, 2)
 | 
				
			||||||
			Strategies:        []types.StrategyType{types.STRATEGY_TYPE_HARD},
 | 
						suite.Require().ElementsMatch(
 | 
				
			||||||
			IsPrivateVault:    false,
 | 
							[]types.VaultResponse{
 | 
				
			||||||
			AllowedDepositors: nil,
 | 
								{
 | 
				
			||||||
			TotalShares:       depositAmount.Amount.ToDec().String(),
 | 
									Denom:             vaultDenom,
 | 
				
			||||||
			TotalValue:        depositAmount.Amount,
 | 
									Strategies:        []types.StrategyType{types.STRATEGY_TYPE_HARD},
 | 
				
			||||||
 | 
									IsPrivateVault:    false,
 | 
				
			||||||
 | 
									AllowedDepositors: nil,
 | 
				
			||||||
 | 
									TotalShares:       depositAmount.Amount.ToDec().String(),
 | 
				
			||||||
 | 
									TotalValue:        depositAmount.Amount,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Denom:             vault2Denom,
 | 
				
			||||||
 | 
									Strategies:        []types.StrategyType{types.STRATEGY_TYPE_SAVINGS},
 | 
				
			||||||
 | 
									IsPrivateVault:    false,
 | 
				
			||||||
 | 
									AllowedDepositors: nil,
 | 
				
			||||||
 | 
									TotalShares:       deposit2Amount.Amount.ToDec().String(),
 | 
				
			||||||
 | 
									TotalValue:        deposit2Amount.Amount,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		res.Vaults[0],
 | 
							res.Vaults,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (suite *grpcQueryTestSuite) TestVaults_NotFound() {
 | 
					func (suite *grpcQueryTestSuite) TestVault_NotFound() {
 | 
				
			||||||
	_, err := suite.queryClient.Vaults(context.Background(), types.NewQueryVaultsRequest("usdx"))
 | 
						_, err := suite.queryClient.Vault(context.Background(), types.NewQueryVaultRequest("usdx"))
 | 
				
			||||||
	suite.Require().Error(err)
 | 
						suite.Require().Error(err)
 | 
				
			||||||
	suite.Require().ErrorIs(err, status.Errorf(codes.NotFound, "vault not found with specified denom"))
 | 
						suite.Require().ErrorIs(err, status.Errorf(codes.NotFound, "vault not found with specified denom"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -145,12 +141,12 @@ func (suite *grpcQueryTestSuite) TestVaults_NotFound() {
 | 
				
			|||||||
func (suite *grpcQueryTestSuite) TestDeposits() {
 | 
					func (suite *grpcQueryTestSuite) TestDeposits() {
 | 
				
			||||||
	vault1Denom := "usdx"
 | 
						vault1Denom := "usdx"
 | 
				
			||||||
	vault2Denom := "busd"
 | 
						vault2Denom := "busd"
 | 
				
			||||||
	vault3Denom := "kava"
 | 
						vault3Denom := "bkava-kavavaloper16xyempempp92x9hyzz9wrgf94r6j9h5f2w4n2l"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Add vaults
 | 
						// Add vaults
 | 
				
			||||||
	suite.CreateVault(vault1Denom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
						suite.CreateVault(vault1Denom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
	suite.CreateVault(vault2Denom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
						suite.CreateVault(vault2Denom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
	suite.CreateVault(vault3Denom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
						suite.CreateVault("bkava", types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	startBalance := sdk.NewCoins(
 | 
						startBalance := sdk.NewCoins(
 | 
				
			||||||
		sdk.NewInt64Coin(vault1Denom, 1000),
 | 
							sdk.NewInt64Coin(vault1Denom, 1000),
 | 
				
			||||||
@ -175,7 +171,7 @@ func (suite *grpcQueryTestSuite) TestDeposits() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	err = suite.Keeper.Deposit(suite.Ctx, acc2, deposit1Amount, types.STRATEGY_TYPE_HARD)
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc2, deposit1Amount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
	suite.Require().NoError(err)
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
	err = suite.Keeper.Deposit(suite.Ctx, acc2, deposit3Amount, types.STRATEGY_TYPE_HARD)
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc2, deposit3Amount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
	suite.Require().NoError(err)
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Run("1) 1 vault for 1 account", func() {
 | 
						suite.Run("1) 1 vault for 1 account", func() {
 | 
				
			||||||
@ -317,3 +313,46 @@ func (suite *grpcQueryTestSuite) TestDeposits_InvalidAddress() {
 | 
				
			|||||||
	suite.Require().Error(err)
 | 
						suite.Require().Error(err)
 | 
				
			||||||
	suite.Require().ErrorIs(err, status.Error(codes.InvalidArgument, "Invalid address"))
 | 
						suite.Require().ErrorIs(err, status.Error(codes.InvalidArgument, "Invalid address"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *grpcQueryTestSuite) TestVault_bKava() {
 | 
				
			||||||
 | 
						vaultDenom := "bkava"
 | 
				
			||||||
 | 
						coinDenom := vaultDenom + "-kavavaloper16xyempempp92x9hyzz9wrgf94r6j9h5f2w4n2l"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(coinDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(coinDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// vault denom is only "bkava" which has it's own special handler
 | 
				
			||||||
 | 
						suite.CreateVault(
 | 
				
			||||||
 | 
							vaultDenom,
 | 
				
			||||||
 | 
							types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS},
 | 
				
			||||||
 | 
							false,
 | 
				
			||||||
 | 
							[]sdk.AccAddress{},
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(
 | 
				
			||||||
 | 
							err,
 | 
				
			||||||
 | 
							"should be able to deposit bkava derivative denom in bkava vault",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res, err := suite.queryClient.Vault(
 | 
				
			||||||
 | 
							context.Background(),
 | 
				
			||||||
 | 
							types.NewQueryVaultRequest(coinDenom),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
						suite.Require().Equal(
 | 
				
			||||||
 | 
							types.VaultResponse{
 | 
				
			||||||
 | 
								Denom: coinDenom,
 | 
				
			||||||
 | 
								Strategies: types.StrategyTypes{
 | 
				
			||||||
 | 
									types.STRATEGY_TYPE_SAVINGS,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								IsPrivateVault:    false,
 | 
				
			||||||
 | 
								AllowedDepositors: []string(nil),
 | 
				
			||||||
 | 
								TotalShares:       "100.000000000000000000",
 | 
				
			||||||
 | 
								TotalValue:        sdk.NewInt(100),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							res.Vault,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										34
									
								
								x/earn/keeper/hooks.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								x/earn/keeper/hooks.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					package keeper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/types"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Implements EarnHooks interface
 | 
				
			||||||
 | 
					var _ types.EarnHooks = Keeper{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AfterVaultDepositCreated - call hook if registered
 | 
				
			||||||
 | 
					func (k Keeper) AfterVaultDepositCreated(
 | 
				
			||||||
 | 
						ctx sdk.Context,
 | 
				
			||||||
 | 
						vaultDenom string,
 | 
				
			||||||
 | 
						depositor sdk.AccAddress,
 | 
				
			||||||
 | 
						sharesOwned sdk.Dec,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
						if k.hooks != nil {
 | 
				
			||||||
 | 
							k.hooks.AfterVaultDepositCreated(ctx, vaultDenom, depositor, sharesOwned)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BeforeVaultDepositModified - call hook if registered
 | 
				
			||||||
 | 
					func (k Keeper) BeforeVaultDepositModified(
 | 
				
			||||||
 | 
						ctx sdk.Context,
 | 
				
			||||||
 | 
						vaultDenom string,
 | 
				
			||||||
 | 
						depositor sdk.AccAddress,
 | 
				
			||||||
 | 
						sharesOwned sdk.Dec,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
						if k.hooks != nil {
 | 
				
			||||||
 | 
							k.hooks.BeforeVaultDepositModified(ctx, vaultDenom, depositor, sharesOwned)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										322
									
								
								x/earn/keeper/hooks_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								x/earn/keeper/hooks_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,322 @@
 | 
				
			|||||||
 | 
					package keeper_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/testutil"
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/types"
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/types/mocks"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/mock"
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/suite"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type hookTestSuite struct {
 | 
				
			||||||
 | 
						testutil.Suite
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *hookTestSuite) SetupTest() {
 | 
				
			||||||
 | 
						suite.Suite.SetupTest()
 | 
				
			||||||
 | 
						suite.Keeper.SetParams(suite.Ctx, types.DefaultParams())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestHookTestSuite(t *testing.T) {
 | 
				
			||||||
 | 
						suite.Run(t, new(hookTestSuite))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
 | 
				
			||||||
 | 
						suite.Keeper.ClearHooks()
 | 
				
			||||||
 | 
						earnHooks := &mocks.EarnHooks{}
 | 
				
			||||||
 | 
						suite.Keeper.SetHooks(earnHooks)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vault1Denom := "usdx"
 | 
				
			||||||
 | 
						vault2Denom := "ukava"
 | 
				
			||||||
 | 
						deposit1Amount := sdk.NewInt64Coin(vault1Denom, 100)
 | 
				
			||||||
 | 
						deposit2Amount := sdk.NewInt64Coin(vault2Denom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(vault1Denom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
 | 
						suite.CreateVault(vault2Denom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc := suite.CreateAccount(sdk.NewCoins(
 | 
				
			||||||
 | 
							sdk.NewInt64Coin(vault1Denom, 1000),
 | 
				
			||||||
 | 
							sdk.NewInt64Coin(vault2Denom, 1000),
 | 
				
			||||||
 | 
						), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// first deposit creates vault - calls AfterVaultDepositCreated with initial shares
 | 
				
			||||||
 | 
						// shares are 1:1
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"AfterVaultDepositCreated",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit1Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit1Amount.Amount.ToDec(),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit1Amount,
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_HARD,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// second deposit adds to vault - calls BeforeVaultDepositModified
 | 
				
			||||||
 | 
						// shares given are the initial shares, not new the shares added to the vault
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"BeforeVaultDepositModified",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit1Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit1Amount.Amount.ToDec(),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit1Amount,
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_HARD,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get the shares from the store from the last deposit
 | 
				
			||||||
 | 
						shareRecord, found := suite.Keeper.GetVaultAccountShares(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// third deposit adds to vault - calls BeforeVaultDepositModified
 | 
				
			||||||
 | 
						// shares given are the shares added in previous deposit, not the shares added to the vault now
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"BeforeVaultDepositModified",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit1Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							shareRecord.AmountOf(deposit1Amount.Denom),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit1Amount,
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_HARD,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// new deposit denom into vault creates the deposit and calls AfterVaultDepositCreated
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"AfterVaultDepositCreated",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit2Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit2Amount.Amount.ToDec(),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit2Amount,
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_SAVINGS,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// second deposit into vault calls BeforeVaultDepositModified with initial shares given
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"BeforeVaultDepositModified",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit2Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit2Amount.Amount.ToDec(),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit2Amount,
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_SAVINGS,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get the shares from the store from the last deposit
 | 
				
			||||||
 | 
						shareRecord, found = suite.Keeper.GetVaultAccountShares(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// third deposit into vault calls BeforeVaultDepositModified with shares from last deposit
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"BeforeVaultDepositModified",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit2Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							shareRecord.AmountOf(deposit2Amount.Denom),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit2Amount,
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_SAVINGS,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ------------------------------------------------------------
 | 
				
			||||||
 | 
						// test hooks with a full withdraw of all shares deposit 1 denom
 | 
				
			||||||
 | 
						shareRecord, found = suite.Keeper.GetVaultAccountShares(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// all shares given to BeforeVaultDepositModified
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"BeforeVaultDepositModified",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit1Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							shareRecord.AmountOf(deposit1Amount.Denom),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							// 3 deposits, multiply original deposit amount by 3
 | 
				
			||||||
 | 
							sdk.NewCoin(deposit1Amount.Denom, deposit1Amount.Amount.MulRaw(3)),
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_HARD,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// test hooks on partial withdraw
 | 
				
			||||||
 | 
						shareRecord, found = suite.Keeper.GetVaultAccountShares(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// all shares given to before deposit modified even with partial withdraw
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"BeforeVaultDepositModified",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit2Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							shareRecord.AmountOf(deposit2Amount.Denom),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit2Amount,
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_SAVINGS,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// test hooks on second partial withdraw
 | 
				
			||||||
 | 
						shareRecord, found = suite.Keeper.GetVaultAccountShares(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// all shares given to before deposit modified even with partial withdraw
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"BeforeVaultDepositModified",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit2Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							shareRecord.AmountOf(deposit2Amount.Denom),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit2Amount,
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_SAVINGS,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// test hooks withdraw all remaining shares
 | 
				
			||||||
 | 
						shareRecord, found = suite.Keeper.GetVaultAccountShares(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// all shares given to before deposit modified even with partial withdraw
 | 
				
			||||||
 | 
						earnHooks.On(
 | 
				
			||||||
 | 
							"BeforeVaultDepositModified",
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							deposit2Amount.Denom,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							shareRecord.AmountOf(deposit2Amount.Denom),
 | 
				
			||||||
 | 
						).Once()
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(
 | 
				
			||||||
 | 
							suite.Ctx,
 | 
				
			||||||
 | 
							acc.GetAddress(),
 | 
				
			||||||
 | 
							deposit2Amount,
 | 
				
			||||||
 | 
							types.STRATEGY_TYPE_SAVINGS,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						earnHooks.AssertExpectations(suite.T())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *hookTestSuite) TestHooks_NoPanicsOnNilHooks() {
 | 
				
			||||||
 | 
						suite.Keeper.ClearHooks()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vaultDenom := "usdx"
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
				
			||||||
 | 
						withdrawAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// AfterVaultDepositModified should not panic if no hooks are registered
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// BeforeVaultDepositModified should not panic if no hooks are registered
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// BeforeVaultDepositModified should not panic if no hooks are registered
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *hookTestSuite) TestHooks_HookOrdering() {
 | 
				
			||||||
 | 
						suite.Keeper.ClearHooks()
 | 
				
			||||||
 | 
						earnHooks := &mocks.EarnHooks{}
 | 
				
			||||||
 | 
						suite.Keeper.SetHooks(earnHooks)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vaultDenom := "usdx"
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						earnHooks.On("AfterVaultDepositCreated", suite.Ctx, depositAmount.Denom, acc.GetAddress(), depositAmount.Amount.ToDec()).
 | 
				
			||||||
 | 
							Run(func(args mock.Arguments) {
 | 
				
			||||||
 | 
								shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc.GetAddress())
 | 
				
			||||||
 | 
								suite.Require().True(found, "expected after hook to be called after shares are updated")
 | 
				
			||||||
 | 
								suite.Require().Equal(depositAmount.Amount.ToDec(), shares.AmountOf(depositAmount.Denom))
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						earnHooks.On("BeforeVaultDepositModified", suite.Ctx, depositAmount.Denom, acc.GetAddress(), depositAmount.Amount.ToDec()).
 | 
				
			||||||
 | 
							Run(func(args mock.Arguments) {
 | 
				
			||||||
 | 
								shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc.GetAddress())
 | 
				
			||||||
 | 
								suite.Require().True(found, "expected after hook to be called after shares are updated")
 | 
				
			||||||
 | 
								suite.Require().Equal(depositAmount.Amount.ToDec(), shares.AmountOf(depositAmount.Denom))
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						existingShares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc.GetAddress())
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
						earnHooks.On("BeforeVaultDepositModified", suite.Ctx, depositAmount.Denom, acc.GetAddress(), existingShares.AmountOf(depositAmount.Denom)).
 | 
				
			||||||
 | 
							Run(func(args mock.Arguments) {
 | 
				
			||||||
 | 
								shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc.GetAddress())
 | 
				
			||||||
 | 
								suite.Require().True(found, "expected after hook to be called after shares are updated")
 | 
				
			||||||
 | 
								suite.Require().Equal(depositAmount.Amount.MulRaw(2).ToDec(), shares.AmountOf(depositAmount.Denom))
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,9 +1,115 @@
 | 
				
			|||||||
package keeper
 | 
					package keeper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RegisterInvariants registers the earn module invariants
 | 
					// RegisterInvariants registers the swap module invariants
 | 
				
			||||||
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
 | 
					func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
 | 
				
			||||||
 | 
						ir.RegisterRoute(types.ModuleName, "vault-records", VaultRecordsInvariant(k))
 | 
				
			||||||
 | 
						ir.RegisterRoute(types.ModuleName, "share-records", ShareRecordsInvariant(k))
 | 
				
			||||||
 | 
						ir.RegisterRoute(types.ModuleName, "vault-shares", VaultSharesInvariant(k))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AllInvariants runs all invariants of the swap module
 | 
				
			||||||
 | 
					func AllInvariants(k Keeper) sdk.Invariant {
 | 
				
			||||||
 | 
						return func(ctx sdk.Context) (string, bool) {
 | 
				
			||||||
 | 
							if res, stop := VaultRecordsInvariant(k)(ctx); stop {
 | 
				
			||||||
 | 
								return res, stop
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if res, stop := ShareRecordsInvariant(k)(ctx); stop {
 | 
				
			||||||
 | 
								return res, stop
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							res, stop := VaultSharesInvariant(k)(ctx)
 | 
				
			||||||
 | 
							return res, stop
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VaultRecordsInvariant iterates all vault records and asserts that they are valid
 | 
				
			||||||
 | 
					func VaultRecordsInvariant(k Keeper) sdk.Invariant {
 | 
				
			||||||
 | 
						broken := false
 | 
				
			||||||
 | 
						message := sdk.FormatInvariant(types.ModuleName, "validate vault records broken", "vault record invalid")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return func(ctx sdk.Context) (string, bool) {
 | 
				
			||||||
 | 
							k.IterateVaultRecords(ctx, func(record types.VaultRecord) bool {
 | 
				
			||||||
 | 
								if err := record.Validate(); err != nil {
 | 
				
			||||||
 | 
									broken = true
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return message, broken
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ShareRecordsInvariant iterates all share records and asserts that they are valid
 | 
				
			||||||
 | 
					func ShareRecordsInvariant(k Keeper) sdk.Invariant {
 | 
				
			||||||
 | 
						broken := false
 | 
				
			||||||
 | 
						message := sdk.FormatInvariant(types.ModuleName, "validate share records broken", "share record invalid")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return func(ctx sdk.Context) (string, bool) {
 | 
				
			||||||
 | 
							k.IterateVaultShareRecords(ctx, func(record types.VaultShareRecord) bool {
 | 
				
			||||||
 | 
								if err := record.Validate(); err != nil {
 | 
				
			||||||
 | 
									broken = true
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return message, broken
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type vaultShares struct {
 | 
				
			||||||
 | 
						totalShares      types.VaultShare
 | 
				
			||||||
 | 
						totalSharesOwned types.VaultShare
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VaultSharesInvariant iterates all vaults and shares and ensures the total vault shares match the sum of depositor shares
 | 
				
			||||||
 | 
					func VaultSharesInvariant(k Keeper) sdk.Invariant {
 | 
				
			||||||
 | 
						broken := false
 | 
				
			||||||
 | 
						message := sdk.FormatInvariant(types.ModuleName, "vault shares broken", "vault shares do not match depositor shares")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return func(ctx sdk.Context) (string, bool) {
 | 
				
			||||||
 | 
							totalShares := make(map[string]vaultShares)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							k.IterateVaultRecords(ctx, func(record types.VaultRecord) bool {
 | 
				
			||||||
 | 
								totalShares[record.TotalShares.Denom] = vaultShares{
 | 
				
			||||||
 | 
									totalShares:      record.TotalShares,
 | 
				
			||||||
 | 
									totalSharesOwned: types.NewVaultShare(record.TotalShares.Denom, sdk.ZeroDec()),
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							k.IterateVaultShareRecords(ctx, func(sr types.VaultShareRecord) bool {
 | 
				
			||||||
 | 
								for _, share := range sr.Shares {
 | 
				
			||||||
 | 
									if shares, found := totalShares[share.Denom]; found {
 | 
				
			||||||
 | 
										shares.totalSharesOwned = shares.totalSharesOwned.Add(share)
 | 
				
			||||||
 | 
										totalShares[share.Denom] = shares
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										totalShares[share.Denom] = vaultShares{
 | 
				
			||||||
 | 
											totalShares:      types.NewVaultShare(share.Denom, sdk.ZeroDec()),
 | 
				
			||||||
 | 
											totalSharesOwned: share,
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, share := range totalShares {
 | 
				
			||||||
 | 
								if !share.totalShares.Amount.Equal(share.totalSharesOwned.Amount) {
 | 
				
			||||||
 | 
									broken = true
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return message, broken
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										182
									
								
								x/earn/keeper/invariants_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								x/earn/keeper/invariants_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,182 @@
 | 
				
			|||||||
 | 
					package keeper_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/app"
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/keeper"
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/testutil"
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/suite"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type invariantTestSuite struct {
 | 
				
			||||||
 | 
						testutil.Suite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						invariants map[string]map[string]sdk.Invariant
 | 
				
			||||||
 | 
						addrs      []sdk.AccAddress
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestInvariantTestSuite(t *testing.T) {
 | 
				
			||||||
 | 
						suite.Run(t, new(invariantTestSuite))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *invariantTestSuite) SetupTest() {
 | 
				
			||||||
 | 
						suite.Suite.SetupTest()
 | 
				
			||||||
 | 
						suite.invariants = make(map[string]map[string]sdk.Invariant)
 | 
				
			||||||
 | 
						keeper.RegisterInvariants(suite, suite.Keeper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, addrs := app.GeneratePrivKeyAddressPairs(4)
 | 
				
			||||||
 | 
						suite.addrs = addrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *invariantTestSuite) SetupValidState() {
 | 
				
			||||||
 | 
						suite.Keeper.SetVaultRecord(suite.Ctx, types.NewVaultRecord(
 | 
				
			||||||
 | 
							"usdx",
 | 
				
			||||||
 | 
							sdk.MustNewDecFromStr("100"),
 | 
				
			||||||
 | 
						))
 | 
				
			||||||
 | 
						suite.Keeper.SetVaultRecord(suite.Ctx, types.NewVaultRecord(
 | 
				
			||||||
 | 
							"ukava",
 | 
				
			||||||
 | 
							sdk.MustNewDecFromStr("250.123456"),
 | 
				
			||||||
 | 
						))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vaultShare1 := types.NewVaultShareRecord(
 | 
				
			||||||
 | 
							suite.addrs[0],
 | 
				
			||||||
 | 
							types.NewVaultShares(
 | 
				
			||||||
 | 
								types.NewVaultShare("usdx", sdk.MustNewDecFromStr("50")),
 | 
				
			||||||
 | 
								types.NewVaultShare("ukava", sdk.MustNewDecFromStr("105.123")),
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						vaultShare2 := types.NewVaultShareRecord(
 | 
				
			||||||
 | 
							suite.addrs[1],
 | 
				
			||||||
 | 
							types.NewVaultShares(
 | 
				
			||||||
 | 
								types.NewVaultShare("usdx", sdk.MustNewDecFromStr("50")),
 | 
				
			||||||
 | 
								types.NewVaultShare("ukava", sdk.MustNewDecFromStr("145.000456")),
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Require().NoError(vaultShare1.Validate())
 | 
				
			||||||
 | 
						suite.Require().NoError(vaultShare2.Validate())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Keeper.SetVaultShareRecord(suite.Ctx, vaultShare1)
 | 
				
			||||||
 | 
						suite.Keeper.SetVaultShareRecord(suite.Ctx, vaultShare2)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *invariantTestSuite) RegisterRoute(moduleName string, route string, invariant sdk.Invariant) {
 | 
				
			||||||
 | 
						_, exists := suite.invariants[moduleName]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !exists {
 | 
				
			||||||
 | 
							suite.invariants[moduleName] = make(map[string]sdk.Invariant)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.invariants[moduleName][route] = invariant
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *invariantTestSuite) runInvariant(route string, invariant func(k keeper.Keeper) sdk.Invariant) (string, bool) {
 | 
				
			||||||
 | 
						ctx := suite.Ctx
 | 
				
			||||||
 | 
						registeredInvariant := suite.invariants[types.ModuleName][route]
 | 
				
			||||||
 | 
						suite.Require().NotNil(registeredInvariant)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// direct call
 | 
				
			||||||
 | 
						dMessage, dBroken := invariant(suite.Keeper)(ctx)
 | 
				
			||||||
 | 
						// registered call
 | 
				
			||||||
 | 
						rMessage, rBroken := registeredInvariant(ctx)
 | 
				
			||||||
 | 
						// all call
 | 
				
			||||||
 | 
						aMessage, aBroken := keeper.AllInvariants(suite.Keeper)(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// require matching values for direct call and registered call
 | 
				
			||||||
 | 
						suite.Require().Equal(dMessage, rMessage, "expected registered invariant message to match")
 | 
				
			||||||
 | 
						suite.Require().Equal(dBroken, rBroken, "expected registered invariant broken to match")
 | 
				
			||||||
 | 
						// require matching values for direct call and all invariants call if broken
 | 
				
			||||||
 | 
						suite.Require().Equalf(dBroken, aBroken, "expected all invariant broken to match, direct %v != all %v", dBroken, aBroken)
 | 
				
			||||||
 | 
						if dBroken {
 | 
				
			||||||
 | 
							suite.Require().Equal(dMessage, aMessage, "expected all invariant message to match")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// return message, broken
 | 
				
			||||||
 | 
						return dMessage, dBroken
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *invariantTestSuite) TestVaultRecordsInvariant() {
 | 
				
			||||||
 | 
						// default state is valid
 | 
				
			||||||
 | 
						message, broken := suite.runInvariant("vault-records", keeper.VaultRecordsInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: validate vault records broken invariant\nvault record invalid\n", message)
 | 
				
			||||||
 | 
						suite.Equal(false, broken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.SetupValidState()
 | 
				
			||||||
 | 
						message, broken = suite.runInvariant("vault-records", keeper.VaultRecordsInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: validate vault records broken invariant\nvault record invalid\n", message)
 | 
				
			||||||
 | 
						suite.Equal(false, broken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// broken with invalid vault record
 | 
				
			||||||
 | 
						suite.Keeper.SetVaultRecord(suite.Ctx, types.VaultRecord{
 | 
				
			||||||
 | 
							TotalShares: types.VaultShare{
 | 
				
			||||||
 | 
								Denom:  "invalid denom",
 | 
				
			||||||
 | 
								Amount: sdk.MustNewDecFromStr("101"),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						message, broken = suite.runInvariant("vault-records", keeper.VaultRecordsInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: validate vault records broken invariant\nvault record invalid\n", message)
 | 
				
			||||||
 | 
						suite.Equal(true, broken)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *invariantTestSuite) TestShareRecordsInvariant() {
 | 
				
			||||||
 | 
						message, broken := suite.runInvariant("share-records", keeper.ShareRecordsInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: validate share records broken invariant\nshare record invalid\n", message)
 | 
				
			||||||
 | 
						suite.Equal(false, broken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.SetupValidState()
 | 
				
			||||||
 | 
						message, broken = suite.runInvariant("share-records", keeper.ShareRecordsInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: validate share records broken invariant\nshare record invalid\n", message)
 | 
				
			||||||
 | 
						suite.Equal(false, broken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// broken with invalid share record
 | 
				
			||||||
 | 
						suite.Keeper.SetVaultShareRecord(suite.Ctx, types.NewVaultShareRecord(
 | 
				
			||||||
 | 
							suite.addrs[0],
 | 
				
			||||||
 | 
							// Directly create vaultshares instead of NewVaultShares() to avoid sanitization
 | 
				
			||||||
 | 
							types.VaultShares{
 | 
				
			||||||
 | 
								types.NewVaultShare("ukava", sdk.MustNewDecFromStr("50")),
 | 
				
			||||||
 | 
								types.NewVaultShare("ukava", sdk.MustNewDecFromStr("105.123")),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						))
 | 
				
			||||||
 | 
						message, broken = suite.runInvariant("share-records", keeper.ShareRecordsInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: validate share records broken invariant\nshare record invalid\n", message)
 | 
				
			||||||
 | 
						suite.Equal(true, broken)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *invariantTestSuite) TestVaultSharesInvariant() {
 | 
				
			||||||
 | 
						message, broken := suite.runInvariant("vault-shares", keeper.VaultSharesInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: vault shares broken invariant\nvault shares do not match depositor shares\n", message)
 | 
				
			||||||
 | 
						suite.Equal(false, broken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.SetupValidState()
 | 
				
			||||||
 | 
						message, broken = suite.runInvariant("vault-shares", keeper.VaultSharesInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: vault shares broken invariant\nvault shares do not match depositor shares\n", message)
 | 
				
			||||||
 | 
						suite.Equal(false, broken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// broken when total shares are greater than depositor shares
 | 
				
			||||||
 | 
						suite.Keeper.SetVaultRecord(suite.Ctx, types.NewVaultRecord(
 | 
				
			||||||
 | 
							"usdx",
 | 
				
			||||||
 | 
							sdk.MustNewDecFromStr("101"),
 | 
				
			||||||
 | 
						))
 | 
				
			||||||
 | 
						message, broken = suite.runInvariant("vault-shares", keeper.VaultSharesInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: vault shares broken invariant\nvault shares do not match depositor shares\n", message)
 | 
				
			||||||
 | 
						suite.Equal(true, broken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// broken when total shares are less than the depositor shares
 | 
				
			||||||
 | 
						suite.Keeper.SetVaultRecord(suite.Ctx, types.NewVaultRecord(
 | 
				
			||||||
 | 
							"usdx",
 | 
				
			||||||
 | 
							sdk.MustNewDecFromStr("99.999"),
 | 
				
			||||||
 | 
						))
 | 
				
			||||||
 | 
						message, broken = suite.runInvariant("vault-shares", keeper.VaultSharesInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: vault shares broken invariant\nvault shares do not match depositor shares\n", message)
 | 
				
			||||||
 | 
						suite.Equal(true, broken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// broken when vault record is missing
 | 
				
			||||||
 | 
						suite.Keeper.DeleteVaultRecord(suite.Ctx, "usdx")
 | 
				
			||||||
 | 
						message, broken = suite.runInvariant("vault-shares", keeper.VaultSharesInvariant)
 | 
				
			||||||
 | 
						suite.Equal("earn: vault shares broken invariant\nvault shares do not match depositor shares\n", message)
 | 
				
			||||||
 | 
						suite.Equal(true, broken)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -13,6 +13,7 @@ type Keeper struct {
 | 
				
			|||||||
	key           sdk.StoreKey
 | 
						key           sdk.StoreKey
 | 
				
			||||||
	cdc           codec.Codec
 | 
						cdc           codec.Codec
 | 
				
			||||||
	paramSubspace paramtypes.Subspace
 | 
						paramSubspace paramtypes.Subspace
 | 
				
			||||||
 | 
						hooks         types.EarnHooks
 | 
				
			||||||
	accountKeeper types.AccountKeeper
 | 
						accountKeeper types.AccountKeeper
 | 
				
			||||||
	bankKeeper    types.BankKeeper
 | 
						bankKeeper    types.BankKeeper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -45,3 +46,17 @@ func NewKeeper(
 | 
				
			|||||||
		savingsKeeper: savingsKeeper,
 | 
							savingsKeeper: savingsKeeper,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetHooks adds hooks to the keeper.
 | 
				
			||||||
 | 
					func (k *Keeper) SetHooks(sh types.EarnHooks) *Keeper {
 | 
				
			||||||
 | 
						if k.hooks != nil {
 | 
				
			||||||
 | 
							panic("cannot set earn hooks twice")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						k.hooks = sh
 | 
				
			||||||
 | 
						return k
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ClearHooks clears the hooks on the keeper
 | 
				
			||||||
 | 
					func (k *Keeper) ClearHooks() {
 | 
				
			||||||
 | 
						k.hooks = nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,18 @@
 | 
				
			|||||||
package keeper
 | 
					package keeper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/kava-labs/kava/x/earn/types"
 | 
						"github.com/kava-labs/kava/x/earn/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						bkavaDenom  = "bkava"
 | 
				
			||||||
 | 
						bkavaPrefix = bkavaDenom + "-"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetParams returns the params from the store
 | 
					// GetParams returns the params from the store
 | 
				
			||||||
func (k Keeper) GetParams(ctx sdk.Context) types.Params {
 | 
					func (k Keeper) GetParams(ctx sdk.Context) types.Params {
 | 
				
			||||||
	var p types.Params
 | 
						var p types.Params
 | 
				
			||||||
@ -24,9 +31,12 @@ func (k Keeper) GetAllowedVaults(ctx sdk.Context) types.AllowedVaults {
 | 
				
			|||||||
	return k.GetParams(ctx).AllowedVaults
 | 
						return k.GetParams(ctx).AllowedVaults
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetAllowedVault returns a single vault from the module params specified by
 | 
					// getAllowedVaultRaw returns a single vault from the module params specified
 | 
				
			||||||
// the denom.
 | 
					// by the denom.
 | 
				
			||||||
func (k Keeper) GetAllowedVault(ctx sdk.Context, vaultDenom string) (types.AllowedVault, bool) {
 | 
					func (k Keeper) getAllowedVaultRaw(
 | 
				
			||||||
 | 
						ctx sdk.Context,
 | 
				
			||||||
 | 
						vaultDenom string,
 | 
				
			||||||
 | 
					) (types.AllowedVault, bool) {
 | 
				
			||||||
	for _, allowedVault := range k.GetAllowedVaults(ctx) {
 | 
						for _, allowedVault := range k.GetAllowedVaults(ctx) {
 | 
				
			||||||
		if allowedVault.Denom == vaultDenom {
 | 
							if allowedVault.Denom == vaultDenom {
 | 
				
			||||||
			return allowedVault, true
 | 
								return allowedVault, true
 | 
				
			||||||
@ -35,3 +45,18 @@ func (k Keeper) GetAllowedVault(ctx sdk.Context, vaultDenom string) (types.Allow
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return types.AllowedVault{}, false
 | 
						return types.AllowedVault{}, false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetAllowedVault returns the AllowedVault that corresponds to the
 | 
				
			||||||
 | 
					// given denom. If the denom starts with "bkava-" where it will return the
 | 
				
			||||||
 | 
					// "bkava" AllowedVault. Otherwise, it will return the exact match for the
 | 
				
			||||||
 | 
					// corresponding AllowedVault denom.
 | 
				
			||||||
 | 
					func (k *Keeper) GetAllowedVault(
 | 
				
			||||||
 | 
						ctx sdk.Context,
 | 
				
			||||||
 | 
						vaultDenom string,
 | 
				
			||||||
 | 
					) (types.AllowedVault, bool) {
 | 
				
			||||||
 | 
						if strings.HasPrefix(vaultDenom, bkavaPrefix) {
 | 
				
			||||||
 | 
							return k.getAllowedVaultRaw(ctx, bkavaDenom)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return k.getAllowedVaultRaw(ctx, vaultDenom)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -12,20 +12,18 @@ type Strategy interface {
 | 
				
			|||||||
	// GetStrategyType returns the strategy type
 | 
						// GetStrategyType returns the strategy type
 | 
				
			||||||
	GetStrategyType() types.StrategyType
 | 
						GetStrategyType() types.StrategyType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// GetEstimatedTotalAssets returns the estimated total assets denominated in
 | 
						// GetEstimatedTotalAssets returns the estimated total assets of the
 | 
				
			||||||
	// GetDenom() of this strategy. This is the value if the strategy were to
 | 
						// strategy with the specified denom. This is the value if the strategy were
 | 
				
			||||||
	// liquidate all assets.
 | 
						// to liquidate all assets.
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	// **Note:** This may not reflect the true value as it may become outdated
 | 
						// **Note:** This may not reflect the true value as it may become outdated
 | 
				
			||||||
	// from market changes.
 | 
						// from market changes.
 | 
				
			||||||
	GetEstimatedTotalAssets(ctx sdk.Context, denom string) (sdk.Coin, error)
 | 
						GetEstimatedTotalAssets(ctx sdk.Context, denom string) (sdk.Coin, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Deposit the specified amount of coins into this strategy. The amount
 | 
						// Deposit the specified amount of coins into this strategy.
 | 
				
			||||||
	// must be denominated in GetDenom().
 | 
					 | 
				
			||||||
	Deposit(ctx sdk.Context, amount sdk.Coin) error
 | 
						Deposit(ctx sdk.Context, amount sdk.Coin) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Withdraw the specified amount of coins from this strategy. The amount
 | 
						// Withdraw the specified amount of coins from this strategy.
 | 
				
			||||||
	// must be denominated in GetDenom().
 | 
					 | 
				
			||||||
	Withdraw(ctx sdk.Context, amount sdk.Coin) error
 | 
						Withdraw(ctx sdk.Context, amount sdk.Coin) error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -35,7 +33,7 @@ func (k *Keeper) GetStrategy(strategyType types.StrategyType) (Strategy, error)
 | 
				
			|||||||
	case types.STRATEGY_TYPE_HARD:
 | 
						case types.STRATEGY_TYPE_HARD:
 | 
				
			||||||
		return (*HardStrategy)(k), nil
 | 
							return (*HardStrategy)(k), nil
 | 
				
			||||||
	case types.STRATEGY_TYPE_SAVINGS:
 | 
						case types.STRATEGY_TYPE_SAVINGS:
 | 
				
			||||||
		panic("unimplemented")
 | 
							return (*SavingsStrategy)(k), nil
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return nil, fmt.Errorf("unknown strategy type: %s", strategyType)
 | 
							return nil, fmt.Errorf("unknown strategy type: %s", strategyType)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -10,14 +10,13 @@ type HardStrategy Keeper
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var _ Strategy = (*HardStrategy)(nil)
 | 
					var _ Strategy = (*HardStrategy)(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetStrategyType returns the strategy type
 | 
				
			||||||
func (s *HardStrategy) GetStrategyType() types.StrategyType {
 | 
					func (s *HardStrategy) GetStrategyType() types.StrategyType {
 | 
				
			||||||
	return types.STRATEGY_TYPE_HARD
 | 
						return types.STRATEGY_TYPE_HARD
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *HardStrategy) IsDenomSupported(denom string) bool {
 | 
					// GetEstimatedTotalAssets returns the current value of all assets deposited
 | 
				
			||||||
	return denom == "usdx"
 | 
					// in hard.
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *HardStrategy) GetEstimatedTotalAssets(ctx sdk.Context, denom string) (sdk.Coin, error) {
 | 
					func (s *HardStrategy) GetEstimatedTotalAssets(ctx sdk.Context, denom string) (sdk.Coin, error) {
 | 
				
			||||||
	macc := s.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
 | 
						macc := s.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
 | 
				
			||||||
	deposit, found := s.hardKeeper.GetSyncedDeposit(ctx, macc.GetAddress())
 | 
						deposit, found := s.hardKeeper.GetSyncedDeposit(ctx, macc.GetAddress())
 | 
				
			||||||
@ -37,11 +36,13 @@ func (s *HardStrategy) GetEstimatedTotalAssets(ctx sdk.Context, denom string) (s
 | 
				
			|||||||
	return sdk.NewCoin(denom, sdk.ZeroInt()), nil
 | 
						return sdk.NewCoin(denom, sdk.ZeroInt()), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deposit deposits the specified amount of coins into hard.
 | 
				
			||||||
func (s *HardStrategy) Deposit(ctx sdk.Context, amount sdk.Coin) error {
 | 
					func (s *HardStrategy) Deposit(ctx sdk.Context, amount sdk.Coin) error {
 | 
				
			||||||
	macc := s.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
 | 
						macc := s.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
 | 
				
			||||||
	return s.hardKeeper.Deposit(ctx, macc.GetAddress(), sdk.NewCoins(amount))
 | 
						return s.hardKeeper.Deposit(ctx, macc.GetAddress(), sdk.NewCoins(amount))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Withdraw withdraws the specified amount of coins from hard.
 | 
				
			||||||
func (s *HardStrategy) Withdraw(ctx sdk.Context, amount sdk.Coin) error {
 | 
					func (s *HardStrategy) Withdraw(ctx sdk.Context, amount sdk.Coin) error {
 | 
				
			||||||
	macc := s.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
 | 
						macc := s.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
 | 
				
			||||||
	return s.hardKeeper.Withdraw(ctx, macc.GetAddress(), sdk.NewCoins(amount))
 | 
						return s.hardKeeper.Withdraw(ctx, macc.GetAddress(), sdk.NewCoins(amount))
 | 
				
			||||||
 | 
				
			|||||||
@ -250,9 +250,12 @@ func (suite *strategyHardTestSuite) TestWithdraw_WithAccumulatedHard() {
 | 
				
			|||||||
	suite.Require().NoError(err)
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Direct hard deposit from module account to increase vault value
 | 
						// Direct hard deposit from module account to increase vault value
 | 
				
			||||||
	suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 20)))
 | 
						err = suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 20)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
						macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
				
			||||||
	suite.HardKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 20)))
 | 
						err = suite.HardKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 20)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Query account value
 | 
						// Query account value
 | 
				
			||||||
	accValue, err := suite.Keeper.GetVaultAccountValue(suite.Ctx, vaultDenom, acc)
 | 
						accValue, err := suite.Keeper.GetVaultAccountValue(suite.Ctx, vaultDenom, acc)
 | 
				
			||||||
@ -293,7 +296,8 @@ func (suite *strategyHardTestSuite) TestAccountShares() {
 | 
				
			|||||||
	vaultDenom := "usdx"
 | 
						vaultDenom := "usdx"
 | 
				
			||||||
	startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
						startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
				
			||||||
	depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
						depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
				
			||||||
	suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 1000)))
 | 
						err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 1000)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
						suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -302,7 +306,7 @@ func (suite *strategyHardTestSuite) TestAccountShares() {
 | 
				
			|||||||
	acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
						acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 1. acc1 deposit 100
 | 
						// 1. acc1 deposit 100
 | 
				
			||||||
	err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
	suite.Require().NoError(err)
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
						acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
@ -344,7 +348,8 @@ func (suite *strategyHardTestSuite) TestAccountShares() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Hard deposit again from module account to triple original value
 | 
						// Hard deposit again from module account to triple original value
 | 
				
			||||||
	// 210 -> 300
 | 
						// 210 -> 300
 | 
				
			||||||
	suite.HardKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 90)))
 | 
						err = suite.HardKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 90)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Deposit again from acc1
 | 
						// Deposit again from acc1
 | 
				
			||||||
	err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
@ -368,7 +373,8 @@ func (suite *strategyHardTestSuite) TestWithdraw_AccumulatedAmount() {
 | 
				
			|||||||
	vaultDenom := "usdx"
 | 
						vaultDenom := "usdx"
 | 
				
			||||||
	startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
						startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
				
			||||||
	depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
						depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
				
			||||||
	suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 1000)))
 | 
						err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 1000)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
						suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -377,7 +383,7 @@ func (suite *strategyHardTestSuite) TestWithdraw_AccumulatedAmount() {
 | 
				
			|||||||
	acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
						acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 1. acc1 deposit 100
 | 
						// 1. acc1 deposit 100
 | 
				
			||||||
	err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
	suite.Require().NoError(err)
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// acc2 deposit 100, just to make sure other deposits do not affect acc1
 | 
						// acc2 deposit 100, just to make sure other deposits do not affect acc1
 | 
				
			||||||
@ -406,7 +412,8 @@ func (suite *strategyHardTestSuite) TestWithdraw_AccumulatedTruncated() {
 | 
				
			|||||||
	vaultDenom := "usdx"
 | 
						vaultDenom := "usdx"
 | 
				
			||||||
	startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
						startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
				
			||||||
	depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
						depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
				
			||||||
	suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 1000)))
 | 
						err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 1000)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
						suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -415,7 +422,7 @@ func (suite *strategyHardTestSuite) TestWithdraw_AccumulatedTruncated() {
 | 
				
			|||||||
	acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
						acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 1. acc1 deposit 100
 | 
						// 1. acc1 deposit 100
 | 
				
			||||||
	err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
	suite.Require().NoError(err)
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// acc2 deposit 100, just to make sure other deposits do not affect acc1
 | 
						// acc2 deposit 100, just to make sure other deposits do not affect acc1
 | 
				
			||||||
@ -451,7 +458,8 @@ func (suite *strategyHardTestSuite) TestWithdraw_ExpensiveShares() {
 | 
				
			|||||||
	vaultDenom := "usdx"
 | 
						vaultDenom := "usdx"
 | 
				
			||||||
	startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
						startBalance := sdk.NewInt64Coin(vaultDenom, 1000)
 | 
				
			||||||
	depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
						depositAmount := sdk.NewInt64Coin(vaultDenom, 100)
 | 
				
			||||||
	suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 2000)))
 | 
						err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 2000)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
						suite.CreateVault(vaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_HARD}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -459,7 +467,7 @@ func (suite *strategyHardTestSuite) TestWithdraw_ExpensiveShares() {
 | 
				
			|||||||
	acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress()
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 1. acc1 deposit 100
 | 
						// 1. acc1 deposit 100
 | 
				
			||||||
	err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
 | 
				
			||||||
	suite.Require().NoError(err)
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
						acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										49
									
								
								x/earn/keeper/strategy_savings.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								x/earn/keeper/strategy_savings.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					package keeper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/types"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SavingsStrategy defines the strategy that deposits assets to x/savings
 | 
				
			||||||
 | 
					type SavingsStrategy Keeper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ Strategy = (*SavingsStrategy)(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetStrategyType returns the strategy type
 | 
				
			||||||
 | 
					func (s *SavingsStrategy) GetStrategyType() types.StrategyType {
 | 
				
			||||||
 | 
						return types.STRATEGY_TYPE_SAVINGS
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetEstimatedTotalAssets returns the current value of all assets deposited
 | 
				
			||||||
 | 
					// in savings.
 | 
				
			||||||
 | 
					func (s *SavingsStrategy) GetEstimatedTotalAssets(ctx sdk.Context, denom string) (sdk.Coin, error) {
 | 
				
			||||||
 | 
						macc := s.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
 | 
				
			||||||
 | 
						deposit, found := s.savingsKeeper.GetDeposit(ctx, macc.GetAddress())
 | 
				
			||||||
 | 
						if !found {
 | 
				
			||||||
 | 
							// Return 0 if no deposit exists for module account
 | 
				
			||||||
 | 
							return sdk.NewCoin(denom, sdk.ZeroInt()), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Only return the deposit for the vault denom.
 | 
				
			||||||
 | 
						for _, coin := range deposit.Amount {
 | 
				
			||||||
 | 
							if coin.Denom == denom {
 | 
				
			||||||
 | 
								return coin, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Return 0 if no deposit exists for the vault denom
 | 
				
			||||||
 | 
						return sdk.NewCoin(denom, sdk.ZeroInt()), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deposit deposits the specified amount of coins into savings.
 | 
				
			||||||
 | 
					func (s *SavingsStrategy) Deposit(ctx sdk.Context, amount sdk.Coin) error {
 | 
				
			||||||
 | 
						macc := s.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
 | 
				
			||||||
 | 
						return s.savingsKeeper.Deposit(ctx, macc.GetAddress(), sdk.NewCoins(amount))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Withdraw withdraws the specified amount of coins from savings.
 | 
				
			||||||
 | 
					func (s *SavingsStrategy) Withdraw(ctx sdk.Context, amount sdk.Coin) error {
 | 
				
			||||||
 | 
						macc := s.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
 | 
				
			||||||
 | 
						return s.savingsKeeper.Withdraw(ctx, macc.GetAddress(), sdk.NewCoins(amount))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										486
									
								
								x/earn/keeper/strategy_savings_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										486
									
								
								x/earn/keeper/strategy_savings_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,486 @@
 | 
				
			|||||||
 | 
					package keeper_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/testutil"
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/x/earn/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/suite"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const savingsVaultDenom = "ukava"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type strategySavingsTestSuite struct {
 | 
				
			||||||
 | 
						testutil.Suite
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) SetupTest() {
 | 
				
			||||||
 | 
						suite.Suite.SetupTest()
 | 
				
			||||||
 | 
						suite.Keeper.SetParams(suite.Ctx, types.DefaultParams())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestStrategySavingsTestSuite(t *testing.T) {
 | 
				
			||||||
 | 
						suite.Run(t, new(strategySavingsTestSuite))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestGetStrategyType() {
 | 
				
			||||||
 | 
						strategy, err := suite.Keeper.GetStrategy(types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Equal(types.STRATEGY_TYPE_SAVINGS, strategy.GetStrategyType())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestDeposit_SingleAcc() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.SavingsDepositAmountEqual(sdk.NewCoins(depositAmount))
 | 
				
			||||||
 | 
						suite.VaultTotalValuesEqual(sdk.NewCoins(depositAmount))
 | 
				
			||||||
 | 
						suite.VaultTotalSharesEqual(types.NewVaultShares(
 | 
				
			||||||
 | 
							types.NewVaultShare(depositAmount.Denom, depositAmount.Amount.ToDec()),
 | 
				
			||||||
 | 
						))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Query vault total
 | 
				
			||||||
 | 
						totalValue, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, savingsVaultDenom)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Equal(depositAmount, totalValue)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestDeposit_SingleAcc_MultipleDeposits() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Second deposit
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectedVaultBalance := depositAmount.Add(depositAmount)
 | 
				
			||||||
 | 
						suite.SavingsDepositAmountEqual(sdk.NewCoins(expectedVaultBalance))
 | 
				
			||||||
 | 
						suite.VaultTotalValuesEqual(sdk.NewCoins(expectedVaultBalance))
 | 
				
			||||||
 | 
						suite.VaultTotalSharesEqual(types.NewVaultShares(
 | 
				
			||||||
 | 
							types.NewVaultShare(expectedVaultBalance.Denom, expectedVaultBalance.Amount.ToDec()),
 | 
				
			||||||
 | 
						))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Query vault total
 | 
				
			||||||
 | 
						totalValue, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, savingsVaultDenom)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Equal(depositAmount.Add(depositAmount), totalValue)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestDeposit_MultipleAcc_MultipleDeposits() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectedTotalValue := sdk.NewCoin(savingsVaultDenom, depositAmount.Amount.MulRaw(4))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
						acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2 deposits each account
 | 
				
			||||||
 | 
						for i := 0; i < 2; i++ {
 | 
				
			||||||
 | 
							// Deposit from acc1
 | 
				
			||||||
 | 
							err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
							suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Deposit from acc2
 | 
				
			||||||
 | 
							err = suite.Keeper.Deposit(suite.Ctx, acc2.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
							suite.Require().NoError(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.SavingsDepositAmountEqual(sdk.NewCoins(expectedTotalValue))
 | 
				
			||||||
 | 
						suite.VaultTotalValuesEqual(sdk.NewCoins(expectedTotalValue))
 | 
				
			||||||
 | 
						suite.VaultTotalSharesEqual(types.NewVaultShares(
 | 
				
			||||||
 | 
							types.NewVaultShare(expectedTotalValue.Denom, expectedTotalValue.Amount.ToDec()),
 | 
				
			||||||
 | 
						))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Query vault total
 | 
				
			||||||
 | 
						totalValue, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, savingsVaultDenom)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Equal(expectedTotalValue, totalValue)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestGetVaultTotalValue_Empty() {
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Query vault total
 | 
				
			||||||
 | 
						totalValue, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, savingsVaultDenom)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewCoin(savingsVaultDenom, sdk.ZeroInt()), totalValue)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestGetVaultTotalValue_NoDenomDeposit() {
 | 
				
			||||||
 | 
						// 2 Vaults usdx, busd
 | 
				
			||||||
 | 
						// 1st vault has deposits
 | 
				
			||||||
 | 
						// 2nd vault has no deposits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vaultDenomBusd := "busd"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
						suite.CreateVault(vaultDenomBusd, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deposit vault1
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Query vault total, savings deposit exists for account, but amount in busd does not
 | 
				
			||||||
 | 
						// Vault2 does not have any value, only returns amount for the correct denom
 | 
				
			||||||
 | 
						// if a savings deposit already exists
 | 
				
			||||||
 | 
						totalValueBusd, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, vaultDenomBusd)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewCoin(vaultDenomBusd, sdk.ZeroInt()), totalValueBusd)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					// Withdraw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestWithdraw() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.SavingsDepositAmountEqual(sdk.NewCoins(depositAmount))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Query vault total
 | 
				
			||||||
 | 
						totalValue, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, savingsVaultDenom)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
						suite.Equal(depositAmount, totalValue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Withdraw
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.SavingsDepositAmountEqual(sdk.NewCoins())
 | 
				
			||||||
 | 
						suite.VaultTotalValuesEqual(sdk.NewCoins())
 | 
				
			||||||
 | 
						suite.VaultTotalSharesEqual(types.NewVaultShares())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						totalValue, err = suite.Keeper.GetVaultTotalValue(suite.Ctx, savingsVaultDenom)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewInt64Coin(savingsVaultDenom, 0), totalValue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Withdraw again
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().Error(err)
 | 
				
			||||||
 | 
						suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound, "vault should be deleted when no more supply")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestWithdraw_OnlyWithdrawOwnSupply() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deposits from 2 accounts
 | 
				
			||||||
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress()
 | 
				
			||||||
 | 
						acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Withdraw
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Withdraw again
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().Error(err)
 | 
				
			||||||
 | 
						suite.Require().ErrorIs(
 | 
				
			||||||
 | 
							err,
 | 
				
			||||||
 | 
							types.ErrVaultShareRecordNotFound,
 | 
				
			||||||
 | 
							"should only be able to withdraw the account's own supply",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestWithdraw_WithAccumulatedSavings() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deposits accounts
 | 
				
			||||||
 | 
						acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress()
 | 
				
			||||||
 | 
						acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deposit from acc2 so the vault doesn't get deleted when withdrawing
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Direct savings deposit from module account to increase vault value
 | 
				
			||||||
 | 
						err = suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 20)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
				
			||||||
 | 
						err = suite.SavingsKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 20)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Query account value
 | 
				
			||||||
 | 
						accValue, err := suite.Keeper.GetVaultAccountValue(suite.Ctx, savingsVaultDenom, acc)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
						suite.Equal(depositAmount.AddAmount(sdk.NewInt(10)), accValue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Withdraw 100, 10 remaining
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Withdraw 100 again -- too much
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().Error(err)
 | 
				
			||||||
 | 
						suite.Require().ErrorIs(
 | 
				
			||||||
 | 
							err,
 | 
				
			||||||
 | 
							types.ErrInsufficientValue,
 | 
				
			||||||
 | 
							"cannot withdraw more than account value",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Half of remaining 10, 5 remaining
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(savingsVaultDenom, sdk.NewInt(5)), types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Withdraw all
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(savingsVaultDenom, sdk.NewInt(5)), types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						accValue, err = suite.Keeper.GetVaultAccountValue(suite.Ctx, savingsVaultDenom, acc)
 | 
				
			||||||
 | 
						suite.Require().Errorf(
 | 
				
			||||||
 | 
							err,
 | 
				
			||||||
 | 
							"account should be deleted when all shares withdrawn but has %s value still",
 | 
				
			||||||
 | 
							accValue,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						suite.Require().Equal("account vault share record for ukava not found", err.Error())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestAccountShares() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
						err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 1000)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deposit from account1
 | 
				
			||||||
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress()
 | 
				
			||||||
 | 
						acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 1. acc1 deposit 100
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewDec(100), acc1Shares.AmountOf(savingsVaultDenom), "initial deposit 1:1 shares")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2. Direct savings deposit from module account to increase vault value
 | 
				
			||||||
 | 
						// Total value: 100 -> 110
 | 
				
			||||||
 | 
						macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
				
			||||||
 | 
						err = suite.SavingsKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 10)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2. acc2 deposit 100
 | 
				
			||||||
 | 
						// share price is 10% more expensive now
 | 
				
			||||||
 | 
						// savings 110 -> 210
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 100 * 100 / 210 = 47.619047619 shares
 | 
				
			||||||
 | 
						// 2.1 price * 47.619047619 = 99.9999999999
 | 
				
			||||||
 | 
						acc2Value, err := suite.Keeper.GetVaultAccountValue(suite.Ctx, savingsVaultDenom, acc2)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
						suite.Equal(
 | 
				
			||||||
 | 
							sdk.NewInt(99),
 | 
				
			||||||
 | 
							acc2Value.Amount,
 | 
				
			||||||
 | 
							"value 1 less than deposit amount with different share price, decimals truncated",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc2Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc2)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
						// 100 * 100 / 110 = 90.909090909090909091
 | 
				
			||||||
 | 
						// QuoInt64() truncates
 | 
				
			||||||
 | 
						expectedAcc2Shares := sdk.NewDec(100).MulInt64(100).QuoInt64(110)
 | 
				
			||||||
 | 
						suite.Equal(expectedAcc2Shares, acc2Shares.AmountOf(savingsVaultDenom))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vaultTotalShares, found := suite.Keeper.GetVaultTotalShares(suite.Ctx, savingsVaultDenom)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewDec(100).Add(expectedAcc2Shares), vaultTotalShares.Amount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Savings deposit again from module account to triple original value
 | 
				
			||||||
 | 
						// 210 -> 300
 | 
				
			||||||
 | 
						err = suite.SavingsKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 90)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deposit again from acc1
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1Shares, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
						// totalShares = 100 + 90            = 190
 | 
				
			||||||
 | 
						// totalValue  = 100 + 10 + 100 + 90 = 300
 | 
				
			||||||
 | 
						// sharesIssued = assetAmount * (shareCount / totalTokens)
 | 
				
			||||||
 | 
						// sharedIssued = 100 * 190 / 300 = 63.3 = 63
 | 
				
			||||||
 | 
						// total shares = 100 + 63 = 163
 | 
				
			||||||
 | 
						suite.Equal(
 | 
				
			||||||
 | 
							sdk.NewDec(100).Add(sdk.NewDec(100).Mul(vaultTotalShares.Amount).Quo(sdk.NewDec(300))),
 | 
				
			||||||
 | 
							acc1Shares.AmountOf(savingsVaultDenom),
 | 
				
			||||||
 | 
							"shares should consist of 100 of 1x share price and 63 of 3x share price",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestWithdraw_AccumulatedAmount() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
						err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 1000)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deposit from account1
 | 
				
			||||||
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress()
 | 
				
			||||||
 | 
						acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 1. acc1 deposit 100
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// acc2 deposit 100, just to make sure other deposits do not affect acc1
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewDec(100), acc1Shares.AmountOf(savingsVaultDenom), "initial deposit 1:1 shares")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2. Direct savings deposit from module account to increase vault value
 | 
				
			||||||
 | 
						// Total value: 200 -> 220, 110 each account
 | 
				
			||||||
 | 
						macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
				
			||||||
 | 
						err = suite.SavingsKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 20)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 3. Withdraw all from acc1 - including accumulated amount
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount.AddAmount(sdk.NewInt(10)), types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
 | 
						suite.Require().False(found, "should have withdrawn entire shares")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestWithdraw_AccumulatedTruncated() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
						err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 1000)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deposit from account1
 | 
				
			||||||
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress()
 | 
				
			||||||
 | 
						acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 1. acc1 deposit 100
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// acc2 deposit 100, just to make sure other deposits do not affect acc1
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewDec(100), acc1Shares.AmountOf(savingsVaultDenom), "initial deposit 1:1 shares")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2. Direct savings deposit from module account to increase vault value
 | 
				
			||||||
 | 
						// Total value: 200 -> 211, 105.5 each account
 | 
				
			||||||
 | 
						macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
				
			||||||
 | 
						err = suite.SavingsKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 11)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						accBal, err := suite.Keeper.GetVaultAccountValue(suite.Ctx, savingsVaultDenom, acc1)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
						suite.Equal(depositAmount.AddAmount(sdk.NewInt(5)), accBal, "acc1 should have 105 usdx")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 3. Withdraw all from acc1 - including accumulated amount
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount.AddAmount(sdk.NewInt(5)), types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1Shares, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
 | 
						suite.Require().Falsef(found, "should have withdrawn entire shares but has %s", acc1Shares)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = suite.Keeper.GetVaultAccountValue(suite.Ctx, savingsVaultDenom, acc1)
 | 
				
			||||||
 | 
						suite.Require().Error(err)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *strategySavingsTestSuite) TestWithdraw_ExpensiveShares() {
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(savingsVaultDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(savingsVaultDenom, 100)
 | 
				
			||||||
 | 
						err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleName, sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 2000)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.CreateVault(savingsVaultDenom, types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Deposit from account1
 | 
				
			||||||
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 1. acc1 deposit 100
 | 
				
			||||||
 | 
						err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
 | 
						suite.Require().True(found)
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewDec(100), acc1Shares.AmountOf(savingsVaultDenom), "initial deposit 1:1 shares")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2. Direct savings deposit from module account to increase vault value
 | 
				
			||||||
 | 
						// Total value: 100 -> 2000, shares now 10usdx each
 | 
				
			||||||
 | 
						macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
				
			||||||
 | 
						err = suite.SavingsKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(savingsVaultDenom, 1900)))
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						accBal, err := suite.Keeper.GetVaultAccountValue(suite.Ctx, savingsVaultDenom, acc1)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewInt(2000), accBal.Amount, "acc1 should have 2000 usdx")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 3. Withdraw all from acc1 - including accumulated amount
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc1, sdk.NewInt64Coin(savingsVaultDenom, 2000), types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1Shares, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
 | 
				
			||||||
 | 
						suite.Require().Falsef(found, "should have withdrawn entire shares but has %s", acc1Shares)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = suite.Keeper.GetVaultAccountValue(suite.Ctx, savingsVaultDenom, acc1)
 | 
				
			||||||
 | 
						suite.Require().Error(err)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -7,9 +7,7 @@ import (
 | 
				
			|||||||
	"github.com/kava-labs/kava/x/earn/types"
 | 
						"github.com/kava-labs/kava/x/earn/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetVaultTotalShares returns the total balance supplied to the vault. This
 | 
					// GetVaultTotalShares returns the total shares of a vault.
 | 
				
			||||||
// may not necessarily be the current value of the vault, as it is the sum
 | 
					 | 
				
			||||||
// of the supplied denom and the value may be higher due to accumulated APYs.
 | 
					 | 
				
			||||||
func (k *Keeper) GetVaultTotalShares(
 | 
					func (k *Keeper) GetVaultTotalShares(
 | 
				
			||||||
	ctx sdk.Context,
 | 
						ctx sdk.Context,
 | 
				
			||||||
	denom string,
 | 
						denom string,
 | 
				
			||||||
@ -22,9 +20,8 @@ func (k *Keeper) GetVaultTotalShares(
 | 
				
			|||||||
	return vault.TotalShares, true
 | 
						return vault.TotalShares, true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetTotalValue returns the total **value** of all coins in this vault,
 | 
					// GetVaultTotalValue returns the total value of a vault, i.e. the realizable
 | 
				
			||||||
// i.e. the realizable total value denominated by GetDenom() if the vault
 | 
					// total value if the vault were to liquidate its entire strategies.
 | 
				
			||||||
// were to liquidate its entire strategies.
 | 
					 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// **Note:** This does not include the tokens held in bank by the module
 | 
					// **Note:** This does not include the tokens held in bank by the module
 | 
				
			||||||
// account. If it were to be included, also note that the module account is
 | 
					// account. If it were to be included, also note that the module account is
 | 
				
			||||||
@ -33,21 +30,21 @@ func (k *Keeper) GetVaultTotalValue(
 | 
				
			|||||||
	ctx sdk.Context,
 | 
						ctx sdk.Context,
 | 
				
			||||||
	denom string,
 | 
						denom string,
 | 
				
			||||||
) (sdk.Coin, error) {
 | 
					) (sdk.Coin, error) {
 | 
				
			||||||
	enabledVault, found := k.GetAllowedVault(ctx, denom)
 | 
						allowedVault, found := k.GetAllowedVault(ctx, denom)
 | 
				
			||||||
	if !found {
 | 
						if !found {
 | 
				
			||||||
		return sdk.Coin{}, types.ErrVaultRecordNotFound
 | 
							return sdk.Coin{}, types.ErrVaultRecordNotFound
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	strategy, err := k.GetStrategy(enabledVault.Strategies[0])
 | 
						strategy, err := k.GetStrategy(allowedVault.Strategies[0])
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return sdk.Coin{}, types.ErrInvalidVaultStrategy
 | 
							return sdk.Coin{}, types.ErrInvalidVaultStrategy
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return strategy.GetEstimatedTotalAssets(ctx, enabledVault.Denom)
 | 
						// Denom can be different from allowedVault.Denom for bkava
 | 
				
			||||||
 | 
						return strategy.GetEstimatedTotalAssets(ctx, denom)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetVaultAccountSupplied returns the supplied amount for a single address
 | 
					// GetVaultAccountShares returns the shares for a single address for all vaults.
 | 
				
			||||||
// within a vault.
 | 
					 | 
				
			||||||
func (k *Keeper) GetVaultAccountShares(
 | 
					func (k *Keeper) GetVaultAccountShares(
 | 
				
			||||||
	ctx sdk.Context,
 | 
						ctx sdk.Context,
 | 
				
			||||||
	acc sdk.AccAddress,
 | 
						acc sdk.AccAddress,
 | 
				
			||||||
 | 
				
			|||||||
@ -42,8 +42,7 @@ func (k *Keeper) UpdateVaultShareRecord(
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DeleteVaultShareRecord deletes the vault share record for a given denom and
 | 
					// DeleteVaultShareRecord deletes the vault share record for a given account.
 | 
				
			||||||
// account.
 | 
					 | 
				
			||||||
func (k *Keeper) DeleteVaultShareRecord(
 | 
					func (k *Keeper) DeleteVaultShareRecord(
 | 
				
			||||||
	ctx sdk.Context,
 | 
						ctx sdk.Context,
 | 
				
			||||||
	acc sdk.AccAddress,
 | 
						acc sdk.AccAddress,
 | 
				
			||||||
@ -52,7 +51,7 @@ func (k *Keeper) DeleteVaultShareRecord(
 | 
				
			|||||||
	store.Delete(types.DepositorVaultSharesKey(acc))
 | 
						store.Delete(types.DepositorVaultSharesKey(acc))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetVaultShareRecord sets the vault share record for a given denom and account.
 | 
					// SetVaultShareRecord sets the vault share record for a given account.
 | 
				
			||||||
func (k *Keeper) SetVaultShareRecord(
 | 
					func (k *Keeper) SetVaultShareRecord(
 | 
				
			||||||
	ctx sdk.Context,
 | 
						ctx sdk.Context,
 | 
				
			||||||
	record types.VaultShareRecord,
 | 
						record types.VaultShareRecord,
 | 
				
			||||||
 | 
				
			|||||||
@ -126,6 +126,9 @@ func (k *Keeper) Withdraw(
 | 
				
			|||||||
		withdrawShares = vaultShareRecord.Shares.GetShare(withdrawAmount.Denom)
 | 
							withdrawShares = vaultShareRecord.Shares.GetShare(withdrawAmount.Denom)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Call hook before record is modified
 | 
				
			||||||
 | 
						k.BeforeVaultDepositModified(ctx, wantAmount.Denom, from, vaultRecord.TotalShares.Amount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Decrement VaultRecord and VaultShareRecord supplies - must delete same
 | 
						// Decrement VaultRecord and VaultShareRecord supplies - must delete same
 | 
				
			||||||
	// amounts
 | 
						// amounts
 | 
				
			||||||
	vaultShareRecord.Shares = vaultShareRecord.Shares.Sub(withdrawShares)
 | 
						vaultShareRecord.Shares = vaultShareRecord.Shares.Sub(withdrawShares)
 | 
				
			||||||
 | 
				
			|||||||
@ -241,3 +241,33 @@ func (suite *withdrawTestSuite) TestWithdraw_Partial() {
 | 
				
			|||||||
		sdk.NewCoins(),
 | 
							sdk.NewCoins(),
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *withdrawTestSuite) TestWithdraw_bKava() {
 | 
				
			||||||
 | 
						vaultDenom := "bkava"
 | 
				
			||||||
 | 
						coinDenom := vaultDenom + "-kavavaloper16xyempempp92x9hyzz9wrgf94r6j9h5f2w4n2l"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						startBalance := sdk.NewInt64Coin(coinDenom, 1000)
 | 
				
			||||||
 | 
						depositAmount := sdk.NewInt64Coin(coinDenom, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// vault denom is only "bkava" which has it's own special handler
 | 
				
			||||||
 | 
						suite.CreateVault(
 | 
				
			||||||
 | 
							vaultDenom,
 | 
				
			||||||
 | 
							types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS},
 | 
				
			||||||
 | 
							false,
 | 
				
			||||||
 | 
							[]sdk.AccAddress{},
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(
 | 
				
			||||||
 | 
							err,
 | 
				
			||||||
 | 
							"should be able to deposit bkava derivative denom in bkava vault",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = suite.Keeper.Withdraw(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
 | 
				
			||||||
 | 
						suite.Require().NoError(
 | 
				
			||||||
 | 
							err,
 | 
				
			||||||
 | 
							"should be able to withdraw bkava derivative denom from bkava vault",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ import (
 | 
				
			|||||||
	hardtypes "github.com/kava-labs/kava/x/hard/types"
 | 
						hardtypes "github.com/kava-labs/kava/x/hard/types"
 | 
				
			||||||
	pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types"
 | 
						pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types"
 | 
				
			||||||
	savingskeeper "github.com/kava-labs/kava/x/savings/keeper"
 | 
						savingskeeper "github.com/kava-labs/kava/x/savings/keeper"
 | 
				
			||||||
 | 
						savingstypes "github.com/kava-labs/kava/x/savings/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/cosmos/cosmos-sdk/simapp"
 | 
						"github.com/cosmos/cosmos-sdk/simapp"
 | 
				
			||||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
@ -141,12 +142,23 @@ func (suite *Suite) SetupTest() {
 | 
				
			|||||||
		hardtypes.DefaultTotalReserves,
 | 
							hardtypes.DefaultTotalReserves,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						savingsGS := savingstypes.NewGenesisState(
 | 
				
			||||||
 | 
							savingstypes.NewParams(
 | 
				
			||||||
 | 
								[]string{
 | 
				
			||||||
 | 
									"ukava",
 | 
				
			||||||
 | 
									"bkava-kavavaloper16xyempempp92x9hyzz9wrgf94r6j9h5f2w4n2l",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
							nil,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tApp := app.NewTestApp()
 | 
						tApp := app.NewTestApp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tApp.InitializeFromGenesisStates(
 | 
						tApp.InitializeFromGenesisStates(
 | 
				
			||||||
		app.GenesisState{
 | 
							app.GenesisState{
 | 
				
			||||||
			pricefeedtypes.ModuleName: tApp.AppCodec().MustMarshalJSON(&pricefeedGS),
 | 
								pricefeedtypes.ModuleName: tApp.AppCodec().MustMarshalJSON(&pricefeedGS),
 | 
				
			||||||
			hardtypes.ModuleName:      tApp.AppCodec().MustMarshalJSON(&hardGS),
 | 
								hardtypes.ModuleName:      tApp.AppCodec().MustMarshalJSON(&hardGS),
 | 
				
			||||||
 | 
								savingstypes.ModuleName:   tApp.AppCodec().MustMarshalJSON(&savingsGS),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -251,6 +263,8 @@ func (suite *Suite) ModuleAccountBalanceEqual(coins sdk.Coins) {
 | 
				
			|||||||
// ----------------------------------------------------------------------------
 | 
					// ----------------------------------------------------------------------------
 | 
				
			||||||
// Earn
 | 
					// Earn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VaultTotalValuesEqual asserts that the vault total values match the provided
 | 
				
			||||||
 | 
					// values.
 | 
				
			||||||
func (suite *Suite) VaultTotalValuesEqual(expected sdk.Coins) {
 | 
					func (suite *Suite) VaultTotalValuesEqual(expected sdk.Coins) {
 | 
				
			||||||
	for _, coin := range expected {
 | 
						for _, coin := range expected {
 | 
				
			||||||
		vaultBal, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, coin.Denom)
 | 
							vaultBal, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, coin.Denom)
 | 
				
			||||||
@ -259,6 +273,8 @@ func (suite *Suite) VaultTotalValuesEqual(expected sdk.Coins) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VaultTotalSharesEqual asserts that the vault total shares match the provided
 | 
				
			||||||
 | 
					// values.
 | 
				
			||||||
func (suite *Suite) VaultTotalSharesEqual(expected types.VaultShares) {
 | 
					func (suite *Suite) VaultTotalSharesEqual(expected types.VaultShares) {
 | 
				
			||||||
	for _, share := range expected {
 | 
						for _, share := range expected {
 | 
				
			||||||
		vaultBal, found := suite.Keeper.GetVaultTotalShares(suite.Ctx, share.Denom)
 | 
							vaultBal, found := suite.Keeper.GetVaultTotalShares(suite.Ctx, share.Denom)
 | 
				
			||||||
@ -267,6 +283,8 @@ func (suite *Suite) VaultTotalSharesEqual(expected types.VaultShares) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VaultAccountSharesEqual asserts that the vault account shares match the provided
 | 
				
			||||||
 | 
					// values.
 | 
				
			||||||
func (suite *Suite) VaultAccountSharesEqual(accs []sdk.AccAddress, supplies []sdk.Coins) {
 | 
					func (suite *Suite) VaultAccountSharesEqual(accs []sdk.AccAddress, supplies []sdk.Coins) {
 | 
				
			||||||
	for i, acc := range accs {
 | 
						for i, acc := range accs {
 | 
				
			||||||
		coins := supplies[i]
 | 
							coins := supplies[i]
 | 
				
			||||||
@ -288,6 +306,8 @@ func (suite *Suite) VaultAccountSharesEqual(accs []sdk.AccAddress, supplies []sd
 | 
				
			|||||||
// ----------------------------------------------------------------------------
 | 
					// ----------------------------------------------------------------------------
 | 
				
			||||||
// Hard
 | 
					// Hard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HardDepositAmountEqual asserts that the hard deposit amount matches the provided
 | 
				
			||||||
 | 
					// values.
 | 
				
			||||||
func (suite *Suite) HardDepositAmountEqual(expected sdk.Coins) {
 | 
					func (suite *Suite) HardDepositAmountEqual(expected sdk.Coins) {
 | 
				
			||||||
	macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
						macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -306,6 +326,29 @@ func (suite *Suite) HardDepositAmountEqual(expected sdk.Coins) {
 | 
				
			|||||||
	)
 | 
						)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					// Savings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SavingsDepositAmountEqual asserts that the savings deposit amount matches the
 | 
				
			||||||
 | 
					// provided values.
 | 
				
			||||||
 | 
					func (suite *Suite) SavingsDepositAmountEqual(expected sdk.Coins) {
 | 
				
			||||||
 | 
						macc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						savingsDeposit, found := suite.SavingsKeeper.GetDeposit(suite.Ctx, macc.GetAddress())
 | 
				
			||||||
 | 
						if expected.IsZero() {
 | 
				
			||||||
 | 
							suite.Require().False(found)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Require().True(found, "savings should have a deposit")
 | 
				
			||||||
 | 
						suite.Require().Equalf(
 | 
				
			||||||
 | 
							expected,
 | 
				
			||||||
 | 
							savingsDeposit.Amount,
 | 
				
			||||||
 | 
							"savings should have a deposit with the amount %v",
 | 
				
			||||||
 | 
							expected,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ----------------------------------------------------------------------------
 | 
					// ----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EventsContains asserts that the expected event is in the provided events
 | 
					// EventsContains asserts that the expected event is in the provided events
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
// earn module errors
 | 
					// earn module errors
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	ErrInvalidVaultDenom        = sdkerrors.Register(ModuleName, 2, "invalid vault denom")
 | 
						ErrInvalidVaultDenom        = sdkerrors.Register(ModuleName, 2, "invalid vault denom")
 | 
				
			||||||
	ErrInvalidVaultStrategy     = sdkerrors.Register(ModuleName, 3, "invalid vault strategy")
 | 
						ErrInvalidVaultStrategy     = sdkerrors.Register(ModuleName, 3, "vault does not support this strategy")
 | 
				
			||||||
	ErrInsufficientAmount       = sdkerrors.Register(ModuleName, 4, "insufficient amount")
 | 
						ErrInsufficientAmount       = sdkerrors.Register(ModuleName, 4, "insufficient amount")
 | 
				
			||||||
	ErrInsufficientValue        = sdkerrors.Register(ModuleName, 5, "insufficient vault account value")
 | 
						ErrInsufficientValue        = sdkerrors.Register(ModuleName, 5, "insufficient vault account value")
 | 
				
			||||||
	ErrVaultRecordNotFound      = sdkerrors.Register(ModuleName, 6, "vault record not found")
 | 
						ErrVaultRecordNotFound      = sdkerrors.Register(ModuleName, 6, "vault record not found")
 | 
				
			||||||
 | 
				
			|||||||
@ -40,3 +40,9 @@ type SavingsKeeper interface {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	GetDeposit(ctx sdk.Context, depositor sdk.AccAddress) (savingstypes.Deposit, bool)
 | 
						GetDeposit(ctx sdk.Context, depositor sdk.AccAddress) (savingstypes.Deposit, bool)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EarnHooks are event hooks called when a user's deposit to a earn vault changes.
 | 
				
			||||||
 | 
					type EarnHooks interface {
 | 
				
			||||||
 | 
						AfterVaultDepositCreated(ctx sdk.Context, vaultDenom string, depositor sdk.AccAddress, sharedOwned sdk.Dec)
 | 
				
			||||||
 | 
						BeforeVaultDepositModified(ctx sdk.Context, vaultDenom string, depositor sdk.AccAddress, sharedOwned sdk.Dec)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -28,7 +28,7 @@ var (
 | 
				
			|||||||
	VaultShareRecordKeyPrefix = []byte{0x02} // depositor address -> vault shares
 | 
						VaultShareRecordKeyPrefix = []byte{0x02} // depositor address -> vault shares
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Vault returns a key generated from a vault denom
 | 
					// VaultKey returns a key generated from a vault denom
 | 
				
			||||||
func VaultKey(denom string) []byte {
 | 
					func VaultKey(denom string) []byte {
 | 
				
			||||||
	return []byte(denom)
 | 
						return []byte(denom)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										38
									
								
								x/earn/types/mocks/EarnHooks.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								x/earn/types/mocks/EarnHooks.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					// Code generated by mockery v2.14.0. DO NOT EDIT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package mocks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						types "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
						mock "github.com/stretchr/testify/mock"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EarnHooks is an autogenerated mock type for the EarnHooks type
 | 
				
			||||||
 | 
					type EarnHooks struct {
 | 
				
			||||||
 | 
						mock.Mock
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AfterVaultDepositCreated provides a mock function with given fields: ctx, vaultDenom, depositor, sharedOwned
 | 
				
			||||||
 | 
					func (_m *EarnHooks) AfterVaultDepositCreated(ctx types.Context, vaultDenom string, depositor types.AccAddress, sharedOwned types.Dec) {
 | 
				
			||||||
 | 
						_m.Called(ctx, vaultDenom, depositor, sharedOwned)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BeforeVaultDepositModified provides a mock function with given fields: ctx, vaultDenom, depositor, sharedOwned
 | 
				
			||||||
 | 
					func (_m *EarnHooks) BeforeVaultDepositModified(ctx types.Context, vaultDenom string, depositor types.AccAddress, sharedOwned types.Dec) {
 | 
				
			||||||
 | 
						_m.Called(ctx, vaultDenom, depositor, sharedOwned)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type mockConstructorTestingTNewEarnHooks interface {
 | 
				
			||||||
 | 
						mock.TestingT
 | 
				
			||||||
 | 
						Cleanup(func())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewEarnHooks creates a new instance of EarnHooks. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
 | 
				
			||||||
 | 
					func NewEarnHooks(t mockConstructorTestingTNewEarnHooks) *EarnHooks {
 | 
				
			||||||
 | 
						mock := &EarnHooks{}
 | 
				
			||||||
 | 
						mock.Mock.Test(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.Cleanup(func() { mock.AssertExpectations(t) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return mock
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -30,8 +30,8 @@ func NewMsgDeposit(depositor string, amount sdk.Coin, strategy StrategyType) *Ms
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ValidateBasic does a simple validation check that doesn't require access to any other information.
 | 
					// ValidateBasic does a simple validation check that doesn't require access to any other information.
 | 
				
			||||||
func (msg MsgDeposit) ValidateBasic() error {
 | 
					func (msg MsgDeposit) ValidateBasic() error {
 | 
				
			||||||
	if msg.Depositor == "" {
 | 
						if _, err := sdk.AccAddressFromBech32(msg.Depositor); err != nil {
 | 
				
			||||||
		return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "depositor address cannot be empty")
 | 
							return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := msg.Amount.Validate(); err != nil {
 | 
						if err := msg.Amount.Validate(); err != nil {
 | 
				
			||||||
@ -82,8 +82,8 @@ func NewMsgWithdraw(from string, amount sdk.Coin, strategy StrategyType) *MsgWit
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ValidateBasic does a simple validation check that doesn't require access to any other information.
 | 
					// ValidateBasic does a simple validation check that doesn't require access to any other information.
 | 
				
			||||||
func (msg MsgWithdraw) ValidateBasic() error {
 | 
					func (msg MsgWithdraw) ValidateBasic() error {
 | 
				
			||||||
	if msg.From == "" {
 | 
						if _, err := sdk.AccAddressFromBech32(msg.From); err != nil {
 | 
				
			||||||
		return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "depositor address cannot be empty")
 | 
							return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := msg.Amount.Validate(); err != nil {
 | 
						if err := msg.Amount.Validate(); err != nil {
 | 
				
			||||||
 | 
				
			|||||||
@ -8,20 +8,25 @@ func NewQueryParamsRequest() *QueryParamsRequest {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewQueryVaultsRequest returns a new QueryVaultsRequest
 | 
					// NewQueryVaultsRequest returns a new QueryVaultsRequest
 | 
				
			||||||
func NewQueryVaultsRequest(denom string) *QueryVaultsRequest {
 | 
					func NewQueryVaultsRequest() *QueryVaultsRequest {
 | 
				
			||||||
	return &QueryVaultsRequest{
 | 
						return &QueryVaultsRequest{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewQueryVaultRequest returns a new QueryVaultRequest
 | 
				
			||||||
 | 
					func NewQueryVaultRequest(denom string) *QueryVaultRequest {
 | 
				
			||||||
 | 
						return &QueryVaultRequest{
 | 
				
			||||||
		Denom: denom,
 | 
							Denom: denom,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewQueryDepositsRequest returns a new QueryDepositsRequest
 | 
					// NewQueryDepositsRequest returns a new QueryDepositsRequest
 | 
				
			||||||
func NewQueryDepositsRequest(
 | 
					func NewQueryDepositsRequest(
 | 
				
			||||||
	owner string,
 | 
						depositor string,
 | 
				
			||||||
	denom string,
 | 
						denom string,
 | 
				
			||||||
	pagination *query.PageRequest,
 | 
						pagination *query.PageRequest,
 | 
				
			||||||
) *QueryDepositsRequest {
 | 
					) *QueryDepositsRequest {
 | 
				
			||||||
	return &QueryDepositsRequest{
 | 
						return &QueryDepositsRequest{
 | 
				
			||||||
		Owner:      owner,
 | 
							Depositor:  depositor,
 | 
				
			||||||
		Denom:      denom,
 | 
							Denom:      denom,
 | 
				
			||||||
		Pagination: pagination,
 | 
							Pagination: pagination,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -109,10 +109,8 @@ func (m *QueryParamsResponse) XXX_DiscardUnknown() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo
 | 
					var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// QueryVaultsRequest is the request type for the Query/Vault RPC method.
 | 
					// QueryVaultsRequest is the request type for the Query/Vaults RPC method.
 | 
				
			||||||
type QueryVaultsRequest struct {
 | 
					type QueryVaultsRequest struct {
 | 
				
			||||||
	// vault filters vault by denom
 | 
					 | 
				
			||||||
	Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"`
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *QueryVaultsRequest) Reset()         { *m = QueryVaultsRequest{} }
 | 
					func (m *QueryVaultsRequest) Reset()         { *m = QueryVaultsRequest{} }
 | 
				
			||||||
@ -187,6 +185,84 @@ func (m *QueryVaultsResponse) XXX_DiscardUnknown() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var xxx_messageInfo_QueryVaultsResponse proto.InternalMessageInfo
 | 
					var xxx_messageInfo_QueryVaultsResponse proto.InternalMessageInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// QueryVaultRequest is the request type for the Query/Vault RPC method.
 | 
				
			||||||
 | 
					type QueryVaultRequest struct {
 | 
				
			||||||
 | 
						// vault filters vault by denom
 | 
				
			||||||
 | 
						Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) Reset()         { *m = QueryVaultRequest{} }
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) String() string { return proto.CompactTextString(m) }
 | 
				
			||||||
 | 
					func (*QueryVaultRequest) ProtoMessage()    {}
 | 
				
			||||||
 | 
					func (*QueryVaultRequest) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return fileDescriptor_63f8dee2f3192a6b, []int{4}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) XXX_Unmarshal(b []byte) error {
 | 
				
			||||||
 | 
						return m.Unmarshal(b)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
 | 
				
			||||||
 | 
						if deterministic {
 | 
				
			||||||
 | 
							return xxx_messageInfo_QueryVaultRequest.Marshal(b, m, deterministic)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							b = b[:cap(b)]
 | 
				
			||||||
 | 
							n, err := m.MarshalToSizedBuffer(b)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return b[:n], nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) XXX_Merge(src proto.Message) {
 | 
				
			||||||
 | 
						xxx_messageInfo_QueryVaultRequest.Merge(m, src)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) XXX_Size() int {
 | 
				
			||||||
 | 
						return m.Size()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) XXX_DiscardUnknown() {
 | 
				
			||||||
 | 
						xxx_messageInfo_QueryVaultRequest.DiscardUnknown(m)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var xxx_messageInfo_QueryVaultRequest proto.InternalMessageInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// QueryVaultResponse is the response type for the Query/Vault RPC method.
 | 
				
			||||||
 | 
					type QueryVaultResponse struct {
 | 
				
			||||||
 | 
						// vault represents the queried earn module vault
 | 
				
			||||||
 | 
						Vault VaultResponse `protobuf:"bytes,1,opt,name=vault,proto3" json:"vault"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) Reset()         { *m = QueryVaultResponse{} }
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) String() string { return proto.CompactTextString(m) }
 | 
				
			||||||
 | 
					func (*QueryVaultResponse) ProtoMessage()    {}
 | 
				
			||||||
 | 
					func (*QueryVaultResponse) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return fileDescriptor_63f8dee2f3192a6b, []int{5}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) XXX_Unmarshal(b []byte) error {
 | 
				
			||||||
 | 
						return m.Unmarshal(b)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
 | 
				
			||||||
 | 
						if deterministic {
 | 
				
			||||||
 | 
							return xxx_messageInfo_QueryVaultResponse.Marshal(b, m, deterministic)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							b = b[:cap(b)]
 | 
				
			||||||
 | 
							n, err := m.MarshalToSizedBuffer(b)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return b[:n], nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) XXX_Merge(src proto.Message) {
 | 
				
			||||||
 | 
						xxx_messageInfo_QueryVaultResponse.Merge(m, src)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) XXX_Size() int {
 | 
				
			||||||
 | 
						return m.Size()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) XXX_DiscardUnknown() {
 | 
				
			||||||
 | 
						xxx_messageInfo_QueryVaultResponse.DiscardUnknown(m)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var xxx_messageInfo_QueryVaultResponse proto.InternalMessageInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// VaultResponse is the response type for a vault.
 | 
					// VaultResponse is the response type for a vault.
 | 
				
			||||||
type VaultResponse struct {
 | 
					type VaultResponse struct {
 | 
				
			||||||
	// denom represents the denom of the vault
 | 
						// denom represents the denom of the vault
 | 
				
			||||||
@ -212,7 +288,7 @@ func (m *VaultResponse) Reset()         { *m = VaultResponse{} }
 | 
				
			|||||||
func (m *VaultResponse) String() string { return proto.CompactTextString(m) }
 | 
					func (m *VaultResponse) String() string { return proto.CompactTextString(m) }
 | 
				
			||||||
func (*VaultResponse) ProtoMessage()    {}
 | 
					func (*VaultResponse) ProtoMessage()    {}
 | 
				
			||||||
func (*VaultResponse) Descriptor() ([]byte, []int) {
 | 
					func (*VaultResponse) Descriptor() ([]byte, []int) {
 | 
				
			||||||
	return fileDescriptor_63f8dee2f3192a6b, []int{4}
 | 
						return fileDescriptor_63f8dee2f3192a6b, []int{6}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (m *VaultResponse) XXX_Unmarshal(b []byte) error {
 | 
					func (m *VaultResponse) XXX_Unmarshal(b []byte) error {
 | 
				
			||||||
	return m.Unmarshal(b)
 | 
						return m.Unmarshal(b)
 | 
				
			||||||
@ -243,8 +319,8 @@ var xxx_messageInfo_VaultResponse proto.InternalMessageInfo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// QueryDepositsRequest is the request type for the Query/Deposits RPC method.
 | 
					// QueryDepositsRequest is the request type for the Query/Deposits RPC method.
 | 
				
			||||||
type QueryDepositsRequest struct {
 | 
					type QueryDepositsRequest struct {
 | 
				
			||||||
	// owner optionally filters deposits by owner
 | 
						// depositor optionally filters deposits by depositor
 | 
				
			||||||
	Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"`
 | 
						Depositor string `protobuf:"bytes,1,opt,name=depositor,proto3" json:"depositor,omitempty"`
 | 
				
			||||||
	// denom optionally filters deposits by vault denom
 | 
						// denom optionally filters deposits by vault denom
 | 
				
			||||||
	Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"`
 | 
						Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"`
 | 
				
			||||||
	// pagination defines an optional pagination for the request.
 | 
						// pagination defines an optional pagination for the request.
 | 
				
			||||||
@ -255,7 +331,7 @@ func (m *QueryDepositsRequest) Reset()         { *m = QueryDepositsRequest{} }
 | 
				
			|||||||
func (m *QueryDepositsRequest) String() string { return proto.CompactTextString(m) }
 | 
					func (m *QueryDepositsRequest) String() string { return proto.CompactTextString(m) }
 | 
				
			||||||
func (*QueryDepositsRequest) ProtoMessage()    {}
 | 
					func (*QueryDepositsRequest) ProtoMessage()    {}
 | 
				
			||||||
func (*QueryDepositsRequest) Descriptor() ([]byte, []int) {
 | 
					func (*QueryDepositsRequest) Descriptor() ([]byte, []int) {
 | 
				
			||||||
	return fileDescriptor_63f8dee2f3192a6b, []int{5}
 | 
						return fileDescriptor_63f8dee2f3192a6b, []int{7}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (m *QueryDepositsRequest) XXX_Unmarshal(b []byte) error {
 | 
					func (m *QueryDepositsRequest) XXX_Unmarshal(b []byte) error {
 | 
				
			||||||
	return m.Unmarshal(b)
 | 
						return m.Unmarshal(b)
 | 
				
			||||||
@ -296,7 +372,7 @@ func (m *QueryDepositsResponse) Reset()         { *m = QueryDepositsResponse{} }
 | 
				
			|||||||
func (m *QueryDepositsResponse) String() string { return proto.CompactTextString(m) }
 | 
					func (m *QueryDepositsResponse) String() string { return proto.CompactTextString(m) }
 | 
				
			||||||
func (*QueryDepositsResponse) ProtoMessage()    {}
 | 
					func (*QueryDepositsResponse) ProtoMessage()    {}
 | 
				
			||||||
func (*QueryDepositsResponse) Descriptor() ([]byte, []int) {
 | 
					func (*QueryDepositsResponse) Descriptor() ([]byte, []int) {
 | 
				
			||||||
	return fileDescriptor_63f8dee2f3192a6b, []int{6}
 | 
						return fileDescriptor_63f8dee2f3192a6b, []int{8}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (m *QueryDepositsResponse) XXX_Unmarshal(b []byte) error {
 | 
					func (m *QueryDepositsResponse) XXX_Unmarshal(b []byte) error {
 | 
				
			||||||
	return m.Unmarshal(b)
 | 
						return m.Unmarshal(b)
 | 
				
			||||||
@ -341,7 +417,7 @@ func (m *DepositResponse) Reset()         { *m = DepositResponse{} }
 | 
				
			|||||||
func (m *DepositResponse) String() string { return proto.CompactTextString(m) }
 | 
					func (m *DepositResponse) String() string { return proto.CompactTextString(m) }
 | 
				
			||||||
func (*DepositResponse) ProtoMessage()    {}
 | 
					func (*DepositResponse) ProtoMessage()    {}
 | 
				
			||||||
func (*DepositResponse) Descriptor() ([]byte, []int) {
 | 
					func (*DepositResponse) Descriptor() ([]byte, []int) {
 | 
				
			||||||
	return fileDescriptor_63f8dee2f3192a6b, []int{7}
 | 
						return fileDescriptor_63f8dee2f3192a6b, []int{9}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (m *DepositResponse) XXX_Unmarshal(b []byte) error {
 | 
					func (m *DepositResponse) XXX_Unmarshal(b []byte) error {
 | 
				
			||||||
	return m.Unmarshal(b)
 | 
						return m.Unmarshal(b)
 | 
				
			||||||
@ -375,6 +451,8 @@ func init() {
 | 
				
			|||||||
	proto.RegisterType((*QueryParamsResponse)(nil), "kava.earn.v1beta1.QueryParamsResponse")
 | 
						proto.RegisterType((*QueryParamsResponse)(nil), "kava.earn.v1beta1.QueryParamsResponse")
 | 
				
			||||||
	proto.RegisterType((*QueryVaultsRequest)(nil), "kava.earn.v1beta1.QueryVaultsRequest")
 | 
						proto.RegisterType((*QueryVaultsRequest)(nil), "kava.earn.v1beta1.QueryVaultsRequest")
 | 
				
			||||||
	proto.RegisterType((*QueryVaultsResponse)(nil), "kava.earn.v1beta1.QueryVaultsResponse")
 | 
						proto.RegisterType((*QueryVaultsResponse)(nil), "kava.earn.v1beta1.QueryVaultsResponse")
 | 
				
			||||||
 | 
						proto.RegisterType((*QueryVaultRequest)(nil), "kava.earn.v1beta1.QueryVaultRequest")
 | 
				
			||||||
 | 
						proto.RegisterType((*QueryVaultResponse)(nil), "kava.earn.v1beta1.QueryVaultResponse")
 | 
				
			||||||
	proto.RegisterType((*VaultResponse)(nil), "kava.earn.v1beta1.VaultResponse")
 | 
						proto.RegisterType((*VaultResponse)(nil), "kava.earn.v1beta1.VaultResponse")
 | 
				
			||||||
	proto.RegisterType((*QueryDepositsRequest)(nil), "kava.earn.v1beta1.QueryDepositsRequest")
 | 
						proto.RegisterType((*QueryDepositsRequest)(nil), "kava.earn.v1beta1.QueryDepositsRequest")
 | 
				
			||||||
	proto.RegisterType((*QueryDepositsResponse)(nil), "kava.earn.v1beta1.QueryDepositsResponse")
 | 
						proto.RegisterType((*QueryDepositsResponse)(nil), "kava.earn.v1beta1.QueryDepositsResponse")
 | 
				
			||||||
@ -384,59 +462,61 @@ func init() {
 | 
				
			|||||||
func init() { proto.RegisterFile("kava/earn/v1beta1/query.proto", fileDescriptor_63f8dee2f3192a6b) }
 | 
					func init() { proto.RegisterFile("kava/earn/v1beta1/query.proto", fileDescriptor_63f8dee2f3192a6b) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var fileDescriptor_63f8dee2f3192a6b = []byte{
 | 
					var fileDescriptor_63f8dee2f3192a6b = []byte{
 | 
				
			||||||
	// 825 bytes of a gzipped FileDescriptorProto
 | 
						// 855 bytes of a gzipped FileDescriptorProto
 | 
				
			||||||
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0xbf, 0x4f, 0x1b, 0x49,
 | 
						0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcd, 0x4f, 0x1b, 0x47,
 | 
				
			||||||
	0x14, 0xf6, 0xda, 0xd8, 0x82, 0xf1, 0xc1, 0x1d, 0x83, 0x4f, 0xb2, 0xcd, 0xb1, 0x36, 0x8b, 0x0e,
 | 
						0x14, 0xf7, 0xda, 0xd8, 0x82, 0x71, 0xa1, 0xf5, 0xe0, 0x4a, 0xb6, 0x29, 0x6b, 0xb3, 0x14, 0x58,
 | 
				
			||||||
	0xf6, 0x90, 0xbc, 0x7b, 0xf8, 0xa4, 0x4b, 0x13, 0x45, 0x8a, 0x83, 0x82, 0x48, 0x11, 0x91, 0x25,
 | 
						0x2a, 0x79, 0xb7, 0xb8, 0x52, 0x7b, 0x41, 0x95, 0xea, 0xa2, 0x22, 0x7a, 0xa8, 0xe8, 0xd2, 0x72,
 | 
				
			||||||
	0xa1, 0x88, 0x14, 0x59, 0x63, 0x3c, 0x5a, 0x56, 0xd8, 0x3b, 0x66, 0x67, 0x6c, 0x42, 0xa2, 0x34,
 | 
						0xa8, 0x54, 0x59, 0x63, 0x3c, 0x5a, 0x56, 0xd8, 0x3b, 0x66, 0x67, 0xec, 0x96, 0x56, 0x51, 0x24,
 | 
				
			||||||
	0xf4, 0x91, 0x22, 0xe5, 0x5f, 0x88, 0x52, 0x50, 0xf3, 0x47, 0x50, 0x22, 0xd2, 0x44, 0x29, 0x20,
 | 
						0xa4, 0xdc, 0x23, 0xe5, 0x7f, 0xc8, 0x01, 0xe5, 0xc8, 0x1f, 0xc1, 0x11, 0x91, 0x4b, 0x94, 0x03,
 | 
				
			||||||
	0x81, 0xd4, 0xa9, 0x53, 0x46, 0xf3, 0x63, 0xfd, 0xdb, 0x71, 0x2a, 0xd8, 0x79, 0xef, 0x7d, 0xdf,
 | 
						0x24, 0x90, 0x73, 0xce, 0x39, 0x46, 0xf3, 0xb1, 0xfe, 0x36, 0x46, 0x39, 0xc1, 0xbe, 0x8f, 0xdf,
 | 
				
			||||||
	0xf7, 0xde, 0x7c, 0xf3, 0x0c, 0x16, 0xf6, 0x51, 0x0b, 0xd9, 0x18, 0x05, 0xbe, 0xdd, 0x5a, 0xab,
 | 
						0xef, 0xf7, 0xde, 0xbc, 0xf7, 0x0c, 0x16, 0x8f, 0x50, 0x1b, 0xd9, 0x18, 0x05, 0xbe, 0xdd, 0xde,
 | 
				
			||||||
	0x60, 0x86, 0xd6, 0xec, 0x83, 0x26, 0x0e, 0x8e, 0xac, 0x46, 0x40, 0x18, 0x81, 0xb3, 0x3c, 0x6c,
 | 
						0xa8, 0x62, 0x86, 0x36, 0xec, 0xe3, 0x16, 0x0e, 0x4e, 0xac, 0x66, 0x40, 0x18, 0x81, 0x29, 0xee,
 | 
				
			||||||
	0xf1, 0xb0, 0xa5, 0xc2, 0xd9, 0xcc, 0x2e, 0xa1, 0x75, 0x42, 0xcb, 0x22, 0xc1, 0x96, 0x1f, 0x32,
 | 
						0xb6, 0xb8, 0xdb, 0x52, 0xee, 0x5c, 0xf6, 0x80, 0xd0, 0x06, 0xa1, 0x15, 0x11, 0x60, 0xcb, 0x0f,
 | 
				
			||||||
	0x3b, 0xbb, 0x2a, 0xbf, 0xec, 0x0a, 0xa2, 0x58, 0xc2, 0xb4, 0x41, 0x1b, 0xc8, 0xf5, 0x7c, 0xc4,
 | 
						0x19, 0x9d, 0xfb, 0x46, 0x7e, 0xd9, 0x55, 0x44, 0xb1, 0x84, 0xe9, 0x80, 0x36, 0x91, 0xeb, 0xf9,
 | 
				
			||||||
	0x3c, 0xe2, 0xab, 0x5c, 0xbd, 0x3b, 0x37, 0xcc, 0xda, 0x25, 0x5e, 0x18, 0x4f, 0xb9, 0xc4, 0x25,
 | 
						0x88, 0x79, 0xc4, 0x57, 0xb1, 0x7a, 0x6f, 0x6c, 0x18, 0x75, 0x40, 0xbc, 0xd0, 0x9f, 0x76, 0x89,
 | 
				
			||||||
	0x92, 0x83, 0xff, 0xa7, 0x4e, 0xff, 0x72, 0x09, 0x71, 0x6b, 0xd8, 0x46, 0x0d, 0xcf, 0x46, 0xbe,
 | 
						0x4b, 0x24, 0x07, 0xff, 0x4f, 0x59, 0xbf, 0x72, 0x09, 0x71, 0xeb, 0xd8, 0x46, 0x4d, 0xcf, 0x46,
 | 
				
			||||||
	0x4f, 0x98, 0x80, 0x0c, 0xf9, 0xf5, 0xc1, 0x66, 0x1a, 0x28, 0x40, 0xf5, 0x30, 0x9e, 0x1f, 0x8c,
 | 
						0xbe, 0x4f, 0x98, 0x80, 0x0c, 0xf9, 0xf5, 0xe1, 0x62, 0x9a, 0x28, 0x40, 0x8d, 0xd0, 0x5f, 0x18,
 | 
				
			||||||
	0x53, 0x16, 0x20, 0x86, 0x5d, 0xd5, 0x6f, 0x76, 0xc8, 0x38, 0x5a, 0xa8, 0x59, 0x63, 0x32, 0x6c,
 | 
						0xf6, 0x53, 0x16, 0x20, 0x86, 0x5d, 0x55, 0x6f, 0x6e, 0x44, 0x3b, 0xda, 0xa8, 0x55, 0x67, 0xd2,
 | 
				
			||||||
	0xa4, 0x00, 0x7c, 0xc4, 0xdb, 0xda, 0x12, 0xa8, 0x0e, 0x3e, 0x68, 0x62, 0xca, 0x8c, 0x87, 0x60,
 | 
						0x6d, 0xa4, 0x01, 0xfc, 0x9d, 0x97, 0xb5, 0x2b, 0x50, 0x1d, 0x7c, 0xdc, 0xc2, 0x94, 0x19, 0xbf,
 | 
				
			||||||
	0xae, 0xe7, 0x94, 0x36, 0x88, 0x4f, 0x31, 0xbc, 0x05, 0x12, 0x92, 0x3d, 0xad, 0xe5, 0x35, 0x33,
 | 
						0x81, 0xf9, 0x3e, 0x2b, 0x6d, 0x12, 0x9f, 0x62, 0xf8, 0x03, 0x48, 0x48, 0xf6, 0x8c, 0x56, 0xd0,
 | 
				
			||||||
	0x59, 0xcc, 0x58, 0x03, 0xc3, 0xb4, 0x64, 0x49, 0x69, 0xe2, 0xec, 0x32, 0x17, 0x71, 0x54, 0xba,
 | 
						0xcc, 0x64, 0x29, 0x6b, 0x0d, 0x35, 0xd3, 0x92, 0x29, 0xe5, 0xa9, 0x8b, 0xeb, 0x7c, 0xc4, 0x51,
 | 
				
			||||||
	0xb1, 0xaa, 0x58, 0x76, 0x38, 0x73, 0xc8, 0x02, 0x53, 0x20, 0x5e, 0xc5, 0x3e, 0xa9, 0x0b, 0xb4,
 | 
						0xe1, 0x1d, 0x96, 0x7d, 0xce, 0xdc, 0x61, 0xf9, 0x53, 0xb1, 0x84, 0x56, 0xc5, 0xf2, 0x23, 0x48,
 | 
				
			||||||
	0x29, 0x47, 0x7e, 0x18, 0x4f, 0x14, 0x77, 0x98, 0xab, 0xb8, 0xef, 0x80, 0x84, 0xd0, 0xcd, 0xb9,
 | 
						0x08, 0x85, 0x9c, 0x25, 0x66, 0x26, 0x4b, 0x85, 0x11, 0x2c, 0x22, 0x25, 0xcc, 0x08, 0xc9, 0x64,
 | 
				
			||||||
	0x63, 0x66, 0xb2, 0x98, 0x1f, 0xc2, 0x2d, 0x4a, 0xc2, 0x8a, 0x50, 0x82, 0xac, 0x32, 0xbe, 0x45,
 | 
						0x96, 0xb1, 0x0e, 0x52, 0x5d, 0x58, 0xc5, 0x05, 0xd3, 0x20, 0x5e, 0xc3, 0x3e, 0x69, 0x08, 0xe5,
 | 
				
			||||||
	0xc1, 0x74, 0x4f, 0x7c, 0x38, 0x3d, 0x74, 0x00, 0x50, 0x13, 0xf4, 0x30, 0x4d, 0x47, 0xf3, 0x31,
 | 
						0x33, 0x8e, 0xfc, 0x30, 0x9c, 0x5e, 0x5d, 0x1d, 0x01, 0x9b, 0x20, 0x2e, 0xa0, 0x54, 0x95, 0x0f,
 | 
				
			||||||
	0x73, 0xa6, 0x98, 0x1b, 0xc2, 0xb5, 0xad, 0xc6, 0xfc, 0xf8, 0xa8, 0x81, 0x4b, 0xb3, 0x27, 0x57,
 | 
						0xe5, 0x97, 0x49, 0xc6, 0xfb, 0x28, 0x98, 0xed, 0xc7, 0x1b, 0xc9, 0x0d, 0x1d, 0x00, 0xd4, 0x53,
 | 
				
			||||||
	0xb9, 0xe9, 0xee, 0x13, 0xea, 0x74, 0xa1, 0x40, 0x13, 0xfc, 0xe1, 0x71, 0x7b, 0x79, 0x2d, 0xc4,
 | 
						0x79, 0x98, 0x66, 0xa2, 0x85, 0x98, 0x39, 0x57, 0xca, 0x8f, 0xa0, 0xda, 0x53, 0xef, 0xf9, 0xc7,
 | 
				
			||||||
	0x70, 0x59, 0x08, 0x4a, 0xc7, 0xf2, 0x9a, 0x39, 0xe9, 0xcc, 0x78, 0x74, 0x4b, 0x1e, 0x0b, 0x6d,
 | 
						0x49, 0x13, 0x97, 0x53, 0x67, 0x37, 0xf9, 0xd9, 0x5e, 0x0b, 0x75, 0x7a, 0x50, 0xa0, 0x09, 0xbe,
 | 
				
			||||||
	0x70, 0x03, 0x40, 0x54, 0xab, 0x91, 0x43, 0x5c, 0x2d, 0x57, 0x71, 0x83, 0x50, 0x8f, 0x91, 0x80,
 | 
						0xf0, 0xf8, 0x1c, 0x7b, 0x6d, 0xc4, 0x70, 0x45, 0x16, 0x11, 0x2b, 0x68, 0xe6, 0xb4, 0x33, 0xe7,
 | 
				
			||||||
	0xa6, 0x27, 0xf2, 0x31, 0x73, 0xaa, 0x94, 0xbe, 0x38, 0x2d, 0xa4, 0x94, 0x3b, 0xef, 0x56, 0xab,
 | 
						0xd1, 0x5d, 0x69, 0x16, 0xda, 0xe0, 0x36, 0x80, 0xa8, 0x5e, 0x27, 0xff, 0xe0, 0x5a, 0xa5, 0x86,
 | 
				
			||||||
	0x01, 0xa6, 0x74, 0x9b, 0x05, 0x9e, 0xef, 0x3a, 0xb3, 0xaa, 0x66, 0xbd, 0x5d, 0x02, 0x17, 0xc1,
 | 
						0x9b, 0x84, 0x7a, 0x8c, 0x04, 0x34, 0x33, 0x55, 0x88, 0x99, 0x33, 0xe5, 0xcc, 0xd5, 0x79, 0x31,
 | 
				
			||||||
	0x6f, 0x8c, 0x30, 0x54, 0x2b, 0xd3, 0x3d, 0x14, 0x60, 0x9a, 0x8e, 0x8b, 0x1e, 0x93, 0xe2, 0x6c,
 | 
						0xad, 0xd6, 0xe0, 0xa7, 0x5a, 0x2d, 0xc0, 0x94, 0xee, 0xb1, 0xc0, 0xf3, 0x5d, 0x27, 0xa5, 0x72,
 | 
				
			||||||
	0x5b, 0x1c, 0xc1, 0x67, 0x40, 0x7e, 0x96, 0x5b, 0xa8, 0xd6, 0xc4, 0xe9, 0x04, 0xcf, 0x28, 0xdd,
 | 
						0xb6, 0x3a, 0x29, 0x70, 0x09, 0x7c, 0xc6, 0x08, 0x43, 0xf5, 0x0a, 0x3d, 0x44, 0x01, 0xa6, 0x99,
 | 
				
			||||||
	0xe6, 0x43, 0xfb, 0x74, 0x99, 0x5b, 0x76, 0x3d, 0xb6, 0xd7, 0xac, 0x58, 0xbb, 0xa4, 0xae, 0x5e,
 | 
						0xb8, 0xa8, 0x31, 0x29, 0x6c, 0x7b, 0xc2, 0x04, 0xff, 0x06, 0xf2, 0xb3, 0xd2, 0x46, 0xf5, 0x16,
 | 
				
			||||||
	0x84, 0xfa, 0x53, 0xa0, 0xd5, 0x7d, 0x9b, 0xf1, 0x16, 0xad, 0x4d, 0x9f, 0x5d, 0x9c, 0x16, 0x80,
 | 
						0xce, 0x24, 0x78, 0x44, 0x79, 0x93, 0xf7, 0xec, 0xf5, 0x75, 0x7e, 0xd5, 0xf5, 0xd8, 0x61, 0xab,
 | 
				
			||||||
	0x92, 0xb4, 0xe9, 0x33, 0x07, 0x08, 0xc0, 0x1d, 0x8e, 0x67, 0xbc, 0xd3, 0x40, 0x4a, 0x5c, 0xa4,
 | 
						0x6a, 0x1d, 0x90, 0x86, 0x5a, 0x3d, 0xf5, 0xa7, 0x48, 0x6b, 0x47, 0x36, 0xe3, 0x25, 0x5a, 0x3b,
 | 
				
			||||||
	0x52, 0xd5, 0xbe, 0x76, 0x0b, 0xc4, 0xc9, 0xa1, 0x8f, 0x03, 0x39, 0xf7, 0x9f, 0xb4, 0x25, 0xd3,
 | 
						0x3e, 0xbb, 0x3a, 0x2f, 0x02, 0x25, 0x69, 0xc7, 0x67, 0x0e, 0x10, 0x80, 0xfb, 0x1c, 0xcf, 0x78,
 | 
				
			||||||
	0x3a, 0xf7, 0x14, 0xed, 0xbe, 0xa7, 0xfb, 0x00, 0x74, 0x5e, 0xa0, 0x98, 0x66, 0xb2, 0xb8, 0x6c,
 | 
						0xa1, 0x81, 0xb4, 0x78, 0x45, 0xa5, 0x2a, 0x9c, 0x2f, 0xf8, 0x3d, 0x98, 0xe9, 0xd4, 0x26, 0x7b,
 | 
				
			||||||
	0x29, 0x1c, 0xfe, 0x04, 0x2d, 0xf9, 0xea, 0x3b, 0xbe, 0x74, 0xb1, 0x52, 0xe0, 0x74, 0x55, 0x1a,
 | 
						0x7f, 0x4f, 0x69, 0xdd, 0xd0, 0xee, 0x7b, 0x45, 0x7b, 0xdf, 0xeb, 0x17, 0x00, 0xba, 0x2b, 0x2f,
 | 
				
			||||||
	0xef, 0x35, 0xf0, 0x67, 0x9f, 0x4c, 0xe5, 0x8f, 0x75, 0x30, 0xa9, 0xee, 0x20, 0xf4, 0x9c, 0x31,
 | 
						0xba, 0x9a, 0x2c, 0xad, 0x5a, 0x0a, 0x8b, 0xef, 0xbc, 0x25, 0xcf, 0x4c, 0x77, 0x11, 0x5c, 0xac,
 | 
				
			||||||
	0xc4, 0x07, 0xaa, 0xac, 0xcf, 0x75, 0xed, 0x4a, 0xb8, 0xd1, 0xa3, 0x33, 0x2a, 0x74, 0xae, 0x8c,
 | 
						0x94, 0x38, 0x3d, 0x99, 0xc6, 0x73, 0x0d, 0x7c, 0x39, 0x20, 0x57, 0xcd, 0xc9, 0x16, 0x98, 0x56,
 | 
				
			||||||
	0xd5, 0x29, 0xc1, 0x7a, 0x84, 0x7e, 0xd7, 0xc0, 0xef, 0x7d, 0x64, 0xf0, 0x7f, 0x30, 0xd5, 0xb6,
 | 
						0x22, 0xc2, 0xd1, 0x37, 0x46, 0xcc, 0x83, 0x4a, 0x1b, 0x18, 0xbe, 0x4e, 0x26, 0xdc, 0xee, 0xd3,
 | 
				
			||||||
	0xc9, 0xd8, 0x71, 0x76, 0x52, 0xe1, 0x03, 0x90, 0x50, 0xbe, 0x88, 0x8a, 0xc6, 0x16, 0x46, 0x3d,
 | 
						0x19, 0x15, 0x3a, 0xd7, 0x26, 0xea, 0x94, 0x60, 0x7d, 0x42, 0x3f, 0x68, 0xe0, 0xf3, 0x01, 0xb2,
 | 
				
			||||||
	0x26, 0x61, 0x95, 0xd2, 0x1c, 0xef, 0xe9, 0xe4, 0x2a, 0x97, 0xec, 0x9c, 0x51, 0x47, 0x21, 0x40,
 | 
						0x4f, 0x6e, 0xe9, 0xaf, 0x20, 0xa1, 0xe6, 0x23, 0x2a, 0x0a, 0x5b, 0x1c, 0xb7, 0x53, 0x62, 0x64,
 | 
				
			||||||
	0x04, 0xe2, 0xd2, 0x40, 0x31, 0x01, 0x95, 0xe9, 0xe9, 0x2d, 0x04, 0xbb, 0x47, 0x3c, 0xbf, 0xf4,
 | 
						0xca, 0xf3, 0xbc, 0xa6, 0xb3, 0x9b, 0x7c, 0xb2, 0x6b, 0xa3, 0x8e, 0x42, 0x80, 0x88, 0xaf, 0x27,
 | 
				
			||||||
	0xaf, 0x82, 0x31, 0x7f, 0xc1, 0x5b, 0xbc, 0x80, 0x3a, 0x12, 0xb9, 0xf8, 0x3a, 0x06, 0xe2, 0xe2,
 | 
						0x1f, 0xa4, 0x98, 0x80, 0xca, 0xf6, 0xd5, 0x16, 0x82, 0xfd, 0x4c, 0x3c, 0xbf, 0xfc, 0xad, 0x82,
 | 
				
			||||||
	0x8e, 0xe0, 0x0b, 0x90, 0x90, 0x0b, 0x06, 0xfe, 0x3d, 0x44, 0xf2, 0xe0, 0x26, 0xcb, 0x2e, 0x8f,
 | 
						0x31, 0x1f, 0x30, 0x63, 0x3c, 0x81, 0x3a, 0x12, 0xb9, 0xf4, 0x64, 0x0a, 0xc4, 0xc5, 0x1b, 0xc1,
 | 
				
			||||||
	0x4b, 0x93, 0x93, 0x34, 0x16, 0x8f, 0x3f, 0x7c, 0x7d, 0x1b, 0x9d, 0x87, 0x19, 0x7b, 0xd4, 0xc6,
 | 
						0xff, 0x40, 0x42, 0x5e, 0x34, 0xb8, 0x32, 0x42, 0xf2, 0xf0, 0xe9, 0xcc, 0xad, 0x4e, 0x0a, 0x93,
 | 
				
			||||||
	0x85, 0xc7, 0x1a, 0x48, 0xc8, 0xa5, 0x34, 0x9a, 0xbc, 0x67, 0xc1, 0x8d, 0x26, 0xef, 0xdd, 0x6d,
 | 
						0x9d, 0x34, 0x96, 0x4e, 0x5f, 0xbe, 0x7b, 0x16, 0x5d, 0x80, 0x59, 0x7b, 0xdc, 0x89, 0xe7, 0xdc,
 | 
				
			||||||
	0xc6, 0x3f, 0x82, 0x7c, 0x09, 0x2e, 0xda, 0x23, 0x96, 0x35, 0xb5, 0x5f, 0x0a, 0xd7, 0xbf, 0xe2,
 | 
						0xf2, 0x34, 0x8e, 0xe7, 0xee, 0x3b, 0xa8, 0xe3, 0xb9, 0xfb, 0x2f, 0xec, 0xbd, 0xdc, 0xf2, 0x88,
 | 
				
			||||||
	0x22, 0x26, 0x43, 0xa7, 0xc2, 0x95, 0x51, 0xf8, 0x7d, 0x4f, 0x2e, 0x6b, 0x8e, 0x4f, 0x54, 0x52,
 | 
						0xc2, 0xc7, 0x20, 0x2e, 0x0f, 0xc5, 0xd7, 0xf7, 0x62, 0x86, 0xcc, 0x2b, 0x13, 0xa2, 0x14, 0xf1,
 | 
				
			||||||
	0x96, 0x84, 0x94, 0x05, 0x38, 0x3f, 0x44, 0x4a, 0xe8, 0xe9, 0xd2, 0xfa, 0xd9, 0x17, 0x3d, 0x72,
 | 
						0xba, 0x20, 0x5e, 0x86, 0x4b, 0x63, 0x89, 0xed, 0xff, 0xc5, 0xb6, 0x3d, 0x82, 0xa7, 0x1a, 0x98,
 | 
				
			||||||
	0x76, 0xad, 0x6b, 0xe7, 0xd7, 0xba, 0xf6, 0xf9, 0x5a, 0xd7, 0xde, 0xdc, 0xe8, 0x91, 0xf3, 0x1b,
 | 
						0x0e, 0x37, 0x04, 0xae, 0x8d, 0x83, 0x1f, 0x58, 0xf9, 0x9c, 0x39, 0x39, 0x50, 0x49, 0x59, 0x16,
 | 
				
			||||||
	0x3d, 0xf2, 0xf1, 0x46, 0x8f, 0x3c, 0xed, 0x5e, 0x1d, 0x1c, 0xa4, 0x50, 0x43, 0x15, 0x2a, 0xe1,
 | 
						0x52, 0x16, 0xe1, 0xc2, 0x08, 0x29, 0xe1, 0x2e, 0x95, 0xb7, 0x2e, 0xde, 0xea, 0x91, 0x8b, 0x5b,
 | 
				
			||||||
	0x9e, 0x4b, 0x40, 0x71, 0xc5, 0x95, 0x84, 0xf8, 0x05, 0xfa, 0xef, 0x47, 0x00, 0x00, 0x00, 0xff,
 | 
						0x5d, 0xbb, 0xbc, 0xd5, 0xb5, 0x37, 0xb7, 0xba, 0xf6, 0xf4, 0x4e, 0x8f, 0x5c, 0xde, 0xe9, 0x91,
 | 
				
			||||||
	0xff, 0xa7, 0x27, 0xb6, 0xa1, 0xb1, 0x07, 0x00, 0x00,
 | 
						0x57, 0x77, 0x7a, 0xe4, 0xaf, 0xde, 0xd3, 0xc5, 0x41, 0x8a, 0x75, 0x54, 0xa5, 0x12, 0xee, 0x5f,
 | 
				
			||||||
 | 
						0x09, 0x28, 0x46, 0xab, 0x9a, 0x10, 0x3f, 0xb5, 0xdf, 0x7d, 0x0c, 0x00, 0x00, 0xff, 0xff, 0xf4,
 | 
				
			||||||
 | 
						0x79, 0x11, 0x40, 0x9a, 0x08, 0x00, 0x00,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Reference imports to suppress errors if they are not otherwise used.
 | 
					// Reference imports to suppress errors if they are not otherwise used.
 | 
				
			||||||
@ -453,9 +533,11 @@ const _ = grpc.SupportPackageIsVersion4
 | 
				
			|||||||
type QueryClient interface {
 | 
					type QueryClient interface {
 | 
				
			||||||
	// Params queries all parameters of the earn module.
 | 
						// Params queries all parameters of the earn module.
 | 
				
			||||||
	Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error)
 | 
						Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error)
 | 
				
			||||||
	// Vaults queries vaults based on vault denom
 | 
						// Vaults queries all vaults
 | 
				
			||||||
	Vaults(ctx context.Context, in *QueryVaultsRequest, opts ...grpc.CallOption) (*QueryVaultsResponse, error)
 | 
						Vaults(ctx context.Context, in *QueryVaultsRequest, opts ...grpc.CallOption) (*QueryVaultsResponse, error)
 | 
				
			||||||
	// Deposits queries deposit details based on owner address and vault
 | 
						// Vault queries a single vault based on the vault denom
 | 
				
			||||||
 | 
						Vault(ctx context.Context, in *QueryVaultRequest, opts ...grpc.CallOption) (*QueryVaultResponse, error)
 | 
				
			||||||
 | 
						// Deposits queries deposit details based on depositor address and vault
 | 
				
			||||||
	Deposits(ctx context.Context, in *QueryDepositsRequest, opts ...grpc.CallOption) (*QueryDepositsResponse, error)
 | 
						Deposits(ctx context.Context, in *QueryDepositsRequest, opts ...grpc.CallOption) (*QueryDepositsResponse, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -485,6 +567,15 @@ func (c *queryClient) Vaults(ctx context.Context, in *QueryVaultsRequest, opts .
 | 
				
			|||||||
	return out, nil
 | 
						return out, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *queryClient) Vault(ctx context.Context, in *QueryVaultRequest, opts ...grpc.CallOption) (*QueryVaultResponse, error) {
 | 
				
			||||||
 | 
						out := new(QueryVaultResponse)
 | 
				
			||||||
 | 
						err := c.cc.Invoke(ctx, "/kava.earn.v1beta1.Query/Vault", in, out, opts...)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return out, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *queryClient) Deposits(ctx context.Context, in *QueryDepositsRequest, opts ...grpc.CallOption) (*QueryDepositsResponse, error) {
 | 
					func (c *queryClient) Deposits(ctx context.Context, in *QueryDepositsRequest, opts ...grpc.CallOption) (*QueryDepositsResponse, error) {
 | 
				
			||||||
	out := new(QueryDepositsResponse)
 | 
						out := new(QueryDepositsResponse)
 | 
				
			||||||
	err := c.cc.Invoke(ctx, "/kava.earn.v1beta1.Query/Deposits", in, out, opts...)
 | 
						err := c.cc.Invoke(ctx, "/kava.earn.v1beta1.Query/Deposits", in, out, opts...)
 | 
				
			||||||
@ -498,9 +589,11 @@ func (c *queryClient) Deposits(ctx context.Context, in *QueryDepositsRequest, op
 | 
				
			|||||||
type QueryServer interface {
 | 
					type QueryServer interface {
 | 
				
			||||||
	// Params queries all parameters of the earn module.
 | 
						// Params queries all parameters of the earn module.
 | 
				
			||||||
	Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error)
 | 
						Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error)
 | 
				
			||||||
	// Vaults queries vaults based on vault denom
 | 
						// Vaults queries all vaults
 | 
				
			||||||
	Vaults(context.Context, *QueryVaultsRequest) (*QueryVaultsResponse, error)
 | 
						Vaults(context.Context, *QueryVaultsRequest) (*QueryVaultsResponse, error)
 | 
				
			||||||
	// Deposits queries deposit details based on owner address and vault
 | 
						// Vault queries a single vault based on the vault denom
 | 
				
			||||||
 | 
						Vault(context.Context, *QueryVaultRequest) (*QueryVaultResponse, error)
 | 
				
			||||||
 | 
						// Deposits queries deposit details based on depositor address and vault
 | 
				
			||||||
	Deposits(context.Context, *QueryDepositsRequest) (*QueryDepositsResponse, error)
 | 
						Deposits(context.Context, *QueryDepositsRequest) (*QueryDepositsResponse, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -514,6 +607,9 @@ func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsReq
 | 
				
			|||||||
func (*UnimplementedQueryServer) Vaults(ctx context.Context, req *QueryVaultsRequest) (*QueryVaultsResponse, error) {
 | 
					func (*UnimplementedQueryServer) Vaults(ctx context.Context, req *QueryVaultsRequest) (*QueryVaultsResponse, error) {
 | 
				
			||||||
	return nil, status.Errorf(codes.Unimplemented, "method Vaults not implemented")
 | 
						return nil, status.Errorf(codes.Unimplemented, "method Vaults not implemented")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					func (*UnimplementedQueryServer) Vault(ctx context.Context, req *QueryVaultRequest) (*QueryVaultResponse, error) {
 | 
				
			||||||
 | 
						return nil, status.Errorf(codes.Unimplemented, "method Vault not implemented")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
func (*UnimplementedQueryServer) Deposits(ctx context.Context, req *QueryDepositsRequest) (*QueryDepositsResponse, error) {
 | 
					func (*UnimplementedQueryServer) Deposits(ctx context.Context, req *QueryDepositsRequest) (*QueryDepositsResponse, error) {
 | 
				
			||||||
	return nil, status.Errorf(codes.Unimplemented, "method Deposits not implemented")
 | 
						return nil, status.Errorf(codes.Unimplemented, "method Deposits not implemented")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -558,6 +654,24 @@ func _Query_Vaults_Handler(srv interface{}, ctx context.Context, dec func(interf
 | 
				
			|||||||
	return interceptor(ctx, in, info, handler)
 | 
						return interceptor(ctx, in, info, handler)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func _Query_Vault_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 | 
				
			||||||
 | 
						in := new(QueryVaultRequest)
 | 
				
			||||||
 | 
						if err := dec(in); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if interceptor == nil {
 | 
				
			||||||
 | 
							return srv.(QueryServer).Vault(ctx, in)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						info := &grpc.UnaryServerInfo{
 | 
				
			||||||
 | 
							Server:     srv,
 | 
				
			||||||
 | 
							FullMethod: "/kava.earn.v1beta1.Query/Vault",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							return srv.(QueryServer).Vault(ctx, req.(*QueryVaultRequest))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return interceptor(ctx, in, info, handler)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func _Query_Deposits_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 | 
					func _Query_Deposits_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 | 
				
			||||||
	in := new(QueryDepositsRequest)
 | 
						in := new(QueryDepositsRequest)
 | 
				
			||||||
	if err := dec(in); err != nil {
 | 
						if err := dec(in); err != nil {
 | 
				
			||||||
@ -588,6 +702,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{
 | 
				
			|||||||
			MethodName: "Vaults",
 | 
								MethodName: "Vaults",
 | 
				
			||||||
			Handler:    _Query_Vaults_Handler,
 | 
								Handler:    _Query_Vaults_Handler,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								MethodName: "Vault",
 | 
				
			||||||
 | 
								Handler:    _Query_Vault_Handler,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			MethodName: "Deposits",
 | 
								MethodName: "Deposits",
 | 
				
			||||||
			Handler:    _Query_Deposits_Handler,
 | 
								Handler:    _Query_Deposits_Handler,
 | 
				
			||||||
@ -673,13 +791,6 @@ func (m *QueryVaultsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 | 
				
			|||||||
	_ = i
 | 
						_ = i
 | 
				
			||||||
	var l int
 | 
						var l int
 | 
				
			||||||
	_ = l
 | 
						_ = l
 | 
				
			||||||
	if len(m.Denom) > 0 {
 | 
					 | 
				
			||||||
		i -= len(m.Denom)
 | 
					 | 
				
			||||||
		copy(dAtA[i:], m.Denom)
 | 
					 | 
				
			||||||
		i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom)))
 | 
					 | 
				
			||||||
		i--
 | 
					 | 
				
			||||||
		dAtA[i] = 0xa
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return len(dAtA) - i, nil
 | 
						return len(dAtA) - i, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -720,6 +831,69 @@ func (m *QueryVaultsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 | 
				
			|||||||
	return len(dAtA) - i, nil
 | 
						return len(dAtA) - i, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) Marshal() (dAtA []byte, err error) {
 | 
				
			||||||
 | 
						size := m.Size()
 | 
				
			||||||
 | 
						dAtA = make([]byte, size)
 | 
				
			||||||
 | 
						n, err := m.MarshalToSizedBuffer(dAtA[:size])
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return dAtA[:n], nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) MarshalTo(dAtA []byte) (int, error) {
 | 
				
			||||||
 | 
						size := m.Size()
 | 
				
			||||||
 | 
						return m.MarshalToSizedBuffer(dAtA[:size])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 | 
				
			||||||
 | 
						i := len(dAtA)
 | 
				
			||||||
 | 
						_ = i
 | 
				
			||||||
 | 
						var l int
 | 
				
			||||||
 | 
						_ = l
 | 
				
			||||||
 | 
						if len(m.Denom) > 0 {
 | 
				
			||||||
 | 
							i -= len(m.Denom)
 | 
				
			||||||
 | 
							copy(dAtA[i:], m.Denom)
 | 
				
			||||||
 | 
							i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom)))
 | 
				
			||||||
 | 
							i--
 | 
				
			||||||
 | 
							dAtA[i] = 0xa
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return len(dAtA) - i, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) Marshal() (dAtA []byte, err error) {
 | 
				
			||||||
 | 
						size := m.Size()
 | 
				
			||||||
 | 
						dAtA = make([]byte, size)
 | 
				
			||||||
 | 
						n, err := m.MarshalToSizedBuffer(dAtA[:size])
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return dAtA[:n], nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) MarshalTo(dAtA []byte) (int, error) {
 | 
				
			||||||
 | 
						size := m.Size()
 | 
				
			||||||
 | 
						return m.MarshalToSizedBuffer(dAtA[:size])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 | 
				
			||||||
 | 
						i := len(dAtA)
 | 
				
			||||||
 | 
						_ = i
 | 
				
			||||||
 | 
						var l int
 | 
				
			||||||
 | 
						_ = l
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							size, err := m.Vault.MarshalToSizedBuffer(dAtA[:i])
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return 0, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							i -= size
 | 
				
			||||||
 | 
							i = encodeVarintQuery(dAtA, i, uint64(size))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						i--
 | 
				
			||||||
 | 
						dAtA[i] = 0xa
 | 
				
			||||||
 | 
						return len(dAtA) - i, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *VaultResponse) Marshal() (dAtA []byte, err error) {
 | 
					func (m *VaultResponse) Marshal() (dAtA []byte, err error) {
 | 
				
			||||||
	size := m.Size()
 | 
						size := m.Size()
 | 
				
			||||||
	dAtA = make([]byte, size)
 | 
						dAtA = make([]byte, size)
 | 
				
			||||||
@ -777,20 +951,20 @@ func (m *VaultResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 | 
				
			|||||||
		dAtA[i] = 0x18
 | 
							dAtA[i] = 0x18
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(m.Strategies) > 0 {
 | 
						if len(m.Strategies) > 0 {
 | 
				
			||||||
		dAtA3 := make([]byte, len(m.Strategies)*10)
 | 
							dAtA4 := make([]byte, len(m.Strategies)*10)
 | 
				
			||||||
		var j2 int
 | 
							var j3 int
 | 
				
			||||||
		for _, num := range m.Strategies {
 | 
							for _, num := range m.Strategies {
 | 
				
			||||||
			for num >= 1<<7 {
 | 
								for num >= 1<<7 {
 | 
				
			||||||
				dAtA3[j2] = uint8(uint64(num)&0x7f | 0x80)
 | 
									dAtA4[j3] = uint8(uint64(num)&0x7f | 0x80)
 | 
				
			||||||
				num >>= 7
 | 
									num >>= 7
 | 
				
			||||||
				j2++
 | 
									j3++
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			dAtA3[j2] = uint8(num)
 | 
								dAtA4[j3] = uint8(num)
 | 
				
			||||||
			j2++
 | 
								j3++
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		i -= j2
 | 
							i -= j3
 | 
				
			||||||
		copy(dAtA[i:], dAtA3[:j2])
 | 
							copy(dAtA[i:], dAtA4[:j3])
 | 
				
			||||||
		i = encodeVarintQuery(dAtA, i, uint64(j2))
 | 
							i = encodeVarintQuery(dAtA, i, uint64(j3))
 | 
				
			||||||
		i--
 | 
							i--
 | 
				
			||||||
		dAtA[i] = 0x12
 | 
							dAtA[i] = 0x12
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -843,10 +1017,10 @@ func (m *QueryDepositsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 | 
				
			|||||||
		i--
 | 
							i--
 | 
				
			||||||
		dAtA[i] = 0x12
 | 
							dAtA[i] = 0x12
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(m.Owner) > 0 {
 | 
						if len(m.Depositor) > 0 {
 | 
				
			||||||
		i -= len(m.Owner)
 | 
							i -= len(m.Depositor)
 | 
				
			||||||
		copy(dAtA[i:], m.Owner)
 | 
							copy(dAtA[i:], m.Depositor)
 | 
				
			||||||
		i = encodeVarintQuery(dAtA, i, uint64(len(m.Owner)))
 | 
							i = encodeVarintQuery(dAtA, i, uint64(len(m.Depositor)))
 | 
				
			||||||
		i--
 | 
							i--
 | 
				
			||||||
		dAtA[i] = 0xa
 | 
							dAtA[i] = 0xa
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -997,10 +1171,6 @@ func (m *QueryVaultsRequest) Size() (n int) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	var l int
 | 
						var l int
 | 
				
			||||||
	_ = l
 | 
						_ = l
 | 
				
			||||||
	l = len(m.Denom)
 | 
					 | 
				
			||||||
	if l > 0 {
 | 
					 | 
				
			||||||
		n += 1 + l + sovQuery(uint64(l))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return n
 | 
						return n
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1019,6 +1189,30 @@ func (m *QueryVaultsResponse) Size() (n int) {
 | 
				
			|||||||
	return n
 | 
						return n
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) Size() (n int) {
 | 
				
			||||||
 | 
						if m == nil {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var l int
 | 
				
			||||||
 | 
						_ = l
 | 
				
			||||||
 | 
						l = len(m.Denom)
 | 
				
			||||||
 | 
						if l > 0 {
 | 
				
			||||||
 | 
							n += 1 + l + sovQuery(uint64(l))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return n
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) Size() (n int) {
 | 
				
			||||||
 | 
						if m == nil {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var l int
 | 
				
			||||||
 | 
						_ = l
 | 
				
			||||||
 | 
						l = m.Vault.Size()
 | 
				
			||||||
 | 
						n += 1 + l + sovQuery(uint64(l))
 | 
				
			||||||
 | 
						return n
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *VaultResponse) Size() (n int) {
 | 
					func (m *VaultResponse) Size() (n int) {
 | 
				
			||||||
	if m == nil {
 | 
						if m == nil {
 | 
				
			||||||
		return 0
 | 
							return 0
 | 
				
			||||||
@ -1060,7 +1254,7 @@ func (m *QueryDepositsRequest) Size() (n int) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	var l int
 | 
						var l int
 | 
				
			||||||
	_ = l
 | 
						_ = l
 | 
				
			||||||
	l = len(m.Owner)
 | 
						l = len(m.Depositor)
 | 
				
			||||||
	if l > 0 {
 | 
						if l > 0 {
 | 
				
			||||||
		n += 1 + l + sovQuery(uint64(l))
 | 
							n += 1 + l + sovQuery(uint64(l))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -1287,38 +1481,6 @@ func (m *QueryVaultsRequest) Unmarshal(dAtA []byte) error {
 | 
				
			|||||||
			return fmt.Errorf("proto: QueryVaultsRequest: illegal tag %d (wire type %d)", fieldNum, wire)
 | 
								return fmt.Errorf("proto: QueryVaultsRequest: illegal tag %d (wire type %d)", fieldNum, wire)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		switch fieldNum {
 | 
							switch fieldNum {
 | 
				
			||||||
		case 1:
 | 
					 | 
				
			||||||
			if wireType != 2 {
 | 
					 | 
				
			||||||
				return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			var stringLen uint64
 | 
					 | 
				
			||||||
			for shift := uint(0); ; shift += 7 {
 | 
					 | 
				
			||||||
				if shift >= 64 {
 | 
					 | 
				
			||||||
					return ErrIntOverflowQuery
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if iNdEx >= l {
 | 
					 | 
				
			||||||
					return io.ErrUnexpectedEOF
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				b := dAtA[iNdEx]
 | 
					 | 
				
			||||||
				iNdEx++
 | 
					 | 
				
			||||||
				stringLen |= uint64(b&0x7F) << shift
 | 
					 | 
				
			||||||
				if b < 0x80 {
 | 
					 | 
				
			||||||
					break
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			intStringLen := int(stringLen)
 | 
					 | 
				
			||||||
			if intStringLen < 0 {
 | 
					 | 
				
			||||||
				return ErrInvalidLengthQuery
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			postIndex := iNdEx + intStringLen
 | 
					 | 
				
			||||||
			if postIndex < 0 {
 | 
					 | 
				
			||||||
				return ErrInvalidLengthQuery
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if postIndex > l {
 | 
					 | 
				
			||||||
				return io.ErrUnexpectedEOF
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			m.Denom = string(dAtA[iNdEx:postIndex])
 | 
					 | 
				
			||||||
			iNdEx = postIndex
 | 
					 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			iNdEx = preIndex
 | 
								iNdEx = preIndex
 | 
				
			||||||
			skippy, err := skipQuery(dAtA[iNdEx:])
 | 
								skippy, err := skipQuery(dAtA[iNdEx:])
 | 
				
			||||||
@ -1424,6 +1586,171 @@ func (m *QueryVaultsResponse) Unmarshal(dAtA []byte) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultRequest) Unmarshal(dAtA []byte) error {
 | 
				
			||||||
 | 
						l := len(dAtA)
 | 
				
			||||||
 | 
						iNdEx := 0
 | 
				
			||||||
 | 
						for iNdEx < l {
 | 
				
			||||||
 | 
							preIndex := iNdEx
 | 
				
			||||||
 | 
							var wire uint64
 | 
				
			||||||
 | 
							for shift := uint(0); ; shift += 7 {
 | 
				
			||||||
 | 
								if shift >= 64 {
 | 
				
			||||||
 | 
									return ErrIntOverflowQuery
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if iNdEx >= l {
 | 
				
			||||||
 | 
									return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								b := dAtA[iNdEx]
 | 
				
			||||||
 | 
								iNdEx++
 | 
				
			||||||
 | 
								wire |= uint64(b&0x7F) << shift
 | 
				
			||||||
 | 
								if b < 0x80 {
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fieldNum := int32(wire >> 3)
 | 
				
			||||||
 | 
							wireType := int(wire & 0x7)
 | 
				
			||||||
 | 
							if wireType == 4 {
 | 
				
			||||||
 | 
								return fmt.Errorf("proto: QueryVaultRequest: wiretype end group for non-group")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if fieldNum <= 0 {
 | 
				
			||||||
 | 
								return fmt.Errorf("proto: QueryVaultRequest: illegal tag %d (wire type %d)", fieldNum, wire)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							switch fieldNum {
 | 
				
			||||||
 | 
							case 1:
 | 
				
			||||||
 | 
								if wireType != 2 {
 | 
				
			||||||
 | 
									return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								var stringLen uint64
 | 
				
			||||||
 | 
								for shift := uint(0); ; shift += 7 {
 | 
				
			||||||
 | 
									if shift >= 64 {
 | 
				
			||||||
 | 
										return ErrIntOverflowQuery
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if iNdEx >= l {
 | 
				
			||||||
 | 
										return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									b := dAtA[iNdEx]
 | 
				
			||||||
 | 
									iNdEx++
 | 
				
			||||||
 | 
									stringLen |= uint64(b&0x7F) << shift
 | 
				
			||||||
 | 
									if b < 0x80 {
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								intStringLen := int(stringLen)
 | 
				
			||||||
 | 
								if intStringLen < 0 {
 | 
				
			||||||
 | 
									return ErrInvalidLengthQuery
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								postIndex := iNdEx + intStringLen
 | 
				
			||||||
 | 
								if postIndex < 0 {
 | 
				
			||||||
 | 
									return ErrInvalidLengthQuery
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if postIndex > l {
 | 
				
			||||||
 | 
									return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								m.Denom = string(dAtA[iNdEx:postIndex])
 | 
				
			||||||
 | 
								iNdEx = postIndex
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								iNdEx = preIndex
 | 
				
			||||||
 | 
								skippy, err := skipQuery(dAtA[iNdEx:])
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (skippy < 0) || (iNdEx+skippy) < 0 {
 | 
				
			||||||
 | 
									return ErrInvalidLengthQuery
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (iNdEx + skippy) > l {
 | 
				
			||||||
 | 
									return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								iNdEx += skippy
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if iNdEx > l {
 | 
				
			||||||
 | 
							return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (m *QueryVaultResponse) Unmarshal(dAtA []byte) error {
 | 
				
			||||||
 | 
						l := len(dAtA)
 | 
				
			||||||
 | 
						iNdEx := 0
 | 
				
			||||||
 | 
						for iNdEx < l {
 | 
				
			||||||
 | 
							preIndex := iNdEx
 | 
				
			||||||
 | 
							var wire uint64
 | 
				
			||||||
 | 
							for shift := uint(0); ; shift += 7 {
 | 
				
			||||||
 | 
								if shift >= 64 {
 | 
				
			||||||
 | 
									return ErrIntOverflowQuery
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if iNdEx >= l {
 | 
				
			||||||
 | 
									return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								b := dAtA[iNdEx]
 | 
				
			||||||
 | 
								iNdEx++
 | 
				
			||||||
 | 
								wire |= uint64(b&0x7F) << shift
 | 
				
			||||||
 | 
								if b < 0x80 {
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fieldNum := int32(wire >> 3)
 | 
				
			||||||
 | 
							wireType := int(wire & 0x7)
 | 
				
			||||||
 | 
							if wireType == 4 {
 | 
				
			||||||
 | 
								return fmt.Errorf("proto: QueryVaultResponse: wiretype end group for non-group")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if fieldNum <= 0 {
 | 
				
			||||||
 | 
								return fmt.Errorf("proto: QueryVaultResponse: illegal tag %d (wire type %d)", fieldNum, wire)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							switch fieldNum {
 | 
				
			||||||
 | 
							case 1:
 | 
				
			||||||
 | 
								if wireType != 2 {
 | 
				
			||||||
 | 
									return fmt.Errorf("proto: wrong wireType = %d for field Vault", wireType)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								var msglen int
 | 
				
			||||||
 | 
								for shift := uint(0); ; shift += 7 {
 | 
				
			||||||
 | 
									if shift >= 64 {
 | 
				
			||||||
 | 
										return ErrIntOverflowQuery
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if iNdEx >= l {
 | 
				
			||||||
 | 
										return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									b := dAtA[iNdEx]
 | 
				
			||||||
 | 
									iNdEx++
 | 
				
			||||||
 | 
									msglen |= int(b&0x7F) << shift
 | 
				
			||||||
 | 
									if b < 0x80 {
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if msglen < 0 {
 | 
				
			||||||
 | 
									return ErrInvalidLengthQuery
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								postIndex := iNdEx + msglen
 | 
				
			||||||
 | 
								if postIndex < 0 {
 | 
				
			||||||
 | 
									return ErrInvalidLengthQuery
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if postIndex > l {
 | 
				
			||||||
 | 
									return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if err := m.Vault.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								iNdEx = postIndex
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								iNdEx = preIndex
 | 
				
			||||||
 | 
								skippy, err := skipQuery(dAtA[iNdEx:])
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (skippy < 0) || (iNdEx+skippy) < 0 {
 | 
				
			||||||
 | 
									return ErrInvalidLengthQuery
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (iNdEx + skippy) > l {
 | 
				
			||||||
 | 
									return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								iNdEx += skippy
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if iNdEx > l {
 | 
				
			||||||
 | 
							return io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
func (m *VaultResponse) Unmarshal(dAtA []byte) error {
 | 
					func (m *VaultResponse) Unmarshal(dAtA []byte) error {
 | 
				
			||||||
	l := len(dAtA)
 | 
						l := len(dAtA)
 | 
				
			||||||
	iNdEx := 0
 | 
						iNdEx := 0
 | 
				
			||||||
@ -1724,7 +2051,7 @@ func (m *QueryDepositsRequest) Unmarshal(dAtA []byte) error {
 | 
				
			|||||||
		switch fieldNum {
 | 
							switch fieldNum {
 | 
				
			||||||
		case 1:
 | 
							case 1:
 | 
				
			||||||
			if wireType != 2 {
 | 
								if wireType != 2 {
 | 
				
			||||||
				return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType)
 | 
									return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			var stringLen uint64
 | 
								var stringLen uint64
 | 
				
			||||||
			for shift := uint(0); ; shift += 7 {
 | 
								for shift := uint(0); ; shift += 7 {
 | 
				
			||||||
@ -1752,7 +2079,7 @@ func (m *QueryDepositsRequest) Unmarshal(dAtA []byte) error {
 | 
				
			|||||||
			if postIndex > l {
 | 
								if postIndex > l {
 | 
				
			||||||
				return io.ErrUnexpectedEOF
 | 
									return io.ErrUnexpectedEOF
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			m.Owner = string(dAtA[iNdEx:postIndex])
 | 
								m.Depositor = string(dAtA[iNdEx:postIndex])
 | 
				
			||||||
			iNdEx = postIndex
 | 
								iNdEx = postIndex
 | 
				
			||||||
		case 2:
 | 
							case 2:
 | 
				
			||||||
			if wireType != 2 {
 | 
								if wireType != 2 {
 | 
				
			||||||
 | 
				
			|||||||
@ -53,24 +53,6 @@ func request_Query_Vaults_0(ctx context.Context, marshaler runtime.Marshaler, cl
 | 
				
			|||||||
	var protoReq QueryVaultsRequest
 | 
						var protoReq QueryVaultsRequest
 | 
				
			||||||
	var metadata runtime.ServerMetadata
 | 
						var metadata runtime.ServerMetadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
					 | 
				
			||||||
		val string
 | 
					 | 
				
			||||||
		ok  bool
 | 
					 | 
				
			||||||
		err error
 | 
					 | 
				
			||||||
		_   = err
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	val, ok = pathParams["denom"]
 | 
					 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protoReq.Denom, err = runtime.String(val)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msg, err := client.Vaults(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
 | 
						msg, err := client.Vaults(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
 | 
				
			||||||
	return msg, metadata, err
 | 
						return msg, metadata, err
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -80,6 +62,15 @@ func local_request_Query_Vaults_0(ctx context.Context, marshaler runtime.Marshal
 | 
				
			|||||||
	var protoReq QueryVaultsRequest
 | 
						var protoReq QueryVaultsRequest
 | 
				
			||||||
	var metadata runtime.ServerMetadata
 | 
						var metadata runtime.ServerMetadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg, err := server.Vaults(ctx, &protoReq)
 | 
				
			||||||
 | 
						return msg, metadata, err
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func request_Query_Vault_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
 | 
				
			||||||
 | 
						var protoReq QueryVaultRequest
 | 
				
			||||||
 | 
						var metadata runtime.ServerMetadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		val string
 | 
							val string
 | 
				
			||||||
		ok  bool
 | 
							ok  bool
 | 
				
			||||||
@ -98,7 +89,34 @@ func local_request_Query_Vaults_0(ctx context.Context, marshaler runtime.Marshal
 | 
				
			|||||||
		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err)
 | 
							return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg, err := server.Vaults(ctx, &protoReq)
 | 
						msg, err := client.Vault(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
 | 
				
			||||||
 | 
						return msg, metadata, err
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func local_request_Query_Vault_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
 | 
				
			||||||
 | 
						var protoReq QueryVaultRequest
 | 
				
			||||||
 | 
						var metadata runtime.ServerMetadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							val string
 | 
				
			||||||
 | 
							ok  bool
 | 
				
			||||||
 | 
							err error
 | 
				
			||||||
 | 
							_   = err
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val, ok = pathParams["denom"]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protoReq.Denom, err = runtime.String(val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg, err := server.Vault(ctx, &protoReq)
 | 
				
			||||||
	return msg, metadata, err
 | 
						return msg, metadata, err
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -185,6 +203,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mux.Handle("GET", pattern_Query_Vault_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 | 
				
			||||||
 | 
							ctx, cancel := context.WithCancel(req.Context())
 | 
				
			||||||
 | 
							defer cancel()
 | 
				
			||||||
 | 
							inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
 | 
				
			||||||
 | 
							rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							resp, md, err := local_request_Query_Vault_0(rctx, inboundMarshaler, server, req, pathParams)
 | 
				
			||||||
 | 
							ctx = runtime.NewServerMetadataContext(ctx, md)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							forward_Query_Vault_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mux.Handle("GET", pattern_Query_Deposits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 | 
						mux.Handle("GET", pattern_Query_Deposits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 | 
				
			||||||
		ctx, cancel := context.WithCancel(req.Context())
 | 
							ctx, cancel := context.WithCancel(req.Context())
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
@ -286,6 +324,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mux.Handle("GET", pattern_Query_Vault_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 | 
				
			||||||
 | 
							ctx, cancel := context.WithCancel(req.Context())
 | 
				
			||||||
 | 
							defer cancel()
 | 
				
			||||||
 | 
							inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
 | 
				
			||||||
 | 
							rctx, err := runtime.AnnotateContext(ctx, mux, req)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							resp, md, err := request_Query_Vault_0(rctx, inboundMarshaler, client, req, pathParams)
 | 
				
			||||||
 | 
							ctx = runtime.NewServerMetadataContext(ctx, md)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							forward_Query_Vault_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mux.Handle("GET", pattern_Query_Deposits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 | 
						mux.Handle("GET", pattern_Query_Deposits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 | 
				
			||||||
		ctx, cancel := context.WithCancel(req.Context())
 | 
							ctx, cancel := context.WithCancel(req.Context())
 | 
				
			||||||
		defer cancel()
 | 
							defer cancel()
 | 
				
			||||||
@ -312,7 +370,9 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
 | 
				
			|||||||
var (
 | 
					var (
 | 
				
			||||||
	pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "earn", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false)))
 | 
						pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "earn", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pattern_Query_Vaults_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"kava", "earn", "v1beta1", "vaults", "denom"}, "", runtime.AssumeColonVerbOpt(false)))
 | 
						pattern_Query_Vaults_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "earn", "v1beta1", "vaults"}, "", runtime.AssumeColonVerbOpt(false)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pattern_Query_Vault_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"kava", "earn", "v1beta1", "vaults", "denom"}, "", runtime.AssumeColonVerbOpt(false)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pattern_Query_Deposits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "earn", "v1beta1", "deposits"}, "", runtime.AssumeColonVerbOpt(false)))
 | 
						pattern_Query_Deposits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"kava", "earn", "v1beta1", "deposits"}, "", runtime.AssumeColonVerbOpt(false)))
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -322,5 +382,7 @@ var (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	forward_Query_Vaults_0 = runtime.ForwardResponseMessage
 | 
						forward_Query_Vaults_0 = runtime.ForwardResponseMessage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						forward_Query_Vault_0 = runtime.ForwardResponseMessage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	forward_Query_Deposits_0 = runtime.ForwardResponseMessage
 | 
						forward_Query_Deposits_0 = runtime.ForwardResponseMessage
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
@ -162,7 +162,7 @@ func (shares VaultShares) IsValid() bool {
 | 
				
			|||||||
	return shares.Validate() == nil
 | 
						return shares.Validate() == nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AmountOf returns the amount of shares of the given denom.
 | 
					// Add adds two sets of VaultShares.
 | 
				
			||||||
func (shares VaultShares) Add(sharesB ...VaultShare) VaultShares {
 | 
					func (shares VaultShares) Add(sharesB ...VaultShare) VaultShares {
 | 
				
			||||||
	return shares.safeAdd(sharesB)
 | 
						return shares.safeAdd(sharesB)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -284,8 +284,8 @@ func (shares VaultShares) negative() VaultShares {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AmountOf returns the amount of shares of the given denom.
 | 
					// AmountOf returns the amount of shares of the given denom.
 | 
				
			||||||
func (v VaultShares) AmountOf(denom string) sdk.Dec {
 | 
					func (shares VaultShares) AmountOf(denom string) sdk.Dec {
 | 
				
			||||||
	for _, s := range v {
 | 
						for _, s := range shares {
 | 
				
			||||||
		if s.Denom == denom {
 | 
							if s.Denom == denom {
 | 
				
			||||||
			return s.Amount
 | 
								return s.Amount
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -295,8 +295,8 @@ func (v VaultShares) AmountOf(denom string) sdk.Dec {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetShare the single share of the given denom.
 | 
					// GetShare the single share of the given denom.
 | 
				
			||||||
func (v VaultShares) GetShare(denom string) VaultShare {
 | 
					func (shares VaultShares) GetShare(denom string) VaultShare {
 | 
				
			||||||
	for _, s := range v {
 | 
						for _, s := range shares {
 | 
				
			||||||
		if s.Denom == denom {
 | 
							if s.Denom == denom {
 | 
				
			||||||
			return s
 | 
								return s
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -306,8 +306,8 @@ func (v VaultShares) GetShare(denom string) VaultShare {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsZero returns true if the VaultShares is empty.
 | 
					// IsZero returns true if the VaultShares is empty.
 | 
				
			||||||
func (v VaultShares) IsZero() bool {
 | 
					func (shares VaultShares) IsZero() bool {
 | 
				
			||||||
	for _, s := range v {
 | 
						for _, s := range shares {
 | 
				
			||||||
		// If any amount is non-zero, false
 | 
							// If any amount is non-zero, false
 | 
				
			||||||
		if !s.Amount.IsZero() {
 | 
							if !s.Amount.IsZero() {
 | 
				
			||||||
			return false
 | 
								return false
 | 
				
			||||||
@ -366,7 +366,7 @@ func removeZeroShares(shares VaultShares) VaultShares {
 | 
				
			|||||||
// ----------------------------------------------------------------------------
 | 
					// ----------------------------------------------------------------------------
 | 
				
			||||||
// VaultShares sort interface
 | 
					// VaultShares sort interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a VaultShares) Len() int { return len(a) }
 | 
					func (shares VaultShares) Len() int { return len(shares) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Less implements sort.Interface for VaultShares
 | 
					// Less implements sort.Interface for VaultShares
 | 
				
			||||||
func (shares VaultShares) Less(i, j int) bool { return shares[i].Denom < shares[j].Denom }
 | 
					func (shares VaultShares) Less(i, j int) bool { return shares[i].Denom < shares[j].Denom }
 | 
				
			||||||
 | 
				
			|||||||
@ -85,7 +85,7 @@ func (vsrs VaultShareRecords) Validate() error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewAllowedVaults returns a new AllowedVaults with the given denom and strategy type.
 | 
					// NewAllowedVault returns a new AllowedVault with the given values.
 | 
				
			||||||
func NewAllowedVault(
 | 
					func NewAllowedVault(
 | 
				
			||||||
	denom string,
 | 
						denom string,
 | 
				
			||||||
	strategyTypes StrategyTypes,
 | 
						strategyTypes StrategyTypes,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user