Update transaction response parsing (#4)

Part of https://www.notion.so/Create-laconic-registry-SDK-d3a636d4aba44f7cbba3bd99b7146811

- Handle errors in the tx response
- Move response parsing to client class
- Run previously skipped naming tests

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
Reviewed-on: #4
Co-authored-by: Prathamesh Musale <prathamesh@noreply.git.vdb.to>
Co-committed-by: Prathamesh Musale <prathamesh@noreply.git.vdb.to>
This commit is contained in:
Prathamesh Musale 2024-03-12 04:55:59 +00:00 committed by nabarun
parent 8d3c35b22e
commit 7fe256e714
4 changed files with 99 additions and 136 deletions

View File

@ -6,7 +6,7 @@ import { DENOM } from './constants';
const WATCHER_YML_PATH = path.join(__dirname, './testing/data/watcher.yml');
const BOND_AMOUNT = '10000';
const BOND_AMOUNT = '1000000000';
const { chainId, restEndpoint, gqlEndpoint, privateKey, fee } = getConfig();
jest.setTimeout(90 * 1000);
@ -99,7 +99,7 @@ const bondTests = () => {
bondId1 = await registry.getNextBondId(privateKey);
expect(bondId1).toBeDefined();
await registry.createBond({ denom: DENOM, amount: '1000000000' }, privateKey, fee);
await registry.createBond({ denom: DENOM, amount: BOND_AMOUNT }, privateKey, fee);
// Create a new record.
let watcher = await publishNewWatcherVersion(bondId1);
@ -124,7 +124,7 @@ const bondTests = () => {
bondId1 = await registry.getNextBondId(privateKey);
expect(bondId1).toBeDefined();
await registry.createBond({ denom: DENOM, amount: '1000000000' }, privateKey, fee);
await registry.createBond({ denom: DENOM, amount: BOND_AMOUNT }, privateKey, fee);
// Create a new record version.
let watcher = await publishNewWatcherVersion(bondId1);
@ -141,7 +141,7 @@ const bondTests = () => {
// Create another bond.
bondId2 = await registry.getNextBondId(privateKey);
expect(bondId2).toBeDefined();
await registry.createBond({ denom: DENOM, amount: '1000000000' }, privateKey, fee);
await registry.createBond({ denom: DENOM, amount: BOND_AMOUNT }, privateKey, fee);
const [bond] = await registry.getBondsByIds([bondId2]);
expect(bond.id).toBe(bondId2);

View File

@ -42,8 +42,6 @@ import { Coin } from './proto2/cosmos/base/v1beta1/coin';
export const DEFAULT_CHAIN_ID = 'laconic_9000-1';
const DEFAULT_WRITE_ERROR = 'Unable to write to laconicd.';
// Parse Tx response from cosmos-sdk.
export const parseTxResponse = (result: any, parseResponse?: (data: string) => any) => {
const { txhash: hash, height, ...txResponse } = result;
@ -96,18 +94,6 @@ export class Registry {
_chain: Chain;
_client: RegistryClient;
static processWriteError (error: string) {
// error string a stacktrace containing the message.
// https://gist.github.com/nikugogoi/de55d390574ded3466abad8bffd81952#file-txresponse-js-L7
const errorMessage = NAMESERVICE_ERRORS.find(message => error.includes(message));
if (!errorMessage) {
console.error(error);
}
return errorMessage || DEFAULT_WRITE_ERROR;
}
constructor (gqlUrl: string, restUrl = '', chainId: string = DEFAULT_CHAIN_ID) {
this._endpoints = {
rest: restUrl,
@ -179,12 +165,10 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.setRecord({ privateKey, record, bondId },
return laconicClient.setRecord({ privateKey, record, bondId },
account.address,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -251,14 +235,12 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.createBond(
return laconicClient.createBond(
account.address,
denom,
amount,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -269,15 +251,13 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.refillBond(
return laconicClient.refillBond(
account.address,
denom,
amount,
id,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -288,15 +268,13 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.withdrawBond(
return laconicClient.withdrawBond(
account.address,
denom,
amount,
id,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -307,13 +285,11 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.cancelBond(
return laconicClient.cancelBond(
account.address,
id,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -324,14 +300,12 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.associateBond(
return laconicClient.associateBond(
account.address,
recordId,
bondId,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -342,13 +316,11 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.dissociateBond(
return laconicClient.dissociateBond(
account.address,
recordId,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -359,13 +331,11 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.dissociateRecords(
return laconicClient.dissociateRecords(
account.address,
bondId,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -376,14 +346,12 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.reassociateRecords(
return laconicClient.reassociateRecords(
account.address,
oldBondId,
newBondId,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -393,15 +361,13 @@ export class Registry {
const account = new Account(Buffer.from(privateKey, 'hex'));
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.reserveAuthority(
return laconicClient.reserveAuthority(
account.address,
name,
owner || account.address,
fee
);
// TODO: Parse error response
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -411,14 +377,13 @@ export class Registry {
const account = new Account(Buffer.from(privateKey, 'hex'));
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.setAuthorityBond(
return laconicClient.setAuthorityBond(
account.address,
bondId,
name,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -428,14 +393,13 @@ export class Registry {
const account = new Account(Buffer.from(privateKey, 'hex'));
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.commitBid(
return laconicClient.commitBid(
account.address,
auctionId,
commitHash,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -445,14 +409,12 @@ export class Registry {
const account = new Account(Buffer.from(privateKey, 'hex'));
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.revealBid(
return laconicClient.revealBid(
account.address,
auctionId,
reveal,
fee
);
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -477,15 +439,12 @@ export class Registry {
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.setName(
return laconicClient.setName(
account.address,
lrn,
cid,
fee
);
// TODO: Parse error response
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
@ -502,43 +461,11 @@ export class Registry {
const account = new Account(Buffer.from(privateKey, 'hex'));
await account.init();
const laconicClient = await this.getLaconicClient(account);
const response: DeliverTxResponse = await laconicClient.deleteName(
return laconicClient.deleteName(
account.address,
lrn,
fee
);
// TODO: Parse error response form delete name
return laconicClient.registry.decode(response.msgResponses[0]);
}
/**
* Submit a generic Tx to the chain.
*/
async _submitTx (message: any, privateKey: string, sender: Sender) {
// Check private key.
if (!isKeyValid(privateKey)) {
throw new Error('Registry privateKey should be a hex string.');
}
// Check that the account exists on-chain.
const account = new Account(Buffer.from(privateKey, 'hex'));
// Generate signed Tx.
const transaction = createTransaction(message, account, sender, this._chain);
const tx = generatePostBodyBroadcast(transaction, BroadcastMode.Block);
// Submit Tx to chain.
const { tx_response: response } = await this._client.submit(tx);
if (response.code !== 0) {
// Throw error when transaction is not successful.
// https://docs.starport.com/guide/nameservice/05-play.html#buy-name-transaction-details
throw new Error(Registry.processWriteError(response.raw_log));
}
return response;
}
/**

View File

@ -13,10 +13,15 @@ import { MsgCancelBondEncodeObject, MsgCreateBondEncodeObject, MsgRefillBondEnco
import { Coin } from './proto2/cosmos/base/v1beta1/coin';
import { MsgAssociateBondEncodeObject, MsgDeleteNameAuthorityEncodeObject, MsgDissociateBondEncodeObject, MsgDissociateRecordsEncodeObject, MsgReassociateRecordsEncodeObject, MsgReserveAuthorityEncodeObject, MsgSetAuthorityBondEncodeObject, MsgSetNameEncodeObject, MsgSetRecordEncodeObject, registryTypes, typeUrlMsgAssociateBond, typeUrlMsgDeleteNameAuthority, typeUrlMsgDissociateBond, typeUrlMsgDissociateRecords, typeUrlMsgReassociateRecords, typeUrlMsgReserveAuthority, typeUrlMsgSetAuthorityBond, typeUrlMsgSetName, typeUrlMsgSetRecord } from './types/cerc/registry/message';
import { MsgCommitBidEncodeObject, MsgRevealBidEncodeObject, auctionTypes, typeUrlMsgCommitBid, typeUrlMsgRevealBid } from './types/cerc/auction/message';
import { Payload } from './proto2/cerc/registry/v1/tx';
import { MsgAssociateBondResponse, MsgDeleteNameAuthorityResponse, MsgDissociateBondResponse, MsgDissociateRecordsResponse, MsgReassociateRecordsResponse, MsgReserveAuthorityResponse, MsgSetAuthorityBondResponse, MsgSetNameResponse, MsgSetRecordResponse, Payload } from './proto2/cerc/registry/v1/tx';
import { Record, Signature } from './proto2/cerc/registry/v1/registry';
import { Account } from './account';
import { Util } from './util';
import { NAMESERVICE_ERRORS } from './messages/registry';
import { MsgCommitBidResponse, MsgRevealBidResponse } from './proto2/cerc/auction/v1/tx';
import { MsgCancelBondResponse, MsgCreateBondResponse, MsgRefillBondResponse, MsgWithdrawBondResponse } from './proto2/cerc/bond/v1/tx';
const DEFAULT_WRITE_ERROR = 'Unable to write to laconicd.';
export const laconicDefaultRegistryTypes: ReadonlyArray<[string, GeneratedType]> = [
...defaultRegistryTypes,
@ -48,7 +53,7 @@ export class LaconicClient extends SigningStargateClient {
amount: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgCreateBondEncodeObject = {
typeUrl: typeUrlMsgCreateBond,
value: {
@ -62,7 +67,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgCreateBondResponse>(response);
}
public async refillBond (
@ -72,7 +78,7 @@ export class LaconicClient extends SigningStargateClient {
id: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgRefillBondEncodeObject = {
typeUrl: typeUrlMsgRefillBond,
value: {
@ -87,7 +93,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgRefillBondResponse>(response);
}
public async withdrawBond (
@ -97,7 +104,7 @@ export class LaconicClient extends SigningStargateClient {
id: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgWithdrawBondEncodeObject = {
typeUrl: typeUrlMsgWithdrawBond,
value: {
@ -112,7 +119,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgWithdrawBondResponse>(response);
}
public async cancelBond (
@ -120,7 +128,7 @@ export class LaconicClient extends SigningStargateClient {
id: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgCancelBondEncodeObject = {
typeUrl: typeUrlMsgCancelBond,
value: {
@ -129,7 +137,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgCancelBondResponse>(response);
}
public async associateBond (
@ -138,7 +147,7 @@ export class LaconicClient extends SigningStargateClient {
bondId: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgAssociateBondEncodeObject = {
typeUrl: typeUrlMsgAssociateBond,
value: {
@ -148,7 +157,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgAssociateBondResponse>(response);
}
public async dissociateBond (
@ -156,7 +166,7 @@ export class LaconicClient extends SigningStargateClient {
recordId: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgDissociateBondEncodeObject = {
typeUrl: typeUrlMsgDissociateBond,
value: {
@ -165,7 +175,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgDissociateBondResponse>(response);
}
public async dissociateRecords (
@ -173,7 +184,7 @@ export class LaconicClient extends SigningStargateClient {
bondId: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgDissociateRecordsEncodeObject = {
typeUrl: typeUrlMsgDissociateRecords,
value: {
@ -182,7 +193,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgDissociateRecordsResponse>(response);
}
public async reassociateRecords (
@ -191,7 +203,7 @@ export class LaconicClient extends SigningStargateClient {
newBondId: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgReassociateRecordsEncodeObject = {
typeUrl: typeUrlMsgReassociateRecords,
value: {
@ -201,7 +213,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgReassociateRecordsResponse>(response);
}
public async reserveAuthority (
@ -210,7 +223,7 @@ export class LaconicClient extends SigningStargateClient {
owner: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgReserveAuthorityEncodeObject = {
typeUrl: typeUrlMsgReserveAuthority,
value: {
@ -220,7 +233,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgReserveAuthorityResponse>(response);
}
public async commitBid (
@ -229,7 +243,7 @@ export class LaconicClient extends SigningStargateClient {
commitHash: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgCommitBidEncodeObject = {
typeUrl: typeUrlMsgCommitBid,
value: {
@ -239,7 +253,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgCommitBidResponse>(response);
}
public async revealBid (
@ -248,7 +263,7 @@ export class LaconicClient extends SigningStargateClient {
reveal: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgRevealBidEncodeObject = {
typeUrl: typeUrlMsgRevealBid,
value: {
@ -258,7 +273,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgRevealBidResponse>(response);
}
public async setRecord (
@ -266,7 +282,7 @@ export class LaconicClient extends SigningStargateClient {
signer: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const registryRecord = Record.fromPartial({ attributes: Buffer.from(JSON.stringify(params.record), 'binary') });
// Sign record.
@ -288,7 +304,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgSetRecordResponse>(response);
}
public async setAuthorityBond (
@ -297,7 +314,7 @@ export class LaconicClient extends SigningStargateClient {
name: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgSetAuthorityBondEncodeObject = {
typeUrl: typeUrlMsgSetAuthorityBond,
value: {
@ -307,7 +324,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgSetAuthorityBondResponse>(response);
}
public async setName (
@ -316,7 +334,7 @@ export class LaconicClient extends SigningStargateClient {
cid: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgSetNameEncodeObject = {
typeUrl: typeUrlMsgSetName,
value: {
@ -326,7 +344,8 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgSetNameResponse>(response);
}
public async deleteName (
@ -334,7 +353,7 @@ export class LaconicClient extends SigningStargateClient {
lrn: string,
fee: StdFee | 'auto' | number,
memo = ''
): Promise<DeliverTxResponse> {
) {
const createMsg: MsgDeleteNameAuthorityEncodeObject = {
typeUrl: typeUrlMsgDeleteNameAuthority,
value: {
@ -343,6 +362,28 @@ export class LaconicClient extends SigningStargateClient {
}
};
return this.signAndBroadcast(signer, [createMsg], fee, memo);
const response = await this.signAndBroadcast(signer, [createMsg], fee, memo);
return this.parseResponse<MsgDeleteNameAuthorityResponse>(response);
}
parseResponse<T> (response: DeliverTxResponse): T {
if (response.code !== 0) {
// Throw error when transaction is not successful.
throw new Error(this.processWriteError(response.rawLog || 'No raw log in response'));
}
return this.registry.decode(response.msgResponses[0]) as T;
}
processWriteError (error: string) {
// error string a stacktrace containing the message.
// https://gist.github.com/nikugogoi/de55d390574ded3466abad8bffd81952#file-txresponse-js-L7
const errorMessage = NAMESERVICE_ERRORS.find(message => error.includes(message));
if (!errorMessage) {
console.error(error);
}
return errorMessage || DEFAULT_WRITE_ERROR;
}
}

View File

@ -75,8 +75,7 @@ const namingTests = () => {
expect(Number(record.height)).toBe(0);
});
// TODO: Implement parse error response
xtest('Reserve already reserved authority', async () => {
test('Reserve already reserved authority', async () => {
await expect(registry.reserveAuthority({ name: authorityName }, privateKey, fee))
.rejects.toThrow('Name already reserved.');
});
@ -115,8 +114,7 @@ const namingTests = () => {
expect(Number(record.height)).toBeGreaterThan(0);
});
// TODO: Parse error response from set name
xtest('Set name for unbonded authority', async () => {
test('Set name for unbonded authority', async () => {
assert(watcherId);
await expect(registry.setName({ lrn, cid: watcherId }, privateKey, fee))
.rejects.toThrow('Authority bond not found.');
@ -269,14 +267,12 @@ const namingTests = () => {
});
});
// TODO: Parse error response form set name
xtest('Set name without reserving authority', async () => {
test('Set name without reserving authority', async () => {
await expect(registry.setName({ lrn: 'lrn://not-reserved/app/test', cid: watcherId }, privateKey, fee))
.rejects.toThrow('Name authority not found.');
});
// TODO: Parse error response form set name
xtest('Set name for non-owned authority', async () => {
test('Set name for non-owned authority', async () => {
await registry.sendCoins({ denom: DENOM, amount: '1000000000', destinationAddress: otherAccount.address }, privateKey, fee);
// Other account reserves an authority.
@ -286,8 +282,7 @@ const namingTests = () => {
await expect(registry.setName({ lrn: `lrn://${otherAuthorityName}/app/test`, cid: watcherId }, privateKey, fee)).rejects.toThrow('Access denied.');
});
// TODO: Parse error response form set name
xtest('Delete name for non-owned authority.', async () => {
test('Delete name for non-owned authority.', async () => {
const otherBondId = await registry.getNextBondId(otherPrivateKey);
await registry.createBond({ denom: DENOM, amount: '1000000' }, otherPrivateKey, fee);
await registry.setAuthorityBond({ name: otherAuthorityName, bondId: otherBondId }, otherPrivateKey, fee);