Skip to content

Commit

Permalink
refactor(oracle)!: replace getQueryObject with OracleBase
Browse files Browse the repository at this point in the history
BREAKING CHANGE: `getQueryObject` removed
Use `Oracle:getQuery`, `OracleClient:getQuery` instead.
  • Loading branch information
davidyuk committed May 31, 2024
1 parent 4008d12 commit bcab498
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 55 deletions.
14 changes: 9 additions & 5 deletions docs/guides/oracles.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,7 @@ const oracleId = 'ok_...';
const queryId = 'oq_...';
const options = { onAccount: 'ak_...' } // only the account of the oracle can respond to the query

// using the query instance
const query = await aeSdk.getQueryObject(oracleId, queryId)
await query.respond('{"temperature": 27.5}', options)

// OR using the aeSdk (instance of AeSdk class) directly by providing the queryId
// using the aeSdk (instance of AeSdk class) by providing the queryId
await aeSdk.respondToQuery(queryId, '{"temperature": 27.5}', options)
```

Expand All @@ -140,6 +136,14 @@ const extendedOracle = await oracle.extendOracle(options)
const extendedOracle = await aeSdk.extendOracleTtl(options)
```

## 5. Get the current state from the node

Both Oracle and OracleClient have methods to get their state from the node.

`Oracle:getState`, `OracleClient:getState` returns the same value as `Node:getOracleByPubkey`, but without arguments (it uses the oracle address provided in the constructor).

`Oracle:getQuery`, `OracleClient:getQuery` corresponds to `Node:getOracleQueryByPubkeyAndQueryId`, adding `decodedQuery`, `decodedResponse` based on the oracle type.

## Example applications

