Skip to content

Commit

Permalink
feat: oracle async wrapper and docs, other misc updates
Browse files Browse the repository at this point in the history
  • Loading branch information
AustinWoetzel committed Nov 1, 2023
1 parent 6eef828 commit a3a6ad5
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ $ yarn test
Docs will be available on a vitepress site. You can run the site locally with this command:

```
$ yarn run docs:dev
$ yarn docs:dev
```
4 changes: 3 additions & 1 deletion docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ export default defineConfig({
text: 'Examples',
items: [
{ text: 'Swap', link: '/swap' },
{ text: 'Oracle', link: '/oracle' },
]
}
],

socialLinks: [
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
{ icon: 'github', link: 'https://github.com/securesecrets/shadejs' },
{ icon: 'discord', link: 'https://discord.com/channels/905665558610051113/905670616391233566' }
]
}
})
15 changes: 8 additions & 7 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ layout: home

hero:
name: "ShadeJS"
text: "Powerful TypeScript Library for Shade Integration"
text: "Powerful SDK for Shade Integration"
tagline: Simple, Robust, and Efficient Developer Tooling
actions:
- theme: brand
Expand All @@ -15,11 +15,12 @@ hero:
# link: /api-examples

features:
- title: Feature A
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
- title: Feature B
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
- title: Feature C
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
- title: TypeScript Support
details: Seamlessly integrate into your javascript projects.
- title: Shade Smart Contracts
details: Query and execute message interfaces defined for interating with Shade Protocol
- title: Secret.js Wrapper
details: Wraps Secret Network's javascript SDK to simplify the developer experience

---

128 changes: 128 additions & 0 deletions docs/oracle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Oracle Examples

This page demonstrates how to query the Shade Oracle Router, which serves price feeds from various sources inluding: Band Protocol, ShadeSwap pools, derivative redemption rates, and others.
## Single Oracle Price

**input**

```js
async function queryPrice({
contractAddress,
codeHash,
oracleKey,
lcdEndpoint,
chainId,
}:{
contractAddress: string,
codeHash?: string,
oracleKey: string,
lcdEndpoint?: string,
chainId?: string,
}) : Promise<ParsedOraclePriceResponse>
```
::: warning
It is recommended that you provide your own LCD endpoint, although we do provide a default mainnet option. Performance of the default endpoint is not guaranteed.
:::

**output**

```js
type ParsedOraclePriceResponse = {
oracleKey: string,
rate: string,
lastUpdatedBase: number,
lastUpdatedQuote: number,
}


```

**example use**

```js
const output = await queryPrice({
contractAddress: '[ORACLE_CONTRACT_ADDRESS]',
codeHash: '[ORACLE_CODE_HASH]',,
oracleKey: 'BTC',
})
console.log(output)
```
***console***
```md
const priceParsed = {
oracleKey: 'BTC',
rate: '27917207155600000000000',
lastUpdatedBase: 1696644063,
lastUpdatedQuote: 18446744073709552000,
};
```

## Multiple Oracle Prices

**input**

```js
async function queryPrices({
contractAddress,
codeHash,
oracleKeys,
lcdEndpoint,
chainId,
}:{
contractAddress: string,
codeHash?: string,
oracleKeys: string[],
lcdEndpoint?: string,
chainId?: string,
}) : Promise<ParsedOraclePricesResponse>
```
::: warning
It is recommended that you provide your own LCD endpoint, although we do provide a default mainnet option. Performance of the default endpoint is not guaranteed.
:::

**output**

```js
type ParsedOraclePricesResponse = {
[oracleKey: string]: ParsedOraclePriceResponse
}

// type reference below

type ParsedOraclePriceResponse = {
oracleKey: string,
rate: string,
lastUpdatedBase: number,
lastUpdatedQuote: number,
}


```

**example use**

```js
const output = await queryPrices({
contractAddress: '[ORACLE_CONTRACT_ADDRESS]',
codeHash: '[ORACLE_CODE_HASH]',,
oracleKeys: ['BTC', 'ETH'],
})
console.log(output)
```
***console***
```md
{
BTC: {
oracleKey: 'BTC',
rate: '27917207155600000000000',
lastUpdatedBase: 1696644063,
lastUpdatedQuote: 18446744073709552000,
},
ETH: {
oracleKey: 'ETH',
rate: '1644083682900000000000',
lastUpdatedBase: 1696644063,
lastUpdatedQuote: 18446744073709552000,
},
}
```
44 changes: 38 additions & 6 deletions src/contracts/services/oracle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
parsePricesFromContract,
queryPrice$,
queryPrices$,
queryPrice,
queryPrices,
} from '~/contracts/services/oracle';
import priceResponse from '~/test/mocks/oracle/priceResponse.json';
import pricesResponse from '~/test/mocks/oracle/pricesResponse.json';
Expand Down Expand Up @@ -52,16 +54,18 @@ test('it can parse the prices response', () => {
)).toStrictEqual(pricesParsed);
});

