-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Shade staking query interface and APY calculation for derivatives (#118)
* feat: added scaffolding to calculate deriavtive APY on back end * feat: added tests * feat: cleaning up pr * feat: added routing for docs * feat: added changeset * fix: wrong constant * fix: tests * feat: moved some files into a utils file, wrote tests, moved mocks * feat: moved a comment
- Loading branch information
Showing
29 changed files
with
2,283 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@shadeprotocol/shadejs": minor | ||
--- | ||
|
||
added apy calculations for derivatives and shade staking query interface |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# APY Calculations | ||
|
||
This page demonstrates how to calculate outputs the shade derivative contracts | ||
|
||
### stkd-SCRT APY | ||
Calculates the apy expected for the stkd-SCRT token | ||
```ts | ||
/** | ||
* Will calculate APY for the stkd secret derivative contract | ||
* | ||
* returns a number that is the decimal form of the percent APY | ||
* @param lcdEndpoint is not optional due to the requirement of the secretChainQueries() function | ||
*/ | ||
function calculateDerivativeScrtApy({ | ||
queryRouterContractAddress, | ||
queryRouterCodeHash, | ||
contractAddress, | ||
codeHash, | ||
lcdEndpoint, | ||
chainId, | ||
}: { | ||
queryRouterContractAddress: string, | ||
queryRouterCodeHash?: string, | ||
contractAddress: string, | ||
codeHash: string, | ||
lcdEndpoint: string, | ||
chainId?: string, | ||
}): Promise<number> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Shade Staking Examples | ||
|
||
This page demonstrates how to query the shade staking contracts | ||
|
||
## Staking Info | ||
|
||
**input** | ||
|
||
```ts | ||
/** | ||
* query the staking info from the shade staking contract | ||
*/ | ||
async function queryShadeStakingOpportunity({ | ||
shadeStakingContractAddress, | ||
shadeStakingCodeHash, | ||
lcdEndpoint, | ||
chainId, | ||
}: { | ||
shadeStakingContractAddress: string, | ||
shadeStakingCodeHash?: string, | ||
lcdEndpoint?: string, | ||
chainId?: string, | ||
}): Promise<StakingInfoServiceModel> | ||
``` | ||
|
||
**output** | ||
|
||
```ts | ||
type StakingInfoServiceModel = { | ||
stakeTokenAddress: string, | ||
totalStakedRaw: string, | ||
unbondingPeriod: number, | ||
rewardPools: StakingRewardPoolServiceModel[], | ||
} | ||
// type references below | ||
type StakingRewardPoolServiceModel = { | ||
id: string, | ||
amountRaw: string, | ||
startDate: Date, | ||
endDate: Date, | ||
tokenAddress: string, | ||
rateRaw: string, | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { | ||
test, | ||
expect, | ||
} from 'vitest'; | ||
import { msgQueryShadeStakingOpportunity } from './shadeStaking'; | ||
|
||
test('it tests the form of the query staking info msg', () => { | ||
const output = { staking_info: {} }; | ||
expect(msgQueryShadeStakingOpportunity()).toStrictEqual(output); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* message for the getting staking opportunity info from the shade staking contract | ||
*/ | ||
const msgQueryShadeStakingOpportunity = () => ({ staking_info: {} }); | ||
|
||
export { | ||
msgQueryShadeStakingOpportunity, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { | ||
test, | ||
expect, | ||
vi, | ||
beforeAll, | ||
} from 'vitest'; | ||
import { of } from 'rxjs'; | ||
import stakingOpportunityResponse from '~/test/mocks/shadeStaking/stakingOpportunityResponse.json'; | ||
import { stakingOpportunityResponseParsed } from '~/test/mocks/shadeStaking/response'; | ||
import { | ||
parseStakingOpportunity, | ||
queryShadeStakingOpportunity, | ||
queryShadeStakingOpportunity$, | ||
} from '~/contracts/services/shadeStaking'; | ||
import { StakingInfoServiceResponse } from '~/types/contracts/shadeStaking/index'; | ||
|
||
const sendSecretClientContractQuery$ = vi.hoisted(() => vi.fn()); | ||
|
||
beforeAll(() => { | ||
vi.mock('~/contracts/definitions/shadeStaking', () => ({ | ||
msgQueryShadeStakingOpportunity: vi.fn(() => 'STAKING_INFO_MSG'), | ||
})); | ||
|
||
vi.mock('~/client/index', () => ({ | ||
getActiveQueryClient$: vi.fn(() => of({ client: 'CLIENT' })), | ||
})); | ||
|
||
vi.mock('~/client/services/clientServices', () => ({ | ||
sendSecretClientContractQuery$, | ||
})); | ||
}); | ||
|
||
test('it can parse the shade staking info', () => { | ||
expect(parseStakingOpportunity( | ||
stakingOpportunityResponse as StakingInfoServiceResponse, | ||
)).toStrictEqual(stakingOpportunityResponseParsed); | ||
}); | ||
|
||
test('it can call the query shade staking info service', async () => { | ||
// observables function | ||
sendSecretClientContractQuery$.mockReturnValueOnce(of(stakingOpportunityResponse)); | ||
|
||
const input = { | ||
shadeStakingContractAddress: 'CONTRACT_ADDRESS', | ||
shadeStakingCodeHash: 'CODE_HASH', | ||
lcdEndpoint: 'LCD_ENDPOINT', | ||
chainId: 'CHAIN_ID', | ||
}; | ||
|
||
let output; | ||
queryShadeStakingOpportunity$(input).subscribe({ | ||
next: (response) => { | ||
output = response; | ||
}, | ||
}); | ||
|
||
expect(sendSecretClientContractQuery$).toHaveBeenCalledWith({ | ||
queryMsg: 'STAKING_INFO_MSG', | ||
client: 'CLIENT', | ||
contractAddress: input.shadeStakingContractAddress, | ||
codeHash: input.shadeStakingCodeHash, | ||
}); | ||
|
||
expect(output).toStrictEqual(stakingOpportunityResponseParsed); | ||
|
||
// async/await function | ||
sendSecretClientContractQuery$.mockReturnValueOnce(of(stakingOpportunityResponse)); | ||
const output2 = await queryShadeStakingOpportunity(input); | ||
|
||
expect(sendSecretClientContractQuery$).toHaveBeenCalledWith({ | ||
queryMsg: 'STAKING_INFO_MSG', | ||
client: 'CLIENT', | ||
contractAddress: input.shadeStakingContractAddress, | ||
codeHash: input.shadeStakingCodeHash, | ||
}); | ||
|
||
expect(output2).toStrictEqual(stakingOpportunityResponseParsed); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { getActiveQueryClient$ } from '~/client'; | ||
import { sendSecretClientContractQuery$ } from '~/client/services/clientServices'; | ||
import { | ||
switchMap, | ||
first, | ||
map, | ||
lastValueFrom, | ||
} from 'rxjs'; | ||
import { convertCoinFromUDenom } from '~/lib/utils'; | ||
import { msgQueryShadeStakingOpportunity } from '~/contracts/definitions/shadeStaking'; | ||
import { | ||
StakingInfoServiceResponse, | ||
StakingRewardPoolServiceModel, | ||
StakingInfoServiceModel, | ||
} from '~/types/contracts/shadeStaking/index'; | ||
|
||
// data returned from the contract in normalized form with | ||
// 18 decimals, in addition to any decimals on the individual token | ||
const NORMALIZATION_FACTOR = 18; | ||
|
||
/** | ||
* parses the response from the shade staking contract into a model | ||
*/ | ||
function parseStakingOpportunity(data: StakingInfoServiceResponse): StakingInfoServiceModel { | ||
const stakeTokenAddress = data.staking_info.info.stake_token; | ||
const totalStakedRaw = data.staking_info.info.total_staked; | ||
const unbondingPeriod = Number(data.staking_info.info.unbond_period); | ||
const rewardPools: StakingRewardPoolServiceModel[] = data.staking_info.info.reward_pools | ||
.map((reward) => ({ | ||
id: reward.id, | ||
amountRaw: reward.amount, | ||
startDate: new Date(Number(reward.start) * 1000), | ||
endDate: new Date(Number(reward.end) * 1000), | ||
tokenAddress: reward.token.address, | ||
rateRaw: convertCoinFromUDenom(reward.rate, NORMALIZATION_FACTOR).toString(), | ||
})); | ||
return { | ||
stakeTokenAddress, | ||
totalStakedRaw, | ||
unbondingPeriod, | ||
rewardPools, | ||
}; | ||
} | ||
|
||
/** | ||
* query the staking info from the shade staking contract | ||
*/ | ||
const queryShadeStakingOpportunity$ = ({ | ||
shadeStakingContractAddress, | ||
shadeStakingCodeHash, | ||
lcdEndpoint, | ||
chainId, | ||
}: { | ||
shadeStakingContractAddress: string, | ||
shadeStakingCodeHash?: string, | ||
lcdEndpoint?: string, | ||
chainId?: string, | ||
}) => getActiveQueryClient$(lcdEndpoint, chainId).pipe( | ||
switchMap(({ client }) => sendSecretClientContractQuery$({ | ||
queryMsg: msgQueryShadeStakingOpportunity(), | ||
client, | ||
contractAddress: shadeStakingContractAddress, | ||
codeHash: shadeStakingCodeHash, | ||
})), | ||
map((response) => parseStakingOpportunity(response as StakingInfoServiceResponse)), | ||
first(), | ||
); | ||
|
||
/** | ||
* query the staking info from the shade staking contract | ||
*/ | ||
async function queryShadeStakingOpportunity({ | ||
shadeStakingContractAddress, | ||
shadeStakingCodeHash, | ||
lcdEndpoint, | ||
chainId, | ||
}: { | ||
shadeStakingContractAddress: string, | ||
shadeStakingCodeHash?: string, | ||
lcdEndpoint?: string, | ||
chainId?: string, | ||
}) { | ||
return lastValueFrom(queryShadeStakingOpportunity$({ | ||
shadeStakingContractAddress, | ||
shadeStakingCodeHash, | ||
lcdEndpoint, | ||
chainId, | ||
})); | ||
} | ||
|
||
export { | ||
parseStakingOpportunity, | ||
queryShadeStakingOpportunity$, | ||
queryShadeStakingOpportunity, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.