- [ae-oracle-pricefeed](https://github.com/aeternity/ae-oracle-pricefeed)
Expand Down
2 changes: 1 addition & 1 deletion src/index-browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export {
export { default as Contract } from './contract/Contract';
export type { ContractMethodsBase } from './contract/Contract';
export {
pollForQueries, getQueryObject, extendOracleTtl,
pollForQueries, extendOracleTtl,
respondToQuery, getOracleObject, registerOracle,
} from './oracle';
export { default as OracleClient } from './oracle/OracleClient';
Expand Down
40 changes: 3 additions & 37 deletions src/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import { _getPollInterval } from './chain';
import { sendTransaction, SendTransactionOptions } from './send-transaction';
import Node from './Node';
import AccountBase from './account/Base';

type OracleQueries = Awaited<ReturnType<Node['getOracleQueriesByPubkey']>>['oracleQueries'];
import { OracleQueryNode } from './oracle/OracleBase';

/**
* Poll for oracle queries
Expand All @@ -31,7 +30,7 @@ type OracleQueries = Awaited<ReturnType<Node['getOracleQueriesByPubkey']>>['orac
*/
export function pollForQueries(
oracleId: Encoded.OracleAddress,
onQuery: (query: OracleQueries[number]) => void,
onQuery: (query: OracleQueryNode) => void,
{ interval, ...options }: { interval?: number; onNode: Node }
& Parameters<typeof _getPollInterval>[1],
): () => void {
Expand Down Expand Up @@ -59,38 +58,6 @@ export function pollForQueries(
return () => { stopped = true; };
}

/**
* Constructor for OracleQuery Object (helper object for using OracleQuery)
* @category oracle
* @param oracleId - Oracle public key
* @param queryId - Oracle Query id
* @param options - Options
* @returns OracleQuery object
*/
export async function getQueryObject(
oracleId: Encoded.OracleAddress,
queryId: Encoded.OracleQueryId,
options: RespondToQueryOptions,
): Promise<GetQueryObjectReturnType> {
const record = await options.onNode.getOracleQueryByPubkeyAndQueryId(oracleId, queryId);
return {
...record,
decodedQuery: decode(record.query as Encoded.OracleQueryId).toString(),
decodedResponse: decode(record.response as Encoded.OracleResponse).toString(),
respond: async (response, opt) => (
// eslint-disable-next-line @typescript-eslint/no-use-before-define
respondToQuery(queryId, response, { ...options, ...opt })
),
};
}

interface GetQueryObjectReturnType extends Awaited<ReturnType<Node['getOracleQueryByPubkeyAndQueryId']>> {
decodedQuery: string;
decodedResponse: string;
respond: (response: string, options?: Parameters<typeof respondToQuery>[2]) =>
ReturnType<typeof respondToQuery>;
}

/**
* Extend oracle ttl
* @category oracle
Expand Down Expand Up @@ -172,7 +139,6 @@ export async function getOracleObject(
pollQueries: pollForQueries,
respondToQuery,
extendOracle: extendOracleTtl,
getQuery: getQueryObject,
},
([name, handler]) => [
name,
Expand All @@ -193,7 +159,7 @@ export async function getOracleObject(

interface GetOracleObjectReturnType extends Awaited<ReturnType<Node['getOracleByPubkey']>> {
id: Encoded.OracleAddress;
queries: OracleQueries;
queries: OracleQueryNode[];
// TODO: replace getOracleObject with a class
pollQueries: (cb: Parameters<typeof pollForQueries>[1]) => ReturnType<typeof pollForQueries>;
respondToQuery: Function;
Expand Down
56 changes: 56 additions & 0 deletions src/oracle/OracleBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { decode, Encoded } from '../utils/encoder';
import Node from '../Node';

export type OracleQueryNode = Awaited<ReturnType<Node['getOracleQueriesByPubkey']>>['oracleQueries'][number];
interface OracleQuery extends OracleQueryNode {
// TODO: type should be corrected in node api
id: Encoded.OracleQueryId;
decodedQuery: string;
decodedResponse: string;
}

function decodeQuery(queryEntry: OracleQueryNode): OracleQuery {
return {
...queryEntry,
id: queryEntry.id as Encoded.OracleQueryId,
decodedQuery: decode(queryEntry.query as Encoded.OracleQuery).toString(),
decodedResponse: decode(queryEntry.response as Encoded.OracleResponse).toString(),
};
}

/**
* This class is needed because `getOracleQuery` would return different values depending on the
* oracle type.
*/
export default class OracleBase {
/**
* @param address - Oracle public key
*/
constructor(
public readonly address: Encoded.OracleAddress,
public options: { onNode: Node },
) {}

/**
* Get oracle entry from the node
* @param options - Options object
*/
async getState(options: { onNode?: Node } = {}): ReturnType<Node['getOracleByPubkey']> {
const opt = { ...this.options, ...options };
return opt.onNode.getOracleByPubkey(this.address);
}

/**
* Get oracle query entry from the node
* @param queryId - Oracle query ID
* @param options - Options object
*/
async getQuery(
queryId: Encoded.OracleQueryId,
options: { onNode?: Node } = {},
): Promise<OracleQuery> {
const { onNode } = { ...this.options, ...options };
const queryEntry = await onNode.getOracleQueryByPubkeyAndQueryId(this.address, queryId);
return decodeQuery(queryEntry);
}
}
11 changes: 7 additions & 4 deletions src/oracle/OracleClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { _getPollInterval, getHeight } from '../chain';
import { sendTransaction } from '../send-transaction';
import Node from '../Node';
import AccountBase from '../account/Base';
import OracleBase from './OracleBase';

interface OracleClientPostQueryOptions extends
Optional<Parameters<typeof sendTransaction>[1], 'onNode' | 'onAccount'>,
Expand All @@ -16,17 +17,19 @@ interface OracleClientPostQueryOptions extends
/**
* @category oracle
*/
export default class OracleClient {
export default class OracleClient extends OracleBase {
/**
* @param address - Oracle public key
* @param options - Options object
* @param options.onAccount - Account to use
* @param options.onNode - Node to use
*/
constructor(
public readonly address: Encoded.OracleAddress,
public options: { onAccount: AccountBase; onNode: Node } & Parameters<OracleClient['query']>[1],
) {}
address: Encoded.OracleAddress,
public override options: { onAccount: AccountBase; onNode: Node } & Parameters<OracleClient['query']>[1],
) {
super(address, options);
}

/**
* Post query to oracle
Expand Down
15 changes: 8 additions & 7 deletions test/integration/delegation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import { getSdk } from '.';
import {
commitmentHash, decode, encode, Encoded, Encoding,
genSalt, AeSdk, Contract, ConsensusProtocolVersion,
genSalt, AeSdk, Contract, ConsensusProtocolVersion, OracleClient,
} from '../../src';

describe('Operation delegation', () => {
Expand Down Expand Up @@ -218,7 +218,7 @@ contract DelegateTest =
describe('Oracle', () => {
let oracle: Awaited<ReturnType<typeof aeSdk.getOracleObject>>;
let oracleId: Encoded.OracleAddress;
let queryObject: Awaited<ReturnType<typeof aeSdk.getQueryObject>>;
let queryObject: Awaited<ReturnType<OracleClient['getQuery']>>;
let delegationSignature: Uint8Array;
const queryFee = 500000;
const ttl: ChainTtl = { RelativeTTL: [50n] };
Expand Down Expand Up @@ -292,9 +292,9 @@ contract DelegateTest =
.createQuery(oracle.id, q, 1000 + queryFee, ttl, ttl, { amount: 5 * queryFee });
assertNotNull(query.result);
query.result.returnType.should.be.equal('ok');
queryObject = await aeSdk.getQueryObject(oracle.id, query.decodedResult);
queryObject.should.be.an('object');
queryObject.decodedQuery.should.be.equal(q);
const oracleClient = new OracleClient(oracle.id, aeSdk.getContext());
queryObject = await oracleClient.getQuery(query.decodedResult);
expect(queryObject.decodedQuery).to.be.equal(q);
});

it('responds to query', async () => {
Expand All @@ -307,8 +307,9 @@ contract DelegateTest =
const { result } = await contract.respond(oracle.id, queryId, respondSig, r);
assertNotNull(result);
result.returnType.should.be.equal('ok');
const queryObject2 = await aeSdk.getQueryObject(oracle.id, queryId);
queryObject2.decodedResponse.should.be.equal(r);
const oracleClient = new OracleClient(oracle.id, aeSdk.getContext());
const queryObject2 = await oracleClient.getQuery(queryId);
expect(queryObject2.decodedResponse).to.be.equal(r);
});

it('fails trying to create general delegation as oracle query', async () => {
Expand Down
2 changes: 1 addition & 1 deletion test/integration/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('Oracle', () => {
it('Respond to query', async () => {
const { queryId } = await oracleClient.postQuery('{"city": "Berlin"}');
oracle = await aeSdk.respondToQuery(queryId, queryResponse);
const query = await oracle.getQuery(queryId);
const query = await oracleClient.getQuery(queryId);

expect(query.decodedResponse).to.be.equal(queryResponse);
expect(decode(query.response as Encoded.OracleResponse).toString()).to.be.equal(queryResponse);
Expand Down

0 comments on commit bcab498

Please sign in to comment.