Skip to content

Commit

Permalink
add client wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
thomas-nguy committed Apr 20, 2021
1 parent 4c98f96 commit d19ee16
Show file tree
Hide file tree
Showing 25 changed files with 233 additions and 11 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ coverage

# Generated docs file
docs/dist/

# Yarn
yarn.lock
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,33 @@ console.log(signedTx.getHexEncoded());
// Note that the result of signedTx.getHexEncoded() can be directly broadcasted to the network as a raw tx
```

### 1.4. Sending transactions 📨

The SDK uses cosmjs stargate client to send transactions. For more information, check
https://github.com/cosmos/cosmjs/tree/main/packages/stargate

```javascript
// Imports
const sdk = require("@crypto-com/chain-jslib");
const cro = sdk.CroSDK({ network: sdk.CroNetwork.Testnet });
const client = await cro.CroClient.connect();
await client.broadcastTx(signedTx.encode().toUint8Array());
```

### 1.5. Query the chain ❓
The SDK uses cosmjs queryclient to query the blockchain. For more information, check
https://github.com/cosmos/cosmjs/tree/main/packages/stargate/src/queries

```javascript
// Imports
const sdk = require("@crypto-com/chain-jslib");
const cro = sdk.CroSDK({ network: sdk.CroNetwork.Testnet });
const client = await cro.CroClient.connect();
const queryResult = await client.query().<module>.<operation>
// example client.query().bank.allBalances(<address>)
```


## 2. Cosmos Protobuf Definitions

### Generate Cosmos Protobuf Definitions in JavaScript
Expand Down
21 changes: 11 additions & 10 deletions lib/e2e/transaction.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'mocha';
import Big from 'big.js';
import { expect } from 'chai';
import { StargateClient, assertIsBroadcastTxSuccess } from '@cosmjs/stargate';
import { assertIsBroadcastTxSuccess } from '@cosmjs/stargate';
import axios from 'axios';

import { HDKey } from '../src/hdkey/hdkey';
Expand All @@ -25,6 +25,7 @@ const customNetwork: Network = {
coinType: 1,
account: 0,
},
rpcUrl: 'http://localhost:26657',
};

const testNode = {
Expand Down Expand Up @@ -72,7 +73,7 @@ describe('e2e test suite', function () {
const address1 = new cro.Address(keyPair.getPubKey());
const address2 = new cro.Address(keyPair2.getPubKey());
const randomAddress = new cro.Address(randomKeyPair.getPubKey());
const client = await StargateClient.connect(`${testNode.httpEndpoint}:${testNode.httpPort}`);
const client = await cro.CroClient.connect();

const msgSend1 = new cro.bank.MsgSend({
fromAddress: address1.account(),
Expand Down Expand Up @@ -139,7 +140,7 @@ describe('e2e test suite', function () {
const address1 = new cro.Address(keyPair.getPubKey());
const address2 = new cro.Address(keyPair2.getPubKey());
const randomAddress = new cro.Address(randomKeyPair.getPubKey());
const client = await StargateClient.connect(`${testNode.httpEndpoint}:${testNode.httpPort}`);
const client = await cro.CroClient.connect();

const msgSend1 = new cro.bank.MsgSend({
fromAddress: address1.account(),
Expand Down Expand Up @@ -202,7 +203,7 @@ describe('e2e test suite', function () {
delegatorAddress: address1.account(),
});

const client = await StargateClient.connect(`${testNode.httpEndpoint}:${testNode.httpPort}`);
const client = await cro.CroClient.connect();

expect(client).to.be.not.undefined;
const account = await client.getAccount(address1.account());
Expand Down Expand Up @@ -235,7 +236,7 @@ describe('e2e test suite', function () {
delegatorAddress: address1.account(),
});

const client = await StargateClient.connect(`${testNode.httpEndpoint}:${testNode.httpPort}`);
const client = await cro.CroClient.connect();

expect(client).to.be.not.undefined;
const account = await client.getAccount(address1.account());
Expand Down Expand Up @@ -282,7 +283,7 @@ describe('e2e test suite', function () {
value: new cro.Coin('1000000000', Units.BASE),
});

const client = await StargateClient.connect(`${testNode.httpEndpoint}:${testNode.httpPort}`);
const client = await cro.CroClient.connect();

expect(client).to.be.not.undefined;
const account = await client.getAccount(addressAccount.account());
Expand Down Expand Up @@ -318,7 +319,7 @@ describe('e2e test suite', function () {
minSelfDelegation: null,
});

const client = await StargateClient.connect(`${testNode.httpEndpoint}:${testNode.httpPort}`);
const client = await cro.CroClient.connect();

expect(client).to.be.not.undefined;
const account = await client.getAccount(address1.account());
Expand Down Expand Up @@ -352,7 +353,7 @@ describe('e2e test suite', function () {
delegatorAddress: address1.account(),
});

const client = await StargateClient.connect(`${testNode.httpEndpoint}:${testNode.httpPort}`);
const client = await cro.CroClient.connect();

expect(client).to.be.not.undefined;
const account = await client.getAccount(address1.account());
Expand Down Expand Up @@ -384,7 +385,7 @@ describe('e2e test suite', function () {
delegatorAddress: address1.account(),
});

const client = await StargateClient.connect(`${testNode.httpEndpoint}:${testNode.httpPort}`);
const client = await cro.CroClient.connect();

expect(client).to.be.not.undefined;
const account = await client.getAccount(address1.account());
Expand Down Expand Up @@ -415,7 +416,7 @@ describe('e2e test suite', function () {
validatorAddress: address1.validator(),
});

const client = await StargateClient.connect(`${testNode.httpEndpoint}:${testNode.httpPort}`);
const client = await cro.CroClient.connect();

expect(client).to.be.not.undefined;
const account = await client.getAccount(address1.account());
Expand Down
41 changes: 41 additions & 0 deletions lib/src/client/client.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { expect } from 'chai';
import { fuzzyDescribe } from '../test/mocha-fuzzy/suite';

import { CroNetwork, CroSDK } from '../core/cro';

const cro = CroSDK({ network: CroNetwork.Testnet });

describe('CroClient', function () {
describe('connect', function () {
fuzzyDescribe('should throw Error when the provided argument is not url', function (fuzzy) {
const testRunner = fuzzy(fuzzy.StringArg('test'));
testRunner(
async function (args0) {
if (args0.valid) {
return;
}
try {
await cro.CroClient.connect(args0.value);
} catch (e) {
expect(e.toString()).to.be.contain(
'ArgumentError: Expected `endpoint` to be of type `string` but received type',
);
}
},
{ invalidArgsOnly: true },
);
});

context('When input is a string', function () {
it('should throw Error when the provided string is not a url', async function () {
try {
await cro.CroClient.connect('invalid');
} catch (e) {
expect(e.toString()).to.be.equals(
'ArgumentError: Expected string `endpoint` to be an url, got `invalid`',
);
}
});
});
});
});
121 changes: 121 additions & 0 deletions lib/src/client/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
import {
StargateClient,
QueryClient,
AuthExtension,
BankExtension,
DistributionExtension,
StakingExtension,
setupAuthExtension,
setupBankExtension,
setupDistributionExtension,
setupStakingExtension,
} from '@cosmjs/stargate';
import { Account } from '@cosmjs/stargate/build/accounts';
import { Coin } from '@cosmjs/stargate/build/codec/cosmos/base/v1beta1/coin';
import { SearchTxFilter, SearchTxQuery } from '@cosmjs/stargate/build/search';
import { Block, BroadcastTxResponse, IndexedTx, SequenceResponse } from '@cosmjs/stargate/build/stargateclient';
import ow from 'ow';
import { InitConfigurations } from '../core/cro';
import { owUrl } from './ow.types';

export interface ICroClient {
query(): (QueryClient & AuthExtension & BankExtension & DistributionExtension & StakingExtension) | undefined;
getChainId(): Promise<string>;
getHeight(): Promise<number>;
getAccount(searchAddress: string): Promise<Account | null>;
getAccountVerified(searchAddress: string): Promise<Account | null>;
getSequence(address: string): Promise<SequenceResponse>;
getBlock(height?: number): Promise<Block>;
getCroBalance(address: string): Promise<Coin>;
getTx(id: string): Promise<IndexedTx | null>;
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
disconnect(): void;
broadcastTx(tx: Uint8Array): Promise<BroadcastTxResponse>;
}

export const croClient = function (config: InitConfigurations) {
return class CroClient implements ICroClient {
tmClient: Tendermint34Client;

baseDenom: string;

readonly txClient: StargateClient;

readonly queryClient:
| (QueryClient & AuthExtension & BankExtension & DistributionExtension & StakingExtension)
| undefined;

private constructor(tmClient: Tendermint34Client, txClient: StargateClient) {
this.txClient = txClient;
this.tmClient = tmClient;
this.queryClient = QueryClient.withExtensions(
tmClient,
setupAuthExtension,
setupBankExtension,
setupStakingExtension,
setupDistributionExtension,
);

this.baseDenom = config.network.coin.baseDenom;
}

public static async connect(endpoint: string = config.network.rpcUrl): Promise<CroClient> {
ow(endpoint, 'endpoint', owUrl);
const tmClient = await Tendermint34Client.connect(endpoint);
const txClient = await StargateClient.connect(endpoint);
return new CroClient(tmClient, txClient);
}

public disconnect(): void {
if (this.tmClient) this.tmClient.disconnect();
if (this.txClient) this.txClient.disconnect();
}

public query():
| (QueryClient & AuthExtension & BankExtension & DistributionExtension & StakingExtension)
| undefined {
return this.queryClient;
}

public async getChainId(): Promise<string> {
return this.txClient.getChainId();
}

public async getHeight(): Promise<number> {
return this.txClient.getHeight();
}

public async getAccount(searchAddress: string): Promise<Account | null> {
return this.txClient.getAccount(searchAddress);
}

public async getAccountVerified(searchAddress: string): Promise<Account | null> {
return this.txClient.getAccountVerified(searchAddress);
}

public async getSequence(address: string): Promise<SequenceResponse> {
return this.txClient.getSequence(address);
}

public async getBlock(height?: number): Promise<Block> {
return this.txClient.getBlock(height);
}

public async getCroBalance(address: string): Promise<Coin> {
return this.txClient.getBalance(address, this.baseDenom);
}

public async getTx(id: string): Promise<IndexedTx | null> {
return this.txClient.getTx(id);
}

public async searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]> {
return this.txClient.searchTx(query, filter);
}

public async broadcastTx(tx: Uint8Array): Promise<BroadcastTxResponse> {
return this.txClient.broadcastTx(tx);
}
};
};
6 changes: 6 additions & 0 deletions lib/src/client/ow.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import ow from 'ow';

export const owUrl = ow.string.validate((val) => ({
validator: val.startsWith('http://') || val.startsWith('https://'),
message: (label) => `Expected ${label} to be an url, got \`${val}\``,
}));
4 changes: 4 additions & 0 deletions lib/src/core/cro.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ow from 'ow';

