Add modules
When a new module is added to Terra Core, you must also add it to several places in feather.js. To add a module, complete the following steps.
Create a new folder
In the src/core
folder, create a new folder and name it after the new module. For example,src/core/greeting
.
Add messages
- Register new messages in a subdirectory in the folder that you created for your new module, as shown in the following example:
src/core/greeting/msgs
For this example, let's assume that you are creating a two new messages, MsgHello
and MsgGoodbye
. The following example shows the code for MsgHello
, and you can extrapolate from it the way to implement MsgGoodbye
.
src/core/greeting/msgs/MsgHello.ts
_37import { JSONSerializable } from '../../../util/json';_37import { AccAddress } from '../../strings';_37_37/**_37 * Just a simple greeting on the blockchain._37 */_37export class MsgHello extends JSONSerializable<MsgHello.Data> {_37 constructor(public recipient: AccAddress) {_37 super();_37 }_37_37 public static fromData(data: MsgHello.Data): MsgHello {_37 const {_37 value: { recipient },_37 } = data;_37 return new MsgHello(recipient);_37 }_37_37 public toData(): MsgHello.Data {_37 const { recipient } = this;_37 return {_37 type: 'greeting/MsgHello',_37 value: {_37 recipient,_37 },_37 };_37 }_37}_37_37export namespace MsgHello {_37 export interface Data {_37 type: 'greeting/MsgHello';_37 value: {_37 recipient: AccAddress;_37 };_37 }_37}
- Create the following file, which will index your new messages.
src/core/greeting/msgs/index.ts
_11import { MsgHello } from './MsgHello';_11import { MsgGoodbye } from './MsgGoodbye';_11_11export * from './MsgHello';_11export * from './MsgGoodbye';_11_11export type GreetingMsg = MsgHello | MsgGoodbye;_11_11export namespace GreetingMsg {_11 export type Data = MsgHello.Data | MsgGoodbye.Data;_11}
- Register the messages in
src/core/Msg.ts
so that they can be parsed correctly.
src/core/Msg.ts
_46// import greeting module messages_46..._46import {_46 MsgHello,_46 MsgGoodbye,_46 GreetingMsg_46} from './greeting/msgs';_46..._46_46// register GreetingMsg_46export type Msg =_46 | BankMsg_46 | DistributionMsg_46 | GovMsg_46 | GreetingMsg // ADD HERE_46 | MsgAuthMsg_46 | SlashingMsg_46 | StakingMsg_46 | WasmMsg;_46_46..._46_46// register GreetingMsg.Data_46export namespace Msg {_46 export type Data =_46 | BankMsg.Data_46 | DistributionMsg.Data_46 | GovMsg.Data_46 | Greeting.Data // ADD HERE_46 | MsgAuthMsg.Data_46 | SlashingMsg.Data_46 | StakingMsg.Data_46 | WasmMsg.Data;_46..._46_46 // register deserializer in Msg.fromData(...)_46 export function fromData(data: Msg.Data): Msg {_46 ..._46 // greeting_46 case 'greeting/MsgHello':_46 return MsgHello.fromData(data);_46 case 'greeting/MsgGoodbye':_46 return MsgGoodbye.fromData(data);_46 ..._46 }_46}
- Register the messages to be exported in
src/core/index.ts
:
_3..._3// greeting_3export 'greeting/msgs';
- Add parameter changes.
feather.js provides an easy way to generate ParameterChangeProposal
s, which is a proposal for changing the blockchain parameters associated with a module. If your module has parameters that can be changed via proposal, you should create the following files:
src/core/greeting/params.ts
_30import { ParamChange } from '..';_30import { Convert } from '../../util/convert';_30_30type MaxHellos = ParamChange.Type<'greeting', 'maxhellos', number>;_30_30type MaxGoodbyes = ParamChange.Type<'greeting', 'maxgoodbyes', number>;_30_30export type GreetingParamChange = MaxHellos | MaxGoodbyes;_30_30export namespace GreetingParamChange {_30 export type Data =_30 | ParamChange.Data.Type<MaxHellos>_30 | ParamChange.Data.Type<MaxGoodbyes>;_30}_30_30export interface GreetingParamChanges {_30 greeting?: {_30 maxhellos?: number;_30 maxgoodbyes?: number;_30 };_30}_30_30export namespace GreetingParamChanges {_30 export const ConversionTable = {_30 greeting: {_30 maxhellos: [Convert.toNumber, Convert.toFixed],_30 maxgoodbyes: [Convert.toNumber, Convert.toFixed],_30 },_30 };_30}
- Register parameter change types
src/core/params/ParamChange.ts
_32..._32import { GreetingParamChange, GreetingParamChanges } from '../greeting/params';_32..._32_32export type ParamChanges = DistributionParamChanges &_32 GovParamChanges &_32 GreetingParamChanges & // ADD HERE_32 SlashingParamChanges &_32 StakingParamChanges &_32 WasmParamChanges;_32_32export namespace ParamChanges {_32 export const ConversionTable = {_32 ...DistributionParamChanges.ConversionTable,_32 ...GovParamChanges.ConversionTable,_32 ...GreetingParamChanges.ConverstionTable, // ADD HERE_32 ...SlashingParamChanges.ConversionTable,_32 ...StakingParamChanges.ConversionTable,_32 ...WasmParamChanges.ConversionTable,_32 };_32_32..._32_32export type ParamChange =_32 | DistributionParamChange_32 | GovParamChange_32 | GreetingParamChange // ADD HERE_32 | SlashingParamChange_32 | StakingParamChange_32 | WasmParamChange;_32_32...
Add API functionality to the LCDClient
If there are API endpoints that exist for the new module, you will need to add this functionality to LCDClient
so that they are accessible.
Assume that the greeting
module has the following endpoints:
GET /greeting/hello/{accAddress}
GET /greeting/parameters
- Create
src/client/lcd/api/GreetingAPI.ts
with the following:
_32import { BaseAPI } from './BaseAPI';_32import { AccAddress } from '../../../core/strings';_32_32export interface GreetingParams {_32 max_hellos: number;_32 max_goodbyes: number;_32}_32_32export namespace GreetingParams {_32 export interface Data {_32 max_hellos: string;_32 max_goodbyes: string;_32 }_32}_32_32export class GreetingAPI extends BaseAPI {_32 public async hello(accAddress: AccAddress): Promise<AccAddress[]> {_32 return this.c_32 .get<AccAddress[]>(`/greeting/hello/${accAddress}`)_32 .then((d) => d.result);_32 }_32_32 public async parameters(): Promise<GreetingParams> {_32 return this.c_32 .get<GreetingParams.Data>(`/greeting/parameters`)_32 .then((d) => d.result)_32 .then((d) => ({_32 max_hellos: Number.parseInt(d.max_hellos),_32 max_goodbyes: Number.parseInt(d.max_goodbyes),_32 }));_32 }_32}
- Register the API functionality inside
src/client/lcd/api/index.ts
:
_12export * from './AuthAPI';_12export * from './BankAPI';_12export * from './DistributionAPI';_12export * from './GovAPI';_12export * from './GreetingAPI'; // ADD HERE_12export * from './MsgAuthAPI';_12export * from './SlashingAPI';_12export * from './StakingAPI';_12export * from './SupplyAPI';_12export * from './TendermintAPI';_12export * from './TxAPI';_12export * from './WasmAPI';
- Add the functionality to
src/client/lcd/LCDClient.ts
:
_63..._63import {_63 AuthAPI,_63 BankAPI,_63 DistributionAPI,_63 GovAPI,_63 GreetingAPI, // ADD HERE_63 MsgAuthAPI,_63 SlashingAPI,_63 StakingAPI,_63 SupplyAPI,_63 TendermintAPI,_63 TxAPI,_63 WasmAPI,_63} from './api';_63..._63_63_63export class LCDClient {_63 public config: LCDClientConfig;_63 public apiRequester: APIRequester;_63_63 // API access_63 public auth: AuthAPI;_63 public bank: BankAPI;_63 public distribution: DistributionAPI;_63 public gov: GovAPI;_63 public greeting: GreetingAPI; // ADD HERE_63 public msgauth: MsgAuthAPI;_63 public slashing: SlashingAPI;_63 public staking: StakingAPI;_63 public supply: SupplyAPI;_63 public tendermint: TendermintAPI;_63 public wasm: WasmAPI;_63 public tx: TxAPI;_63_63 /**_63 * Creates a new LCD client with the specified configuration._63 *_63 * @param config LCD configuration_63 */_63 constructor(config: LCDClientConfig) {_63 this.config = {_63 ...DEFAULT_LCD_OPTIONS,_63 ...config,_63 };_63_63 this.apiRequester = new APIRequester(this.config.URL);_63_63 // instantiate APIs_63 this.auth = new AuthAPI(this.apiRequester);_63 this.bank = new BankAPI(this.apiRequester);_63 this.distribution = new DistributionAPI(this.apiRequester);_63 this.gov = new GovAPI(this.apiRequester);_63 this.greeting = new GreetingAPI(this.apiRequester); // ADD HERE_63 this.msgauth = new MsgAuthAPI(this.apiRequester);_63 this.slashing = new SlashingAPI(this.apiRequester);_63 this.staking = new StakingAPI(this.apiRequester);_63 this.supply = new SupplyAPI(this.apiRequester);_63 this.tendermint = new TendermintAPI(this.apiRequester);_63 this.wasm = new WasmAPI(this.apiRequester);_63 this.tx = new TxAPI(this);_63 }