Add tests for querying bond
This commit is contained in:
parent
19d5405087
commit
7fe5bcda83
@ -25,6 +25,7 @@
|
|||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
"ethers": "^5.6.1",
|
"ethers": "^5.6.1",
|
||||||
"evmosjs": "^0.2.2",
|
"evmosjs": "^0.2.2",
|
||||||
|
"graphql.js": "^0.6.8",
|
||||||
"is-url": "^1.2.4",
|
"is-url": "^1.2.4",
|
||||||
"js-sha256": "^0.9.0",
|
"js-sha256": "^0.9.0",
|
||||||
"ripemd160": "^2.0.2",
|
"ripemd160": "^2.0.2",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Registry } from './index';
|
import { Registry } from './index';
|
||||||
import { getConfig } from './testing/helper';
|
import { getConfig, wait } from './testing/helper';
|
||||||
|
|
||||||
const { mockServer, chibaClonk: { chainId, endpoint, privateKey, accountAddress, fee } } = getConfig();
|
const { mockServer, chibaClonk: { chainId, restEndpoint, gqlEndpoint, privateKey, accountAddress, fee } } = getConfig();
|
||||||
|
|
||||||
jest.setTimeout(90 * 1000);
|
jest.setTimeout(90 * 1000);
|
||||||
|
|
||||||
@ -9,15 +9,41 @@ const bondTests = () => {
|
|||||||
let registry: Registry;
|
let registry: Registry;
|
||||||
let bondId1: string;
|
let bondId1: string;
|
||||||
|
|
||||||
|
let bondOwner: string;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
registry = new Registry(endpoint, chainId);
|
registry = new Registry(restEndpoint, gqlEndpoint, chainId);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Create bond.', async () => {
|
test('Create bond.', async () => {
|
||||||
bondId1 = await registry.getNextBondId(accountAddress);
|
bondId1 = await registry.getNextBondId(accountAddress);
|
||||||
expect(bondId1).toBeDefined();
|
expect(bondId1).toBeDefined();
|
||||||
await registry.createBond({ denom: 'aphoton', amount: '100' }, accountAddress, privateKey, fee);
|
await registry.createBond({ denom: 'aphoton', amount: '100' }, accountAddress, privateKey, fee);
|
||||||
|
await wait(5000)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Get bond by ID.', async () => {
|
||||||
|
const [bond] = await registry.getBondsByIds([bondId1]);
|
||||||
|
expect(bond).toBeDefined();
|
||||||
|
expect(bond.id).toBe(bondId1);
|
||||||
|
expect(bond.balance).toHaveLength(1);
|
||||||
|
expect(bond.balance[0]).toEqual({ type: 'aphoton', quantity: '100' });
|
||||||
|
bondOwner = bond.owner;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Query bonds.', async () => {
|
||||||
|
const bonds = await registry.queryBonds();
|
||||||
|
expect(bonds).toBeDefined();
|
||||||
|
const bond = bonds.filter((bond: any) => bond.id === bondId1);
|
||||||
|
expect(bond).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Query bonds by owner.', async () => {
|
||||||
|
const bonds = await registry.queryBonds({ owner: bondOwner });
|
||||||
|
expect(bonds).toBeDefined();
|
||||||
|
const bond = bonds.filter((bond: any) => bond.id === bondId1);
|
||||||
|
expect(bond).toBeDefined();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mockServer) {
|
if (mockServer) {
|
||||||
|
1
src/graphql.d.ts
vendored
Normal file
1
src/graphql.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
declare module 'graphql.js'
|
30
src/index.ts
30
src/index.ts
@ -53,13 +53,17 @@ export class Registry {
|
|||||||
return message.log || DEFAULT_WRITE_ERROR;
|
return message.log || DEFAULT_WRITE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(url: string, cosmosChainId = DEFAULT_CHAIN_ID) {
|
constructor(restUrl: string, gqlUrl: string, cosmosChainId = DEFAULT_CHAIN_ID) {
|
||||||
if (!isUrl(url)) {
|
if (!isUrl(restUrl)) {
|
||||||
throw new Error('Path to a registry GQL endpoint should be provided.');
|
throw new Error('Path to a REST endpoint should be provided.');
|
||||||
}
|
}
|
||||||
|
|
||||||
this._endpoint = url;
|
if (!isUrl(gqlUrl)) {
|
||||||
this._client = new RegistryClient(url);
|
throw new Error('Path to a GQL endpoint should be provided.');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._endpoint = restUrl;
|
||||||
|
this._client = new RegistryClient(restUrl, gqlUrl);
|
||||||
|
|
||||||
this._chain = {
|
this._chain = {
|
||||||
chainId: 9000,
|
chainId: 9000,
|
||||||
@ -85,7 +89,7 @@ export class Registry {
|
|||||||
const accountObj = account.base_account;
|
const accountObj = account.base_account;
|
||||||
|
|
||||||
const nextSeq = parseInt(accountObj.sequence, 10) + 1;
|
const nextSeq = parseInt(accountObj.sequence, 10) + 1;
|
||||||
result = sha256(`${accountObj.address}:${accountObj.number}:${nextSeq}`);
|
result = sha256(`${accountObj.address}:${accountObj.account_number}:${nextSeq}`);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const error = err[0] || err;
|
const error = err[0] || err;
|
||||||
throw new Error(Registry.processWriteError(error));
|
throw new Error(Registry.processWriteError(error));
|
||||||
@ -94,6 +98,20 @@ export class Registry {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get bonds by ids.
|
||||||
|
*/
|
||||||
|
async getBondsByIds(ids: string[]) {
|
||||||
|
return this._client.getBondsByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query bonds by attributes.
|
||||||
|
*/
|
||||||
|
async queryBonds(attributes = {}) {
|
||||||
|
return this._client.queryBonds(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create bond.
|
* Create bond.
|
||||||
*/
|
*/
|
||||||
|
@ -1,22 +1,43 @@
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import graphqlClient from 'graphql.js'
|
||||||
import { generateEndpointAccount, generateEndpointBroadcast, generatePostBodyBroadcast } from '@tharsis/provider';
|
import { generateEndpointAccount, generateEndpointBroadcast, generatePostBodyBroadcast } from '@tharsis/provider';
|
||||||
|
|
||||||
|
import { Util } from './util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registry
|
* Registry
|
||||||
*/
|
*/
|
||||||
export class RegistryClient {
|
export class RegistryClient {
|
||||||
_endpoint: string
|
_restEndpoint: string
|
||||||
|
_graph: any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get query result.
|
||||||
|
*/
|
||||||
|
static async getResult(query: any, key: string, modifier?: (rows: any[]) => {}) {
|
||||||
|
const result = await query;
|
||||||
|
if (result && result[key] && result[key].length && result[key][0] !== null) {
|
||||||
|
if (modifier) {
|
||||||
|
return modifier(result[key]);
|
||||||
|
}
|
||||||
|
return result[key];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* New Client.
|
* New Client.
|
||||||
* @param {string} endpoint
|
|
||||||
* @param {object} options
|
|
||||||
*/
|
*/
|
||||||
constructor(endpoint: string) {
|
constructor(restEndpoint: string, gqlEndpoint: string) {
|
||||||
assert(endpoint);
|
assert(restEndpoint);
|
||||||
|
|
||||||
this._endpoint = endpoint;
|
this._restEndpoint = restEndpoint;
|
||||||
|
|
||||||
|
this._graph = graphqlClient(gqlEndpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
asJSON: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,11 +46,58 @@ export class RegistryClient {
|
|||||||
async getAccount(address: string) {
|
async getAccount(address: string) {
|
||||||
assert(address);
|
assert(address);
|
||||||
|
|
||||||
let { data } = await axios.get(`${this._endpoint}${generateEndpointAccount(address)}`)
|
let { data } = await axios.get(`${this._restEndpoint}${generateEndpointAccount(address)}`)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get bonds by ids.
|
||||||
|
*/
|
||||||
|
async getBondsByIds(ids: string[]) {
|
||||||
|
assert(ids);
|
||||||
|
assert(ids.length);
|
||||||
|
|
||||||
|
const query = `query ($ids: [String!]) {
|
||||||
|
getBondsByIds(ids: $ids) {
|
||||||
|
id
|
||||||
|
owner
|
||||||
|
balance {
|
||||||
|
type
|
||||||
|
quantity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const variables = {
|
||||||
|
ids
|
||||||
|
};
|
||||||
|
|
||||||
|
return RegistryClient.getResult(this._graph(query)(variables), 'getBondsByIds');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get records by attributes.
|
||||||
|
*/
|
||||||
|
async queryBonds(attributes = {}) {
|
||||||
|
const query = `query ($attributes: [KeyValueInput!]) {
|
||||||
|
queryBonds(attributes: $attributes) {
|
||||||
|
id
|
||||||
|
owner
|
||||||
|
balance {
|
||||||
|
type
|
||||||
|
quantity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const variables = {
|
||||||
|
attributes: Util.toGQLAttributes(attributes)
|
||||||
|
};
|
||||||
|
|
||||||
|
return RegistryClient.getResult(this._graph(query)(variables), 'queryBonds');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit transaction.
|
* Submit transaction.
|
||||||
*/
|
*/
|
||||||
@ -38,7 +106,7 @@ export class RegistryClient {
|
|||||||
|
|
||||||
// Broadcast transaction.
|
// Broadcast transaction.
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`${this._endpoint}${generateEndpointBroadcast()}`,
|
`${this._restEndpoint}${generateEndpointBroadcast()}`,
|
||||||
tx
|
tx
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
const DEFAULT_PRIVATE_KEY = '0451f0bd95c855d52e76cdc8dd06f29097b944bfef26d3455725157f9133f4e0';
|
const DEFAULT_PRIVATE_KEY = '794ce0bf3c75571416001c3415e69059aeba54038bcac8ce5b9792259e6d193b';
|
||||||
const DEFAULT_ADDRESS = 'ethm19n3je0lhuk0w9kmkftsuw4etn8lmpu3jjfayeh'
|
const DEFAULT_ADDRESS = 'ethm10atmndy7sm46829rc3yr7cxqucgrz5e9jg58xp'
|
||||||
|
|
||||||
|
export const wait = (time: number) => new Promise(resolve => setTimeout(resolve, time))
|
||||||
|
|
||||||
export const getConfig = () => ({
|
export const getConfig = () => ({
|
||||||
mockServer: process.env.MOCK_SERVER || false,
|
mockServer: process.env.MOCK_SERVER || false,
|
||||||
@ -7,7 +9,8 @@ export const getConfig = () => ({
|
|||||||
chainId: process.env.CHIBA_CLONK_CHAIN_ID || 'ethermint_9000-1',
|
chainId: process.env.CHIBA_CLONK_CHAIN_ID || 'ethermint_9000-1',
|
||||||
privateKey: DEFAULT_PRIVATE_KEY,
|
privateKey: DEFAULT_PRIVATE_KEY,
|
||||||
accountAddress: DEFAULT_ADDRESS,
|
accountAddress: DEFAULT_ADDRESS,
|
||||||
endpoint: process.env.CHIBA_CLONK_ENDPOINT || 'http://localhost:1317',
|
restEndpoint: process.env.CHIBA_CLONK_REST_ENDPOINT || 'http://localhost:1317',
|
||||||
|
gqlEndpoint: process.env.CHIBA_CLONK_GQL_ENDPOINT || 'http://localhost:9473/api',
|
||||||
fee: {
|
fee: {
|
||||||
amount: '20',
|
amount: '20',
|
||||||
denom: 'aphoton',
|
denom: 'aphoton',
|
||||||
|
79
src/util.ts
Normal file
79
src/util.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* Utils
|
||||||
|
*/
|
||||||
|
export class Util {
|
||||||
|
/**
|
||||||
|
* Sorts JSON object.
|
||||||
|
*/
|
||||||
|
static sortJSON(object: any) {
|
||||||
|
if (object instanceof Array) {
|
||||||
|
for (let i = 0; i < object.length; i++) {
|
||||||
|
object[i] = Util.sortJSON(object[i]);
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
if (typeof object !== 'object' || object === null) return object;
|
||||||
|
|
||||||
|
let keys = Object.keys(object);
|
||||||
|
keys = keys.sort();
|
||||||
|
const newObject: {[key: string]: any} = {};
|
||||||
|
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
newObject[keys[i]] = Util.sortJSON(object[keys[i]]);
|
||||||
|
}
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marshal object into gql 'attributes' variable.
|
||||||
|
*/
|
||||||
|
static toGQLAttributes(object: any) {
|
||||||
|
const vars: any[] = [];
|
||||||
|
|
||||||
|
Object.keys(object).forEach(key => {
|
||||||
|
let type: string = typeof object[key];
|
||||||
|
if (object[key] === null) {
|
||||||
|
vars.push({ key, value: { 'null': true } });
|
||||||
|
} else if (type === 'number') {
|
||||||
|
type = (object[key] % 1 === 0) ? 'int' : 'float';
|
||||||
|
vars.push({ key, value: { [type]: object[key] } });
|
||||||
|
} else if (type === 'string') {
|
||||||
|
vars.push({ key, value: { 'string': object[key] } });
|
||||||
|
} else if (type === 'boolean') {
|
||||||
|
vars.push({ key, value: { 'boolean': object[key] } });
|
||||||
|
} else if (type === 'object') {
|
||||||
|
const nestedObject = object[key];
|
||||||
|
if (nestedObject['/'] !== undefined) {
|
||||||
|
vars.push({ key, value: { 'reference': { id: nestedObject['/'] } } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmarshal attributes array to object.
|
||||||
|
*/
|
||||||
|
static fromGQLAttributes(attributes: any[] = []) {
|
||||||
|
const res: {[key: string]: any} = {};
|
||||||
|
|
||||||
|
attributes.forEach(attr => {
|
||||||
|
if (attr.value.null) {
|
||||||
|
res[attr.key] = null;
|
||||||
|
} else if (attr.value.json) {
|
||||||
|
res[attr.key] = JSON.parse(attr.value.json);
|
||||||
|
} else if (attr.value.reference) {
|
||||||
|
// Convert GQL reference to IPLD style link.
|
||||||
|
const ref = attr.value.reference;
|
||||||
|
res[attr.key] = { '/': ref.id };
|
||||||
|
} else {
|
||||||
|
const { values, null: n, ...types } = attr.value;
|
||||||
|
const value = Object.values(types).find(v => v !== null);
|
||||||
|
res[attr.key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
@ -2220,6 +2220,11 @@ graceful-fs@^4.2.9:
|
|||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
|
||||||
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
|
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
|
||||||
|
|
||||||
|
graphql.js@^0.6.8:
|
||||||
|
version "0.6.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/graphql.js/-/graphql.js-0.6.8.tgz#5c2e57311b5e74c6665ff9394394bc76f273542f"
|
||||||
|
integrity sha512-y1OxsvPCfBell00yb2T1E+JQjFXzbmqDT3hsf7Ckof80DlRuQ3SrmLL7KC04Up81vlBj+l9opYJjDLf9OgMH3w==
|
||||||
|
|
||||||
has-flag@^3.0.0:
|
has-flag@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||||
|
Loading…
Reference in New Issue
Block a user