Skip to content

Commit

Permalink
[CORE-859] add new market widget: gov proposal submission and query (
Browse files Browse the repository at this point in the history
…#111)

* submits gov proposal

* fix wrapping for update clob pair + add example commands

* define composer + update existing test

* symbol -> ticker

* bump package version

* add comments

* fix lint

* format

* format + comment

* revert package bump

* format..pls

* add methods to submit gov proposal and query all proposals

* add wallet + fix client + wait longer

* query comment

* export title and summary helpers

* nit new name
  • Loading branch information
ttl33 authored Jan 24, 2024
1 parent 32da264 commit e880b13
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 108 deletions.
118 changes: 23 additions & 95 deletions v4-client-js/examples/gov_add_new_market.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { EncodeObject, Registry } from '@cosmjs/proto-signing';
import Long from 'long';

import { BECH32_PREFIX } from '../src';
import { GovAddNewMarketParams, LocalWallet, ProposalStatus } from '../src';
import { CompositeClient } from '../src/clients/composite-client';
import { Network } from '../src/clients/constants';
import { generateRegistry } from '../src/clients/lib/registry';
import { Composer } from '../src/clients/modules/composer';
import LocalWallet from '../src/clients/modules/local-wallet';
import { BECH32_PREFIX, Network } from '../src/clients/constants';
import { getGovAddNewMarketSummary, getGovAddNewMarketTitle, sleep } from '../src/lib/utils';
import { DYDX_LOCAL_MNEMONIC } from './constants';

const INITIAL_DEPOSIT_AMOUNT = 10_000_000_000_000; // 10,000 whole native tokens.
const MOCK_DATA = {
const MOCK_DATA: GovAddNewMarketParams = {
// common
id: 34,
ticker: 'BONK-USD',
Expand All @@ -32,7 +29,6 @@ const MOCK_DATA = {

// x/perpetuals
liquidityTier: 2,
defaultFundingPpm: 0,
atomicResolution: -1,

// x/clob
Expand Down Expand Up @@ -60,104 +56,36 @@ async function test(): Promise<void> {
console.log('**Start**');

const wallet = await LocalWallet.fromMnemonic(DYDX_LOCAL_MNEMONIC, BECH32_PREFIX);
console.log(wallet);

const network = Network.local();
const client = await CompositeClient.connect(network);
console.log('**Client**');
console.log(client);

const composer: Composer = client.validatorClient.post.composer;
const registry: Registry = generateRegistry();
const msgs: EncodeObject[] = [];

// x/prices.MsgCreateOracleMarket
const createOracleMarket = composer.composeMsgCreateOracleMarket(
MOCK_DATA.id,
MOCK_DATA.ticker,
MOCK_DATA.priceExponent,
MOCK_DATA.minExchanges,
MOCK_DATA.minPriceChange,
MOCK_DATA.exchangeConfigJson,
);

// x/perpetuals.MsgCreatePerpetual
const createPerpetual = composer.composeMsgCreatePerpetual(
MOCK_DATA.id,
MOCK_DATA.id,
MOCK_DATA.ticker,
MOCK_DATA.atomicResolution,
MOCK_DATA.defaultFundingPpm,
MOCK_DATA.liquidityTier,
);

// x/clob.MsgCreateClobPair
const createClobPair = composer.composeMsgCreateClobPair(
MOCK_DATA.id,
MOCK_DATA.id,
MOCK_DATA.quantumConversionExponent,
MOCK_DATA.stepBaseQuantums,
MOCK_DATA.subticksPerTick,
);

// x/clob.MsgUpdateClobPair
const updateClobPair = composer.composeMsgUpdateClobPair(
MOCK_DATA.id,
MOCK_DATA.id,
MOCK_DATA.quantumConversionExponent,
MOCK_DATA.stepBaseQuantums,
MOCK_DATA.subticksPerTick,
);

// x/delaymsg.MsgDelayMessage
const delayMessage = composer.composeMsgDelayMessage(
// IMPORTANT: must wrap messages in Any type to fit into delaymsg.
composer.wrapMessageAsAny(registry, updateClobPair),
MOCK_DATA.delayBlocks,
);
msgs.push(createOracleMarket);
msgs.push(createPerpetual);
msgs.push(createClobPair);
msgs.push(delayMessage);

// x/gov.v1.MsgSubmitProposal
const submitProposal = composer.composeMsgSubmitProposal(
getTitle(MOCK_DATA.ticker),
INITIAL_DEPOSIT_AMOUNT,
client.validatorClient.config.denoms,
getSummary(MOCK_DATA.ticker, MOCK_DATA.delayBlocks),
// IMPORTANT: must wrap messages in Any type for gov's submit proposal.
composer.wrapMessageArrAsAny(registry, msgs),
wallet.address!, // proposer
);

console.log('**Submit Proposal**');
console.log(submitProposal);

const tx = await client.send(
const tx = await client.submitGovAddNewMarketProposal(
wallet,
() => Promise.resolve([submitProposal]),
false,
client.validatorClient.post.defaultDydxGasPrice,
undefined,
() => client.validatorClient.post.account(
wallet.address!,
undefined,
),
MOCK_DATA,
getGovAddNewMarketTitle(MOCK_DATA.ticker),
getGovAddNewMarketSummary(MOCK_DATA.ticker, MOCK_DATA.delayBlocks),
INITIAL_DEPOSIT_AMOUNT,
);
console.log('**Tx**');
console.log(tx);
}

function getTitle(
ticker: string,
): string {
return `Add ${ticker} perpetual market`;
}
await sleep(5000);

function getSummary(
ticker: string,
delayBlocks: number,
): string {
return `Add the x/prices, x/perpetuals and x/clob parameters needed for a ${ticker} perpetual market. Create the market in INITIALIZING status and transition it to ACTIVE status after ${delayBlocks} blocks.`;
const depositProposals = await client.validatorClient.get.getAllGovProposals(
ProposalStatus.PROPOSAL_STATUS_DEPOSIT_PERIOD,
);
console.log('**Deposit Proposals**');
console.log(depositProposals);

const votingProposals = await client.validatorClient.get.getAllGovProposals(
ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD,
);
console.log('**Voting Proposals**');
console.log(votingProposals);
}

test().catch((error) => {
Expand Down
4 changes: 2 additions & 2 deletions v4-client-js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion v4-client-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dydxprotocol/v4-client-js",
"version": "1.0.15",
"version": "1.0.16",
"description": "General client library for the new dYdX system (v4 decentralized)",
"main": "build/src/index.js",
"scripts": {
Expand Down
99 changes: 97 additions & 2 deletions v4-client-js/src/clients/composite-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Long from 'long';
import protobuf from 'protobufjs';

import { isStatefulOrder, verifyOrderFlags } from '../lib/validation';
import { OrderFlags } from '../types';
import { GovAddNewMarketParams, OrderFlags } from '../types';
import {
Network,
OrderExecution,
Expand All @@ -31,6 +31,7 @@ import {
} from './helpers/chain-helpers';
import { IndexerClient } from './indexer-client';
import { UserError } from './lib/errors';
import { generateRegistry } from './lib/registry';
import LocalWallet from './modules/local-wallet';
import { SubaccountInfo } from './subaccount';
import { ValidatorClient } from './validator-client';
Expand Down Expand Up @@ -498,7 +499,7 @@ export class CompositeClient {
);
}

private async retrieveMarketInfo(marketId: string, marketInfo?:MarketInfo): Promise<MarketInfo> {
private async retrieveMarketInfo(marketId: string, marketInfo?: MarketInfo): Promise<MarketInfo> {
if (marketInfo) {
return Promise.resolve(marketInfo);
} else {
Expand Down Expand Up @@ -1000,4 +1001,98 @@ export class CompositeClient {

return Buffer.from(signature).toString('base64');
}

/**
* @description Submit a governance proposal to add a new market.
*
* @param params Parameters neeeded to create a new market.
* @param title Title of the gov proposal.
* @param summary Summary of the gov proposal.
* @param initialDepositAmount Initial deposit amount of the gov proposal.
* @param proposer proposer of the gov proposal.
*
* @returns the transaction hash.
*/
async submitGovAddNewMarketProposal(
wallet: LocalWallet,
params: GovAddNewMarketParams,
title: string,
summary: string,
initialDepositAmount: number,
): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
const msg: Promise<EncodeObject[]> = new Promise((resolve) => {
const composer = this.validatorClient.post.composer;
const registry = generateRegistry();
const msgs: EncodeObject[] = [];

// x/prices.MsgCreateOracleMarket
const createOracleMarket = composer.composeMsgCreateOracleMarket(
params.id,
params.ticker,
params.priceExponent,
params.minExchanges,
params.minPriceChange,
params.exchangeConfigJson,
);

// x/perpetuals.MsgCreatePerpetual
const createPerpetual = composer.composeMsgCreatePerpetual(
params.id,
params.id,
params.ticker,
params.atomicResolution,
params.liquidityTier,
);

// x/clob.MsgCreateClobPair
const createClobPair = composer.composeMsgCreateClobPair(
params.id,
params.id,
params.quantumConversionExponent,
params.stepBaseQuantums,
params.subticksPerTick,
);

// x/clob.MsgUpdateClobPair
const updateClobPair = composer.composeMsgUpdateClobPair(
params.id,
params.id,
params.quantumConversionExponent,
params.stepBaseQuantums,
params.subticksPerTick,
);

// x/delaymsg.MsgDelayMessage
const delayMessage = composer.composeMsgDelayMessage(
// IMPORTANT: must wrap messages in Any type to fit into delaymsg.
composer.wrapMessageAsAny(registry, updateClobPair),
params.delayBlocks,
);

// The order matters.
msgs.push(createOracleMarket);
msgs.push(createPerpetual);
msgs.push(createClobPair);
msgs.push(delayMessage);

// x/gov.v1.MsgSubmitProposal
const submitProposal = composer.composeMsgSubmitProposal(
title,
initialDepositAmount,
this.validatorClient.config.denoms, // use the client denom.
summary,
// IMPORTANT: must wrap messages in Any type for gov's submit proposal.
composer.wrapMessageArrAsAny(registry, msgs),
wallet.address!, // proposer
);

resolve([submitProposal]);
});

return this.send(
wallet,
() => msg,
false,
);
}
}
3 changes: 1 addition & 2 deletions v4-client-js/src/clients/modules/composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,6 @@ export class Composer {
marketId: number,
ticker: string,
atomicResolution: number,
defaultFundingPpm: number,
liquidityTier: number,
): EncodeObject {
const msg: MsgCreatePerpetual = {
Expand All @@ -352,7 +351,7 @@ export class Composer {
marketId,
ticker,
atomicResolution,
defaultFundingPpm,
defaultFundingPpm: 0, // default funding should be 0 to start.
liquidityTier,
},
};
Expand Down
39 changes: 36 additions & 3 deletions v4-client-js/src/clients/modules/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import {
BridgeModule,
ClobModule,
FeeTierModule,
GovV1Module,
PerpetualsModule,
PricesModule,
ProposalStatus,
RewardsModule,
StakingModule,
StatsModule,
Expand Down Expand Up @@ -365,7 +367,7 @@ export class Get {
*/
async getEquityTierLimitConfiguration(): Promise<
ClobModule.QueryEquityTierLimitConfigurationResponse
> {
> {
const requestData: Uint8Array = Uint8Array.from(
ClobModule.QueryEquityTierLimitConfigurationRequest.encode({})
.finish(),
Expand Down Expand Up @@ -470,9 +472,40 @@ export class Get {
return StakingModule.QueryValidatorsResponse.decode(data);
}

/**
* @description Get all gov proposals.
*
* @param proposalStatus Status of the proposal to filter by.
* @param voter Voter to filter by.
* @param depositor Depositor to filter by.
*
* @returns All gov proposals that match the filters above.
*/
async getAllGovProposals(
proposalStatus: ProposalStatus = ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD,
voter: string = '',
depositor: string = '',
): Promise<GovV1Module.QueryProposalsResponse> {
const requestData = Uint8Array.from(
GovV1Module.QueryProposalsRequest
.encode({
proposalStatus,
voter,
depositor,
pagination: PAGE_REQUEST,
})
.finish(),
);
const data: Uint8Array = await this.sendQuery(
'/cosmos.gov.v1.Query/Proposals',
requestData,
);
return GovV1Module.QueryProposalsResponse.decode(data);
}

private async sendQuery(requestUrl: string, requestData: Uint8Array): Promise<Uint8Array> {
const resp: QueryAbciResponse = await
this.stargateQueryClient.queryAbci(requestUrl, requestData);
// eslint-disable-next-line max-len
const resp: QueryAbciResponse = await this.stargateQueryClient.queryAbci(requestUrl, requestData);
return resp.value;
}
}
Loading

0 comments on commit e880b13

Please sign in to comment.