diff --git a/package.json b/package.json index 18818ce..dafc8bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lum-network/sdk-javascript", - "version": "0.4.5", + "version": "0.4.6", "license": "Apache-2.0", "description": "Javascript SDK library for NodeJS and Web browsers to interact with the Lum Network.", "homepage": "https://github.com/lum-network/sdk-javascript#readme", diff --git a/src/client/LumClient.ts b/src/client/LumClient.ts index dc80794..543992f 100644 --- a/src/client/LumClient.ts +++ b/src/client/LumClient.ts @@ -14,10 +14,11 @@ import { import { BaseAccount } from '../codec/cosmos/auth/v1beta1/auth'; import { LumWallet, LumUtils, LumTypes, LumRegistry } from '..'; +import { BeamExtension, setupBeamExtension as BeamSetupBeamExtension } from '../extensions'; export class LumClient { readonly tmClient: Tendermint34Client; - readonly queryClient: StargateQueryClient & AuthExtension & BankExtension & DistributionExtension & StakingExtension; + readonly queryClient: StargateQueryClient & AuthExtension & BankExtension & DistributionExtension & StakingExtension & BeamExtension; private chainId?: string; /** @@ -27,7 +28,14 @@ export class LumClient { */ constructor(tmClient: Tendermint34Client) { this.tmClient = tmClient; - this.queryClient = StargateQueryClient.withExtensions(tmClient, StargateSetupAuthExtension, StargateSetupBankExtension, StargateDistributionExtension, StargateStakingExtension); + this.queryClient = StargateQueryClient.withExtensions( + tmClient, + StargateSetupAuthExtension, + StargateSetupBankExtension, + StargateDistributionExtension, + StargateStakingExtension, + BeamSetupBeamExtension, + ); // Used for debugging while gasWanted, gasUsed and codespace are still waiting to be included in the code lib // // @ts-ignore diff --git a/src/codec/chain/beam/beam.ts b/src/codec/chain/beam/beam.ts index edd782b..34f5f8b 100644 --- a/src/codec/chain/beam/beam.ts +++ b/src/codec/chain/beam/beam.ts @@ -6,21 +6,25 @@ import { Coin } from '../../cosmos/base/v1beta1/coin'; export const protobufPackage = 'lum.network.beam'; export enum BeamState { - OPEN = 0, - CANCELED = 1, - CLOSED = 2, + UNSPECIFIED = 0, + OPEN = 1, + CANCELED = 2, + CLOSED = 3, UNRECOGNIZED = -1, } export function beamStateFromJSON(object: any): BeamState { switch (object) { case 0: + case 'UNSPECIFIED': + return BeamState.UNSPECIFIED; + case 1: case 'OPEN': return BeamState.OPEN; - case 1: + case 2: case 'CANCELED': return BeamState.CANCELED; - case 2: + case 3: case 'CLOSED': return BeamState.CLOSED; case -1: @@ -32,6 +36,8 @@ export function beamStateFromJSON(object: any): BeamState { export function beamStateToJSON(object: BeamState): string { switch (object) { + case BeamState.UNSPECIFIED: + return 'UNSPECIFIED'; case BeamState.OPEN: return 'OPEN'; case BeamState.CANCELED: diff --git a/src/codec/chain/beam/query.ts b/src/codec/chain/beam/query.ts index 6cc7f5f..aa129f4 100644 --- a/src/codec/chain/beam/query.ts +++ b/src/codec/chain/beam/query.ts @@ -11,7 +11,7 @@ export interface QueryGetBeamRequest { } export interface QueryGetBeamResponse { - Beam?: Beam; + beam?: Beam; } export interface QueryFetchBeamsRequest { @@ -19,7 +19,7 @@ export interface QueryFetchBeamsRequest { } export interface QueryFetchBeamsResponse { - Beam: Beam[]; + beams: Beam[]; pagination?: PageResponse; } @@ -82,8 +82,8 @@ const baseQueryGetBeamResponse: object = {}; export const QueryGetBeamResponse = { encode(message: QueryGetBeamResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.Beam !== undefined) { - Beam.encode(message.Beam, writer.uint32(10).fork()).ldelim(); + if (message.beam !== undefined) { + Beam.encode(message.beam, writer.uint32(10).fork()).ldelim(); } return writer; }, @@ -96,7 +96,7 @@ export const QueryGetBeamResponse = { const tag = reader.uint32(); switch (tag >>> 3) { case 1: - message.Beam = Beam.decode(reader, reader.uint32()); + message.beam = Beam.decode(reader, reader.uint32()); break; default: reader.skipType(tag & 7); @@ -108,26 +108,26 @@ export const QueryGetBeamResponse = { fromJSON(object: any): QueryGetBeamResponse { const message = { ...baseQueryGetBeamResponse } as QueryGetBeamResponse; - if (object.Beam !== undefined && object.Beam !== null) { - message.Beam = Beam.fromJSON(object.Beam); + if (object.beam !== undefined && object.beam !== null) { + message.beam = Beam.fromJSON(object.beam); } else { - message.Beam = undefined; + message.beam = undefined; } return message; }, toJSON(message: QueryGetBeamResponse): unknown { const obj: any = {}; - message.Beam !== undefined && (obj.Beam = message.Beam ? Beam.toJSON(message.Beam) : undefined); + message.beam !== undefined && (obj.beam = message.beam ? Beam.toJSON(message.beam) : undefined); return obj; }, fromPartial(object: DeepPartial): QueryGetBeamResponse { const message = { ...baseQueryGetBeamResponse } as QueryGetBeamResponse; - if (object.Beam !== undefined && object.Beam !== null) { - message.Beam = Beam.fromPartial(object.Beam); + if (object.beam !== undefined && object.beam !== null) { + message.beam = Beam.fromPartial(object.beam); } else { - message.Beam = undefined; + message.beam = undefined; } return message; }, @@ -192,7 +192,7 @@ const baseQueryFetchBeamsResponse: object = {}; export const QueryFetchBeamsResponse = { encode(message: QueryFetchBeamsResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - for (const v of message.Beam) { + for (const v of message.beams) { Beam.encode(v!, writer.uint32(10).fork()).ldelim(); } if (message.pagination !== undefined) { @@ -205,12 +205,12 @@ export const QueryFetchBeamsResponse = { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = { ...baseQueryFetchBeamsResponse } as QueryFetchBeamsResponse; - message.Beam = []; + message.beams = []; while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: - message.Beam.push(Beam.decode(reader, reader.uint32())); + message.beams.push(Beam.decode(reader, reader.uint32())); break; case 2: message.pagination = PageResponse.decode(reader, reader.uint32()); @@ -225,10 +225,10 @@ export const QueryFetchBeamsResponse = { fromJSON(object: any): QueryFetchBeamsResponse { const message = { ...baseQueryFetchBeamsResponse } as QueryFetchBeamsResponse; - message.Beam = []; - if (object.Beam !== undefined && object.Beam !== null) { - for (const e of object.Beam) { - message.Beam.push(Beam.fromJSON(e)); + message.beams = []; + if (object.beams !== undefined && object.beams !== null) { + for (const e of object.beams) { + message.beams.push(Beam.fromJSON(e)); } } if (object.pagination !== undefined && object.pagination !== null) { @@ -241,10 +241,10 @@ export const QueryFetchBeamsResponse = { toJSON(message: QueryFetchBeamsResponse): unknown { const obj: any = {}; - if (message.Beam) { - obj.Beam = message.Beam.map((e) => (e ? Beam.toJSON(e) : undefined)); + if (message.beams) { + obj.beams = message.beams.map((e) => (e ? Beam.toJSON(e) : undefined)); } else { - obj.Beam = []; + obj.beams = []; } message.pagination !== undefined && (obj.pagination = message.pagination ? PageResponse.toJSON(message.pagination) : undefined); return obj; @@ -252,10 +252,10 @@ export const QueryFetchBeamsResponse = { fromPartial(object: DeepPartial): QueryFetchBeamsResponse { const message = { ...baseQueryFetchBeamsResponse } as QueryFetchBeamsResponse; - message.Beam = []; - if (object.Beam !== undefined && object.Beam !== null) { - for (const e of object.Beam) { - message.Beam.push(Beam.fromPartial(e)); + message.beams = []; + if (object.beams !== undefined && object.beams !== null) { + for (const e of object.beams) { + message.beams.push(Beam.fromPartial(e)); } } if (object.pagination !== undefined && object.pagination !== null) { diff --git a/src/extensions/beam.ts b/src/extensions/beam.ts new file mode 100644 index 0000000..5d96cb7 --- /dev/null +++ b/src/extensions/beam.ts @@ -0,0 +1,33 @@ +import { createProtobufRpcClient, QueryClient } from '@cosmjs/stargate'; + +import { assert } from '@cosmjs/utils'; + +import { Beam } from '../codec/chain/beam/beam'; +import { QueryClientImpl } from '../codec/chain/beam/query'; + +export interface BeamExtension { + readonly beam: { + readonly get: (id: string) => Promise; + readonly fetch: () => Promise; + }; +} + +export const setupBeamExtension = (base: QueryClient): BeamExtension => { + const rpc = createProtobufRpcClient(base); + const queryService = new QueryClientImpl(rpc); + + return { + beam: { + get: async (id: string) => { + const { beam } = await queryService.Beam({ id }); + assert(beam); + return beam; + }, + fetch: async () => { + const { beams } = await queryService.Beams({}); + assert(beams); + return beams; + }, + }, + }; +}; diff --git a/src/extensions/index.ts b/src/extensions/index.ts new file mode 100644 index 0000000..8f87cbd --- /dev/null +++ b/src/extensions/index.ts @@ -0,0 +1 @@ +export * from './beam'; diff --git a/tests/client.test.ts b/tests/client.test.ts index 1e68aed..7f94bd5 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -1,6 +1,6 @@ import { LumWallet, LumWalletFactory, LumClient, LumUtils, LumConstants, LumRegistry, LumTypes, LumMessages } from '../src'; import axios from 'axios'; -import { BeamData } from "../src/codec/chain/beam/beam"; +import { BeamData, BeamState } from "../src/codec/chain/beam/beam"; const randomString = (): string => { return Math.random().toString(36).substring(7); @@ -47,6 +47,67 @@ describe('LumClient', () => { await expect(clt.disconnect()).resolves.toBeTruthy(); }); + it('should open a beam and close it', async () => { + const beamId = randomString(); + + let acc = await clt.getAccount(w1.getAddress()); + expect(acc).toBeTruthy(); + + const chainId = await clt.getChainId(); + const amount: LumTypes.Coin = { + amount: '1', + denom: LumConstants.MicroLumDenom, + }; + + const fee = { + amount: [{ denom: LumConstants.MicroLumDenom, amount: '1' }], + gas: '100000', + }; + + // Create the beam + let doc = { + accountNumber: acc.accountNumber, + chainId, + fee: fee, + memo: 'Beam review transaction', + messages: [LumMessages.BuildMsgOpenBeam(beamId, w1.getAddress(), '', amount, 'test', 'lum-network/review', null, 0, 0)], + signers: [ + { + accountNumber: acc.accountNumber, + sequence: acc.sequence, + publicKey: w1.getPublicKey(), + }, + ], + }; + + const txCreate = await clt.signAndBroadcastTx(w1, doc); + expect(txCreate.deliverTx.code).toBe(0); + const beamAfterCreate = await clt.queryClient.beam.get(beamId); + expect(beamAfterCreate.status).toBe(BeamState.OPEN); + + // Update the beam + acc = await clt.getAccount(w1.getAddress()); + doc = { + accountNumber: acc.accountNumber, + chainId, + fee: fee, + memo: 'Beam review transaction', + messages: [LumMessages.BuildMsgUpdateBeam(beamId, w1.getAddress(), null, BeamState.CANCELED)], + signers: [ + { + accountNumber: acc.accountNumber, + sequence: acc.sequence, + publicKey: w1.getPublicKey(), + }, + ], + }; + + const txUpdate = await clt.signAndBroadcastTx(w1, doc); + expect(txUpdate.deliverTx.code).toBe(0); + const beamAfterUpdate = await clt.queryClient.beam.get(beamId); + expect(beamAfterUpdate.status).toBe(BeamState.CANCELED); + }); + it('should open a beam review transaction', async () => { const beamId = randomString();