test('it can send the query single price service', () => {
sendSecretClientContractQuery$.mockReturnValue(of(priceResponse));

test('it can send the query single price service', async () => {
const input = {
contractAddress: 'CONTRACT_ADDRESS',
codeHash: 'CODE_HASH',
oracleKey: 'ORACLE_KEY',
lcdEndpoint: 'LCD_ENDPOINT',
chainId: 'CHAIN_ID',
};

// observables function
sendSecretClientContractQuery$.mockReturnValueOnce(of(priceResponse));

let output;
queryPrice$(input).subscribe({
next: (response) => {
Expand All @@ -77,18 +81,33 @@ test('it can send the query single price service', () => {
});

expect(output).toStrictEqual(priceParsed);
});

test('it can send the query multiple prices service', () => {
sendSecretClientContractQuery$.mockReturnValue(of(pricesResponse));
// async/await function
sendSecretClientContractQuery$.mockReturnValueOnce(of(priceResponse));
const response = await queryPrice(input);

expect(sendSecretClientContractQuery$).toHaveBeenCalledWith({
queryMsg: 'MSG_QUERY_ORACLE_PRICE',
client: 'CLIENT',
contractAddress: input.contractAddress,
codeHash: input.codeHash,
});

expect(response).toStrictEqual(priceParsed);
});

test('it can send the query multiple prices service', async () => {
const input = {
contractAddress: 'CONTRACT_ADDRESS',
codeHash: 'CODE_HASH',
oracleKeys: ['ORACLE_KEY'],
lcdEndpoint: 'LCD_ENDPOINT',
chainId: 'CHAIN_ID',
};

// observables function
sendSecretClientContractQuery$.mockReturnValueOnce(of(pricesResponse));

let output;
queryPrices$(input).subscribe({
next: (response) => {
Expand All @@ -104,4 +123,17 @@ test('it can send the query multiple prices service', () => {
});

expect(output).toStrictEqual(pricesParsed);

// async/await function
sendSecretClientContractQuery$.mockReturnValueOnce(of(pricesResponse));
const response = await queryPrices(input);

expect(sendSecretClientContractQuery$).toHaveBeenCalledWith({
queryMsg: 'MSG_QUERY_ORACLE_PRICES',
client: 'CLIENT',
contractAddress: input.contractAddress,
codeHash: input.codeHash,
});

expect(response).toStrictEqual(pricesParsed);
});
53 changes: 53 additions & 0 deletions src/contracts/services/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
switchMap,
first,
map,
lastValueFrom,
} from 'rxjs';
import { sendSecretClientContractQuery$ } from '~/client/services/clientServices';
import { getActiveQueryClient$ } from '~/client';
Expand Down Expand Up @@ -66,6 +67,31 @@ const queryPrice$ = ({
first(),
);

/**
* query the price of an asset using the oracle key
*/
async function queryPrice({
contractAddress,
codeHash,
oracleKey,
lcdEndpoint,
chainId,
}:{
contractAddress: string,
codeHash?: string,
oracleKey: string,
lcdEndpoint?: string,
chainId?: string,
}) {
return lastValueFrom(queryPrice$({
contractAddress,
codeHash,
oracleKey,
lcdEndpoint,
chainId,
}));
}

/**
* query multiple asset prices using oracle keys
*/
Expand All @@ -92,9 +118,36 @@ const queryPrices$ = ({
first(),
);

/**
* query multiple asset prices using oracle keys
*/
async function queryPrices({
contractAddress,
codeHash,
oracleKeys,
lcdEndpoint,
chainId,
}:{
contractAddress: string,
codeHash?: string,
oracleKeys: string[],
lcdEndpoint?: string,
chainId?: string,
}) {
return lastValueFrom(queryPrices$({
contractAddress,
codeHash,
oracleKeys,
lcdEndpoint,
chainId,
}));
}

export {
parsePriceFromContract,
parsePricesFromContract,
queryPrice$,
queryPrices$,
queryPrice,
queryPrices,
};
19 changes: 18 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import '~/polyfills/index';
import { getSecretNetworkClient$, getActiveQueryClient$ } from '~/client';
import { queryPrice$, queryPrices$ } from '~/contracts/services/oracle';
import {
queryPrice$,
queryPrices$,
queryPrice,
queryPrices,
} from '~/contracts/services/oracle';
import { batchQuery$ } from '~/contracts/services/batchQuery';
import {
queryFactoryConfig$,
queryFactoryPairs$,
queryPairConfig$,
batchQueryPairsInfo$,
batchQueryStakingInfo$,
queryFactoryConfig,
queryFactoryPairs,
queryPairConfig,
batchQueryPairsInfo,
batchQueryStakingInfo,
} from '~/contracts/services/swap';
import { querySnip20TokenInfo$ } from './contracts/services/snip20';

Expand All @@ -16,11 +26,18 @@ export {
getActiveQueryClient$,
queryPrice$,
queryPrices$,
queryPrice,
queryPrices,
batchQuery$,
queryFactoryConfig$,
queryFactoryPairs$,
queryPairConfig$,
batchQueryPairsInfo$,
batchQueryStakingInfo$,
queryFactoryConfig,
queryFactoryPairs,
queryPairConfig,
batchQueryPairsInfo,
batchQueryStakingInfo,
querySnip20TokenInfo$,
};

0 comments on commit a3a6ad5

Please sign in to comment.