import { croClient } from '../client/client';
import { Network } from '../network/network';
import { coin } from '../coin/coin';
import { owCroSDKInitParams } from './ow.types';
Expand All @@ -24,6 +25,7 @@ export const CroSDK = function (configs: InitConfigurations) {
ow(configs, 'configs', owCroSDKInitParams);

return {
CroClient: croClient(configs),
Coin: coin(configs),
RawTransaction: rawTransaction(configs),
Address: userAddress(configs),
Expand Down Expand Up @@ -71,6 +73,7 @@ export class CroNetwork {
coinType: 1,
account: 0,
},
rpcUrl: 'https://testnet-croeseid.crypto.org:26657',
};

public static Mainnet: Network = {
Expand All @@ -87,6 +90,7 @@ export class CroNetwork {
coinType: 394,
account: 0,
},
rpcUrl: 'https://mainnet.crypto.org:26657',
};
}

Expand Down
1 change: 1 addition & 0 deletions lib/src/network/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export type Network = {
coinType: number;
account: number;
};
rpcUrl: string;
};
1 change: 1 addition & 0 deletions lib/src/network/ow.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export const owNetwork = () =>
coinType: ow.number,
account: ow.number,
}),
rpcUrl: ow.string,
});
1 change: 1 addition & 0 deletions lib/src/transaction/amino.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('Amino JSON sign mode', function () {
coinType: 1,
account: 0,
},
rpcUrl: '',
},
});
const msg = new cro.bank.MsgSend({
Expand Down
1 change: 1 addition & 0 deletions lib/src/transaction/msg/bank/msgsend.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const cro = CroSDK({
coinType: 1,
account: 0,
},
rpcUrl: '',
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const cro = CroSDK({
coinType: 1,
account: 0,
},
rpcUrl: '',
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const cro = CroSDK({
coinType: 1,
account: 0,
},
rpcUrl: '',
},
});

Expand Down
1 change: 1 addition & 0 deletions lib/src/transaction/msg/gov/MsgDeposit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const cro = CroSDK({
coinType: 1,
account: 0,
},
rpcUrl: '',
},
});

Expand Down
Loading

0 comments on commit d19ee16

Please sign in to comment.