Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Js014 merge develop #196

Merged
merged 16 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/brave-emus-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shadeprotocol/shadejs": patch
---

SecretJs Bump
5 changes: 5 additions & 0 deletions .changeset/dirty-yaks-think.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shadeprotocol/shadejs": minor
---

adding decimals as a required arg to queryDerivativeShdStakingInfo
5 changes: 5 additions & 0 deletions .changeset/large-bananas-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shadeprotocol/shadejs": minor
---

upgrade secretjs which includes breaking changes for the pre-upgraded version of secret network
5 changes: 5 additions & 0 deletions .changeset/rotten-paws-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shadeprotocol/shadejs": patch
---

change from individual validator queries to batch data
5 changes: 5 additions & 0 deletions .changeset/spicy-badgers-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shadeprotocol/shadejs": patch
---

change secret endpoints to new api after upgrade
5 changes: 5 additions & 0 deletions .changeset/swift-mirrors-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shadeprotocol/shadejs": patch
---

add batch query for shade staking
39 changes: 39 additions & 0 deletions src/client/services/clientServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,45 @@ const sendSecretClientContractQuery$ = ({
first(),
);

// This function queries the total supply of the a token
const secretClientTokenSupplyQuery$ = (
client: SecretNetworkClient,
denom: string,
) => createFetchClient(defer(
() => from(client.query.bank.supplyOf({
denom,
})),
));

// This function queries the individual validator data
const secretClientValidatorQuery$ = (
client: SecretNetworkClient,
validatorAddress: string,
) => createFetchClient(defer(
() => from(client.query.staking.validator({ validator_addr: validatorAddress })),
));

// This function queries a single page of multiple validators data
const secretClientValidatorsQuery$ = ({
client,
offset,
limit,
}:{
client: SecretNetworkClient,
offset?: number,
limit?: number,
}) => createFetchClient(defer(
() => from(client.query.staking.validators({
pagination: {
offset: offset ? offset.toString() : undefined,
limit: limit ? limit.toString() : undefined,
},
})),
));

export {
sendSecretClientContractQuery$,
secretClientTokenSupplyQuery$,
secretClientValidatorQuery$,
secretClientValidatorsQuery$,
};
2 changes: 2 additions & 0 deletions src/contracts/services/derivativeShd.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ beforeAll(() => {
test('it can parse the staking info', () => {
expect(parseDerivativeShdStakingInfo(
stakingInfoResponse as StakingInfoResponse,
8,
)).toStrictEqual(stakingInfoResponseParsed);
});

Expand All @@ -41,6 +42,7 @@ test('it can call the query staking info service', async () => {
codeHash: 'CODE_HASH',
lcdEndpoint: 'LCD_ENDPOINT',
chainId: 'CHAIN_ID',
decimals: 8,
};

let output;
Expand Down
13 changes: 8 additions & 5 deletions src/contracts/services/derivativeShd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,21 @@ import {
import { convertCoinFromUDenom } from '~/lib/utils';
import { msgQueryShdDerivativeStakingInfo } from '~/contracts/definitions/derivativeShd';

// Contract returns price as a rate of dSHD/SHD with 8 decimals
const DERIVATE_PRICE_DECIMALS = 8;

/**
* Parses the staking info query into a cleaner data model
* NOT FOR PRODUCTION USE, CONTRACT IS IN DEVELOPMENT ON TESTNET ONLY
*/
const parseDerivativeShdStakingInfo = (
response: StakingInfoResponse,
decimals: number,
): ParsedStakingInfoResponse => ({
unbondingTime: response.staking_info.unbonding_time,
bondedShd: response.staking_info.bonded_shd,
rewards: response.staking_info.rewards,
totalDerivativeTokenSupply: response.staking_info.total_derivative_token_supply,
price: convertCoinFromUDenom(
response.staking_info.price,
DERIVATE_PRICE_DECIMALS,
decimals,
).toNumber(),
feeInfo: {
stakingFee: response.staking_info.fee_info.staking.rate / (
Expand All @@ -54,19 +52,21 @@ const queryDerivativeShdStakingInfo$ = ({
codeHash,
lcdEndpoint,
chainId,
decimals,
}: {
contractAddress: string,
codeHash?: string,
lcdEndpoint?: string,
chainId?: string,
decimals: number,
}) => getActiveQueryClient$(lcdEndpoint, chainId).pipe(
switchMap(({ client }) => sendSecretClientContractQuery$({
queryMsg: msgQueryShdDerivativeStakingInfo(),
client,
contractAddress,
codeHash,
})),
map((response) => parseDerivativeShdStakingInfo(response as StakingInfoResponse)),
map((response) => parseDerivativeShdStakingInfo(response as StakingInfoResponse, decimals)),
first(),
);

Expand All @@ -79,17 +79,20 @@ async function queryDerivativeShdStakingInfo({
codeHash,
lcdEndpoint,
chainId,
decimals,
}: {
contractAddress: string,
codeHash?: string,
lcdEndpoint?: string,
chainId?: string,
decimals: number,
}) {
return lastValueFrom(queryDerivativeShdStakingInfo$({
contractAddress,
codeHash,
lcdEndpoint,
chainId,
decimals,
}));
}

Expand Down
66 changes: 66 additions & 0 deletions src/contracts/services/shadeStaking.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ import { of } from 'rxjs';
import stakingOpportunityResponse from '~/test/mocks/shadeStaking/stakingOpportunityResponse.json';
import { stakingOpportunityResponseParsed } from '~/test/mocks/shadeStaking/response';
import {
batchQueryShadeStakingOpportunity,
batchQueryShadeStakingOpportunity$,
parseStakingOpportunity,
queryShadeStakingOpportunity,
queryShadeStakingOpportunity$,
} from '~/contracts/services/shadeStaking';
import { StakingInfoServiceResponse } from '~/types/contracts/shadeStaking/index';
import { batchStakingInfoUnparsed } from '~/test/mocks/shadeStaking/batchStakingInfoUnparsed';
import { batchStakingInfoParsed } from '~/test/mocks/shadeStaking/batchStakingInfoParsed';

const sendSecretClientContractQuery$ = vi.hoisted(() => vi.fn());
const batchQuery$ = vi.hoisted(() => vi.fn());

beforeAll(() => {
vi.mock('~/contracts/definitions/shadeStaking', () => ({
Expand All @@ -28,6 +33,10 @@ beforeAll(() => {
vi.mock('~/client/services/clientServices', () => ({
sendSecretClientContractQuery$,
}));

vi.mock('~/contracts/services/batchQuery', () => ({
batchQuery$,
}));
});

test('it can parse the shade staking info', () => {
Expand Down Expand Up @@ -76,3 +85,60 @@ test('it can call the query shade staking info service', async () => {

expect(output2).toStrictEqual(stakingOpportunityResponseParsed);
});

test('it can call the batch shade staking info query service', async () => {
const input = {
queryRouterContractAddress: 'CONTRACT_ADDRESS',
queryRouterCodeHash: 'CODE_HASH',
lcdEndpoint: 'LCD_ENDPOINT',
chainId: 'CHAIN_ID',
stakingContracts: [{
address: 'STAKING_ADDRESS',
codeHash: 'STAKING_CODE_HASH',
}],
};
// observables function
batchQuery$.mockReturnValueOnce(of(batchStakingInfoUnparsed));
let output;
batchQueryShadeStakingOpportunity$(input).subscribe({
next: (response) => {
output = response;
},
});

expect(batchQuery$).toHaveBeenCalledWith({
contractAddress: input.queryRouterContractAddress,
codeHash: input.queryRouterCodeHash,
lcdEndpoint: input.lcdEndpoint,
chainId: input.chainId,
queries: [{
id: input.stakingContracts[0].address,
contract: {
address: input.stakingContracts[0].address,
codeHash: input.stakingContracts[0].codeHash,
},
queryMsg: 'STAKING_INFO_MSG',
}],
});

expect(output).toStrictEqual(batchStakingInfoParsed);

// async/await function
batchQuery$.mockReturnValueOnce(of(batchStakingInfoUnparsed));
const response = await batchQueryShadeStakingOpportunity(input);
expect(batchQuery$).toHaveBeenCalledWith({
contractAddress: input.queryRouterContractAddress,
codeHash: input.queryRouterCodeHash,
lcdEndpoint: input.lcdEndpoint,
chainId: input.chainId,
queries: [{
id: input.stakingContracts[0].address,
contract: {
address: input.stakingContracts[0].address,
codeHash: input.stakingContracts[0].codeHash,
},
queryMsg: 'STAKING_INFO_MSG',
}],
});
expect(response).toStrictEqual(batchStakingInfoParsed);
});
89 changes: 89 additions & 0 deletions src/contracts/services/shadeStaking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ import {
StakingInfoServiceResponse,
StakingRewardPoolServiceModel,
StakingInfoServiceModel,
BatchShadeStakingOpportunity,
} from '~/types/contracts/shadeStaking/index';
import {
BatchQueryParams,
BatchQueryParsedResponse,
Contract,
MinBlockHeightValidationOptions,
} from '~/types';
import { batchQuery$ } from './batchQuery';

// data returned from the contract in normalized form with
// 18 decimals, in addition to any decimals on the individual token
Expand Down Expand Up @@ -42,6 +50,18 @@ function parseStakingOpportunity(data: StakingInfoServiceResponse): StakingInfoS
};
}

/**
* parses the staking info reponse from a batch query of
* multiple staking contracts
*/
const parseBatchQueryShadeStakingOpportunityResponse = (
response: BatchQueryParsedResponse,
): BatchShadeStakingOpportunity => response.map((item) => ({
stakingContractAddress: item.id as string,
stakingInfo: parseStakingOpportunity(item.response),
blockHeight: item.blockHeight,
}));

/**
* query the staking info from the shade staking contract
*/
Expand Down Expand Up @@ -88,8 +108,77 @@ async function queryShadeStakingOpportunity({
}));
}

/**
* query the staking info for multiple staking contracts at one time
*/
function batchQueryShadeStakingOpportunity$({
queryRouterContractAddress,
queryRouterCodeHash,
lcdEndpoint,
chainId,
stakingContracts,
minBlockHeightValidationOptions,
}:{
queryRouterContractAddress: string,
queryRouterCodeHash?: string,
lcdEndpoint?: string,
chainId?: string,
stakingContracts: Contract[]
minBlockHeightValidationOptions?: MinBlockHeightValidationOptions,
}) {
const queries:BatchQueryParams[] = stakingContracts.map((contract) => ({
id: contract.address,
contract: {
address: contract.address,
codeHash: contract.codeHash,
},
queryMsg: msgQueryShadeStakingOpportunity(),
}));
return batchQuery$({
contractAddress: queryRouterContractAddress,
codeHash: queryRouterCodeHash,
lcdEndpoint,
chainId,
queries,
minBlockHeightValidationOptions,
}).pipe(
map(parseBatchQueryShadeStakingOpportunityResponse),
first(),
);
}

/**
* query the staking info for multiple staking contracts at one time
*/
async function batchQueryShadeStakingOpportunity({
queryRouterContractAddress,
queryRouterCodeHash,
lcdEndpoint,
chainId,
stakingContracts,
minBlockHeightValidationOptions,
}:{
queryRouterContractAddress: string,
queryRouterCodeHash?: string,
lcdEndpoint?: string,
chainId?: string,
stakingContracts: Contract[]
minBlockHeightValidationOptions?: MinBlockHeightValidationOptions,
}) {
return lastValueFrom(batchQueryShadeStakingOpportunity$({
queryRouterContractAddress,
queryRouterCodeHash,
lcdEndpoint,
chainId,
stakingContracts,
minBlockHeightValidationOptions,
}));
}

export {
parseStakingOpportunity,
queryShadeStakingOpportunity$,
queryShadeStakingOpportunity,
batchQueryShadeStakingOpportunity$,
batchQueryShadeStakingOpportunity,
};
3 changes: 3 additions & 0 deletions src/lib/apy/derivativeScrt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { of } from 'rxjs';
import chainQueryParsedResponse from '~/test/mocks/secretChainQueries/chainQueryParsedResponse.json';
import { queryDerivativeScrtInfo$ } from '~/contracts/services/derivativeScrt';
import stakingInfoResponseMainnet from '~/test/mocks/derivativeScrt/stakingInfoResponseMainnet.json';
import { mockValidatorsCommissions } from '~/test/mocks/secretChainQueries/validatorsCommissionsParsedResponse';
import {
secretChainQueries$,
SecretQueryOptions,
Expand All @@ -21,6 +22,8 @@ beforeAll(() => {
vi.mock('~/lib/apy/secretQueries', async (importOriginal: any) => ({
...(await importOriginal()),
secretChainQueries$: vi.fn(() => of(chainQueryParsedResponse)),
queryScrtTotalSupply$: vi.fn(() => of(292470737038201)),
queryAllValidatorsCommissions$: vi.fn(() => of(mockValidatorsCommissions)),
}));

vi.mock('~/contracts/services/derivativeScrt', () => ({
Expand Down
Loading