From 17998441b3de98f4b52f5f6ba619ff80b6ca1398 Mon Sep 17 00:00:00 2001 From: jingyi2811 Date: Thu, 3 Jun 2021 21:03:03 +0800 Subject: [PATCH] Add appointoracle rpc (#336) --- .../category/oracle/appointOracle.test.ts | 100 ++++++++++++++++++ .../jellyfish-api-core/src/category/oracle.ts | 44 ++++++++ packages/jellyfish-api-core/src/index.ts | 3 + website/docs/jellyfish/api/oracle.md | 38 +++++++ website/sidebars.js | 2 + 5 files changed, 187 insertions(+) create mode 100644 packages/jellyfish-api-core/__tests__/category/oracle/appointOracle.test.ts create mode 100644 packages/jellyfish-api-core/src/category/oracle.ts create mode 100644 website/docs/jellyfish/api/oracle.md diff --git a/packages/jellyfish-api-core/__tests__/category/oracle/appointOracle.test.ts b/packages/jellyfish-api-core/__tests__/category/oracle/appointOracle.test.ts new file mode 100644 index 0000000000..8782bdd60a --- /dev/null +++ b/packages/jellyfish-api-core/__tests__/category/oracle/appointOracle.test.ts @@ -0,0 +1,100 @@ +import { MasterNodeRegTestContainer } from '@defichain/testcontainers' +import { ContainerAdapterClient } from '../../container_adapter_client' +import { UTXO } from '../../../src/category/oracle' +import { RpcApiError } from '../../../src' + +describe('Oracle', () => { + const container = new MasterNodeRegTestContainer() + const client = new ContainerAdapterClient(container) + + beforeAll(async () => { + await container.start() + await container.waitForReady() + await container.waitForWalletCoinbaseMaturity() + }) + + afterAll(async () => { + await container.stop() + }) + + it('should appointOracle', async () => { + const priceFeeds = [ + { currency: 'USD', token: 'TESLA' }, + { currency: 'EUR', token: 'APPLE' } + ] + + const txid = await client.oracle.appointOracle(await container.getNewAddress(), priceFeeds, { weightage: 1 }) + + expect(typeof txid).toStrictEqual('string') + expect(txid.length).toStrictEqual(64) + + await container.generate(1) + + const result = await container.call('getoracledata', [txid]) + expect(result).toStrictEqual( + { + weightage: 1, + oracleid: txid, + address: expect.any(String), + priceFeeds: [ + { token: 'APPLE', currency: 'EUR' }, + { token: 'TESLA', currency: 'USD' } + ], + tokenPrices: [] + } + ) + }) + + it('should appointOracle with utxos', async () => { + const priceFeeds = [ + { currency: 'USD', token: 'TESLA' }, + { currency: 'EUR', token: 'APPLE' } + ] + + const address = await container.getNewAddress() + const utxos = await container.call('listunspent', [1, 9999999, [address], true]) + const inputs: UTXO[] = utxos.map((utxo: UTXO) => { + return { + txid: utxo.txid, + vout: utxo.vout + } + }) + + const txid = await client.oracle.appointOracle(address, priceFeeds, { weightage: 1, utxos: inputs }) + + expect(typeof txid).toStrictEqual('string') + expect(txid.length).toStrictEqual(64) + + await container.generate(1) + + const result = await container.call('getoracledata', [txid]) + expect(result).toStrictEqual( + { + weightage: 1, + oracleid: txid, + address: expect.any(String), + priceFeeds: [ + { token: 'APPLE', currency: 'EUR' }, + { token: 'TESLA', currency: 'USD' } + ], + tokenPrices: [] + } + ) + }) + + it('should not appointOracle with arbitrary utxos', async () => { + const priceFeeds = [ + { currency: 'USD', token: 'TESLA' }, + { currency: 'EUR', token: 'APPLE' } + ] + + const { txid, vout } = await container.fundAddress(await container.getNewAddress(), 10) + const promise = client.oracle.appointOracle(await container.getNewAddress(), priceFeeds, { + weightage: 1, + utxos: [{ txid, vout }] + }) + + await expect(promise).rejects.toThrow(RpcApiError) + await expect(promise).rejects.toThrow('RpcApiError: \'Test AppointOracleTx execution failed:\ntx not from foundation member\', code: -32600, method: appointoracle') + }) +}) diff --git a/packages/jellyfish-api-core/src/category/oracle.ts b/packages/jellyfish-api-core/src/category/oracle.ts new file mode 100644 index 0000000000..c815ac51f0 --- /dev/null +++ b/packages/jellyfish-api-core/src/category/oracle.ts @@ -0,0 +1,44 @@ +import { ApiClient } from '../.' + +/** + * Oracle RPCs for DeFi Blockchain + */ +export class Oracle { + private readonly client: ApiClient + + constructor (client: ApiClient) { + this.client = client + } + + /** + * Creates a price oracle for rely of real time price data. + * + * @param {string} address + * @param {PriceFeed[]} priceFeeds + * @param {AppointOracleOptions} [options] + * @param {number} options.weightage + * @param {UTXO[]} [options.utxos = []] + * @param {string} [options.utxos.txid] + * @param {number} [options.utxos.vout] + * @return {Promise} + */ + async appointOracle (address: string, priceFeeds: PriceFeed[], options: AppointOracleOptions = {}): Promise { + const { utxos = [] } = options + return await this.client.call('appointoracle', [address, priceFeeds, options.weightage, utxos], 'number') + } +} + +export interface PriceFeed { + currency: string + token: string +} + +export interface AppointOracleOptions { + weightage?: number + utxos?: UTXO[] +} + +export interface UTXO { + txid: string + vout: number +} diff --git a/packages/jellyfish-api-core/src/index.ts b/packages/jellyfish-api-core/src/index.ts index a250e83a35..7819be4983 100644 --- a/packages/jellyfish-api-core/src/index.ts +++ b/packages/jellyfish-api-core/src/index.ts @@ -7,6 +7,7 @@ import { Wallet } from './category/wallet' import { Account } from './category/account' import { PoolPair } from './category/poolpair' import { Token } from './category/token' +import { Oracle } from './category/oracle' import { Server } from './category/server' export * from '@defichain/jellyfish-json' @@ -19,6 +20,7 @@ export * as wallet from './category/wallet' export * as poolpair from './category/poolpair' export * as token from './category/token' export * as account from './category/account' +export * as oracle from './category/oracle' export * as server from './category/server' /** @@ -33,6 +35,7 @@ export abstract class ApiClient { public readonly account = new Account(this) public readonly poolpair = new PoolPair(this) public readonly token = new Token(this) + public readonly oracle = new Oracle(this) public readonly server = new Server(this) /** diff --git a/website/docs/jellyfish/api/oracle.md b/website/docs/jellyfish/api/oracle.md new file mode 100644 index 0000000000..13833f4a09 --- /dev/null +++ b/website/docs/jellyfish/api/oracle.md @@ -0,0 +1,38 @@ +--- +id: oracle +title: Oracle API +sidebar_label: Oracle API +slug: /jellyfish/api/oracle +--- + +```js +import {Client} from '@defichain/jellyfish' +const client = new Client() +// Using client.oracle. +const something = await client.oracle.method() +``` + +## appointOracle + +Creates a price oracle for rely of real time price data. + +```ts title="client.oracle.appointOracle()" +interface oracle { + appointOracle (address: string, priceFeeds: PriceFeed[], options: AppointOracleOptions = {}): Promise +} + +interface PriceFeed { + currency: string + token: string +} + +interface AppointOracleOptions { + weightage?: number + utxos?: UTXO[] +} + +interface UTXO { + txid: string + vout: number +} +``` diff --git a/website/sidebars.js b/website/sidebars.js index d8f9b543f9..d600b21c5e 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -16,6 +16,8 @@ module.exports = { 'jellyfish/api/poolpair', 'jellyfish/api/token', 'jellyfish/api/account', + 'jellyfish/api/oracle', + 'jellyfish/api/account', 'jellyfish/api/server' ] }