diff --git a/nibiru b/nibiru index 82affcbb..9219a944 160000 --- a/nibiru +++ b/nibiru @@ -1 +1 @@ -Subproject commit 82affcbbce49314bb80e7af571d5c9bc1f359d40 +Subproject commit 9219a94448940c1835106cb3d82dc61f50948234 diff --git a/src/gql/heart-monitor/heart-monitor.test.ts b/src/gql/heart-monitor/heart-monitor.test.ts index 6b6784df..5e069e2b 100644 --- a/src/gql/heart-monitor/heart-monitor.test.ts +++ b/src/gql/heart-monitor/heart-monitor.test.ts @@ -55,6 +55,8 @@ import { defaultEvm, defaultBybit, defaultProxy, + GQLMarketing, + QueryMarketingArgs, } from ".." const nibiruUrl = "testnet-2" @@ -135,6 +137,21 @@ test("distributionCommissions", async () => { await testDistributionCommissions({}, defaultDistributionCommission) }) +const testEvm = async (fields: GQLEvm) => { + const resp = await heartMonitor.evm(fields) + expect(resp).toHaveProperty("evm") + + if (resp.evm) { + const { evm } = resp + + checkFields([evm], ["funTokens"]) + } +} + +test("evm", async () => { + await testEvm(defaultEvm) +}) + const testFeatureFlags = async (fields: GQLFeatureFlags) => { const resp = await heartMonitor.featureFlags(fields) expect(resp).toHaveProperty("featureFlags") @@ -288,6 +305,27 @@ test("inflation", async () => { ) }) +const testMarketing = async ( + args: QueryMarketingArgs, + fields: GQLMarketing +) => { + const resp = await heartMonitor.marketing(args, fields) + expect(resp).toHaveProperty("marketing") + + if (resp.marketing) { + const { marketing } = resp + + checkFields([marketing], ["isTaskCompleted"]) + } +} + +test("marketing", async () => { + await testMarketing( + { isTaskCompleted: { taskId: "task-123", userAddress: "nibi1xyz" } }, + { isTaskCompleted: true } + ) +}) + const testOracle = async (args: QueryOracleArgs, fields: OracleFields) => { const resp = await heartMonitor.oracle(args, fields) expect(resp).toHaveProperty("oracle") @@ -380,21 +418,6 @@ test("proxies", async () => { await testProxies({ bybit: defaultBybit }) }) -const testEvm = async (fields: GQLEvm) => { - const resp = await heartMonitor.evm(fields) - expect(resp).toHaveProperty("evm") - - if (resp.evm) { - const { evm } = resp - - checkFields([evm], ["funTokens"]) - } -} - -test("evm", async () => { - await testEvm(defaultEvm) -}) - test("queryBatchHandler", async () => { // TODO: Make a partial type that includes all of these const resp = await heartMonitor.GQLQueryGqlBatchHandler<{ diff --git a/src/gql/heart-monitor/heart-monitor.ts b/src/gql/heart-monitor/heart-monitor.ts index 1c959271..221af9fc 100644 --- a/src/gql/heart-monitor/heart-monitor.ts +++ b/src/gql/heart-monitor/heart-monitor.ts @@ -45,6 +45,10 @@ import { GQLProxies, GqlOutProxies, proxies, + QueryMarketingArgs, + MarketingFields, + GqlOutMarketing, + marketing, GQLStakingFields, GqlOutStaking, QueryStakingArgs, @@ -65,6 +69,10 @@ export interface IHeartMonitor { subscriptionClient?: Client closeWebSocket: () => Promise + readonly GQLQueryGqlBatchHandler: ( + queryQueryStrings: string[] + ) => Promise + readonly communityPool: ( args: GQLQueryGqlCommunityPoolArgs, fields: DeepPartial @@ -75,6 +83,8 @@ export interface IHeartMonitor { fields: DeepPartial ) => Promise + readonly evm: (fields: DeepPartial) => Promise + readonly featureFlags: ( fields: DeepPartial ) => Promise @@ -94,6 +104,11 @@ export interface IHeartMonitor { fields: DeepPartial ) => Promise + readonly marketing: ( + args: QueryMarketingArgs, + fields: DeepPartial + ) => Promise + readonly oracle: ( args: QueryOracleArgs, fields: DeepPartial @@ -111,12 +126,6 @@ export interface IHeartMonitor { domainName?: string ) => Promise - readonly evm: (fields: DeepPartial) => Promise - - readonly GQLQueryGqlBatchHandler: ( - queryQueryStrings: string[] - ) => Promise - readonly staking: ( args: QueryStakingArgs, fields: DeepPartial @@ -165,6 +174,9 @@ export class HeartMonitor implements IHeartMonitor { } } + GQLQueryGqlBatchHandler = async (queryQueryStrings: string[]) => + queryBatchHandler(queryQueryStrings, this.gqlEndpt) + closeWebSocket = async () => this.subscriptionClient?.dispose() communityPool = async ( @@ -177,6 +189,8 @@ export class HeartMonitor implements IHeartMonitor { fields: DeepPartial ) => distributionCommissions(args, this.gqlEndpt, fields) + evm = async (fields: DeepPartial) => evm(this.gqlEndpt, fields) + featureFlags = async (fields: DeepPartial) => featureFlags(this.gqlEndpt, fields) @@ -193,6 +207,11 @@ export class HeartMonitor implements IHeartMonitor { fields: DeepPartial ) => inflation(args, this.gqlEndpt, fields) + marketing = async ( + args: QueryMarketingArgs, + fields: DeepPartial + ) => marketing(args, this.gqlEndpt, fields) + oracle = async (args: QueryOracleArgs, fields: DeepPartial) => oracle(args, this.gqlEndpt, fields) @@ -204,11 +223,6 @@ export class HeartMonitor implements IHeartMonitor { proxies = async (fields: DeepPartial, domainName?: string) => proxies(this.gqlEndpt, fields, domainName) - evm = async (fields: DeepPartial) => evm(this.gqlEndpt, fields) - - GQLQueryGqlBatchHandler = async (queryQueryStrings: string[]) => - queryBatchHandler(queryQueryStrings, this.gqlEndpt) - staking = async ( args: QueryStakingArgs, fields: DeepPartial diff --git a/src/gql/query/index.ts b/src/gql/query/index.ts index 87a5ddb3..2b8fc8f6 100644 --- a/src/gql/query/index.ts +++ b/src/gql/query/index.ts @@ -9,6 +9,7 @@ export * from "./featureFlags" export * from "./governance" export * from "./ibc" export * from "./inflation" +export * from "./marketing" export * from "./oracle" export * from "./proxies" export * from "./staking" diff --git a/src/gql/query/marketing.ts b/src/gql/query/marketing.ts new file mode 100644 index 00000000..1ec9a19f --- /dev/null +++ b/src/gql/query/marketing.ts @@ -0,0 +1,53 @@ +import { + doGqlQuery, + GQLQuery, + DeepPartial, + GQLMarketing, + GQLMarketingGqlIsTaskCompletedArgs, + arg, +} from ".." + +export type QueryMarketingArgs = { + isTaskCompleted?: GQLMarketingGqlIsTaskCompletedArgs +} + +export interface GqlOutMarketing { + marketing?: GQLQuery["marketing"] +} + +export type MarketingFields = DeepPartial + +export const marketingQueryString = ( + args: QueryMarketingArgs, + fields: MarketingFields +) => { + const marketingQuery: string[] = [] + + if (fields.isTaskCompleted) { + const qArgs = + args.isTaskCompleted ?? ({} as GQLMarketingGqlIsTaskCompletedArgs) + const argList = [ + arg("taskId", qArgs.taskId), + arg("userAddress", qArgs.userAddress), + ] + marketingQuery.push(`isTaskCompleted(${argList.join(", ")})`) + } + + return ` + marketing { + ${marketingQuery.join("\n")} + } + ` +} + +export const marketing = async ( + args: QueryMarketingArgs, + endpt: string, + fields: MarketingFields +): Promise => + doGqlQuery( + `{ + ${marketingQueryString(args, fields)} + }`, + endpt + ) diff --git a/src/gql/utils/generated.ts b/src/gql/utils/generated.ts index c6b1845f..72d37191 100644 --- a/src/gql/utils/generated.ts +++ b/src/gql/utils/generated.ts @@ -54,9 +54,9 @@ export enum GQLCommunityPoolOrder { } export type GQLContractEventsFilter = { - readonly block?: InputMaybe; - readonly contractAddress?: InputMaybe; - readonly type?: InputMaybe; + readonly block: GQLIntFilter; + readonly contractAddress?: InputMaybe; + readonly type?: InputMaybe; }; export enum GQLContractEventsOrder { @@ -121,6 +121,7 @@ export type GQLEvent = { readonly block: GQLBlock; readonly contractAddress?: Maybe; readonly eventSeqNo: Scalars['Int']['output']; + readonly txHash?: Maybe; readonly txSeqNo: Scalars['Int']['output']; readonly type: Scalars['String']['output']; }; @@ -423,6 +424,17 @@ export type GQLInternalGqlEmployeeArgs = { where: GQLEmployeeFilter; }; +export type GQLMarketing = { + readonly __typename?: 'Marketing'; + readonly isTaskCompleted: Scalars['Boolean']['output']; +}; + + +export type GQLMarketingGqlIsTaskCompletedArgs = { + taskId: Scalars['String']['input']; + userAddress: Scalars['String']['input']; +}; + export type GQLMessage = { readonly __typename?: 'Message'; readonly action?: Maybe; @@ -533,6 +545,7 @@ export type GQLQuery = { readonly ibc: GQLIbc; readonly inflation: GQLInflation; readonly internal: GQLInternal; + readonly marketing: GQLMarketing; readonly messages: ReadonlyArray; readonly oracle: GQLOracle; readonly proxies: GQLProxies; @@ -769,6 +782,10 @@ export enum GQLStatsVolumeOrder { GQLPeriodStartTs = 'period_start_ts' } +export type GQLStringEqualsFilter = { + readonly eq?: InputMaybe; +}; + export type GQLStringFilter = { readonly eq?: InputMaybe; readonly like?: InputMaybe; @@ -874,7 +891,6 @@ export type GQLUserContract = { readonly __typename?: 'UserContract'; readonly contractAddress: Scalars['String']['output']; readonly contractType: Scalars['String']['output']; - readonly events?: Maybe>; readonly user: GQLUser; }; @@ -973,7 +989,7 @@ export type GQLWasmGqlContractEventsArgs = { offset?: InputMaybe; order?: InputMaybe; orderDesc?: InputMaybe; - where?: InputMaybe; + where: GQLContractEventsFilter; }; diff --git a/src/gql/utils/schema.graphql b/src/gql/utils/schema.graphql index ca7b5cb6..e26aafce 100644 --- a/src/gql/utils/schema.graphql +++ b/src/gql/utils/schema.graphql @@ -1,3 +1,14 @@ +""" +Directs the executor to defer this fragment when the `if` argument is true or undefined. +""" +directive @defer( + """Deferred when true or undefined.""" + if: Boolean = true + + """Unique name""" + label: String +) on FRAGMENT_SPREAD | INLINE_FRAGMENT + directive @goModel(model: String, models: [String!]) on ENUM | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION type Balance { @@ -36,9 +47,9 @@ enum CommunityPoolOrder { } input ContractEventsFilter { - block: IntFilter - contractAddress: StringFilter - type: StringFilter + block: IntFilter! + contractAddress: StringEqualsFilter + type: StringEqualsFilter } enum ContractEventsOrder { @@ -99,6 +110,7 @@ type Event { block: Block! contractAddress: String eventSeqNo: Int! + txHash: String txSeqNo: Int! type: String! } @@ -328,6 +340,10 @@ type Internal { employee(where: EmployeeFilter!): Employee } +type Marketing { + isTaskCompleted(taskId: String!, userAddress: String!): Boolean! +} + type Message { action: String block: Block! @@ -407,6 +423,7 @@ type Query { ibc: IBC! inflation: Inflation! internal: Internal! + marketing: Marketing! messages(limit: Int, offset: Int, order_by: MessagesOrder, order_desc: Boolean, where: MessagesFilter): [Message!]! oracle: Oracle! proxies: Proxies! @@ -511,6 +528,10 @@ enum StatsVolumeOrder { period_start_ts } +input StringEqualsFilter { + eq: String +} + input StringFilter { eq: String like: String @@ -605,7 +626,6 @@ type User { type UserContract { contractAddress: String! contractType: String! - events: [Event!] user: User! } @@ -690,6 +710,6 @@ enum ValidatorStatus { } type Wasm { - contractEvents(limit: Int, offset: Int, order: ContractEventsOrder, orderDesc: Boolean, where: ContractEventsFilter): [Event!]! + contractEvents(limit: Int, offset: Int, order: ContractEventsOrder, orderDesc: Boolean, where: ContractEventsFilter!): [Event!]! userContracts(limit: Int, offset: Int, order: UserContractsOrder, orderDesc: Boolean, where: UserContractsFilter): [UserContract!]! } \ No newline at end of file diff --git a/src/protojs/eth/evm/module/module.ts b/src/protojs/eth/evm/module/module.ts new file mode 100644 index 00000000..6e13be70 --- /dev/null +++ b/src/protojs/eth/evm/module/module.ts @@ -0,0 +1,172 @@ +/* eslint-disable */ +import Long from "long"; +import _m0 from "protobufjs/minimal"; + +/** Module is the config object for the devgas module. */ +export interface Module { + /** authority defines the custom module authority. If not set, defaults to the governance module. */ + authority: string; +} + +/** ModuleAccountPermission represents permissions for a module account. */ +export interface ModuleAccountPermission { + /** account is the name of the module. */ + account: string; + /** + * permissions are the permissions this module has. Currently recognized + * values are minter, burner and staking. + */ + permissions: string[]; +} + +function createBaseModule(): Module { + return { authority: "" }; +} + +export const Module = { + encode(message: Module, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.authority !== "") { + writer.uint32(10).string(message.authority); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Module { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseModule(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.authority = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Module { + return { authority: isSet(object.authority) ? String(object.authority) : "" }; + }, + + toJSON(message: Module): unknown { + const obj: any = {}; + message.authority !== undefined && (obj.authority = message.authority); + return obj; + }, + + create, I>>(base?: I): Module { + return Module.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): Module { + const message = createBaseModule(); + message.authority = object.authority ?? ""; + return message; + }, +}; + +function createBaseModuleAccountPermission(): ModuleAccountPermission { + return { account: "", permissions: [] }; +} + +export const ModuleAccountPermission = { + encode(message: ModuleAccountPermission, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.account !== "") { + writer.uint32(10).string(message.account); + } + for (const v of message.permissions) { + writer.uint32(18).string(v!); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ModuleAccountPermission { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseModuleAccountPermission(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.account = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.permissions.push(reader.string()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ModuleAccountPermission { + return { + account: isSet(object.account) ? String(object.account) : "", + permissions: Array.isArray(object?.permissions) ? object.permissions.map((e: any) => String(e)) : [], + }; + }, + + toJSON(message: ModuleAccountPermission): unknown { + const obj: any = {}; + message.account !== undefined && (obj.account = message.account); + if (message.permissions) { + obj.permissions = message.permissions.map((e) => e); + } else { + obj.permissions = []; + } + return obj; + }, + + create, I>>(base?: I): ModuleAccountPermission { + return ModuleAccountPermission.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): ModuleAccountPermission { + const message = createBaseModuleAccountPermission(); + message.account = object.account ?? ""; + message.permissions = object.permissions?.map((e) => e) || []; + return message; + }, +}; + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +type DeepPartial = T extends Builtin ? T + : T extends Long ? string | number | Long : T extends Array ? Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any; + _m0.configure(); +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} diff --git a/src/protojs/eth/evm/v1/events.ts b/src/protojs/eth/evm/v1/events.ts index 8c829558..439bd006 100644 --- a/src/protojs/eth/evm/v1/events.ts +++ b/src/protojs/eth/evm/v1/events.ts @@ -30,7 +30,10 @@ export interface EventTxLog { logs: Log[]; } -/** EventBlockBloom defines an Ethereum block bloom filter event */ +/** + * EventBlockBloom contains the bloom filter for an Ethereum block. + * The bloom filter encodes logs for efficient event filtering. + */ export interface EventBlockBloom { /** bloom is the bloom filter of the block */ bloom: string; @@ -44,7 +47,10 @@ export interface EventFunTokenCreated { isMadeFromCoin: boolean; } -/** ConvertCoinToEvm defines sending fun token to erc20 event. */ +/** + * EventConvertCoinToEvm is an event emitted when converting Bank Coins into + * ERC20 tokens with the "eth.evm.v1.MsgConvertCoinToEvm" transaction message. + */ export interface EventConvertCoinToEvm { sender: string; erc20ContractAddress: string; @@ -71,6 +77,18 @@ export interface EventContractExecuted { contractAddr: string; } +/** + * EventConvertEvmToCoin is an event emitted when converting ERC20 tokens to Bank + * Coins with the "eth.evm.v1.MsgConvertEvmToCoin" transaction message. + */ +export interface EventConvertEvmToCoin { + sender: string; + erc20ContractAddress: string; + toAddress: string; + bankCoin?: Coin; + senderEthAddr: string; +} + function createBaseEventEthereumTx(): EventEthereumTx { return { amount: "", ethHash: "", index: "", gasUsed: "", hash: "", recipient: "", vmError: "" }; } @@ -745,6 +763,118 @@ export const EventContractExecuted = { }, }; +function createBaseEventConvertEvmToCoin(): EventConvertEvmToCoin { + return { sender: "", erc20ContractAddress: "", toAddress: "", bankCoin: undefined, senderEthAddr: "" }; +} + +export const EventConvertEvmToCoin = { + encode(message: EventConvertEvmToCoin, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.sender !== "") { + writer.uint32(10).string(message.sender); + } + if (message.erc20ContractAddress !== "") { + writer.uint32(18).string(message.erc20ContractAddress); + } + if (message.toAddress !== "") { + writer.uint32(26).string(message.toAddress); + } + if (message.bankCoin !== undefined) { + Coin.encode(message.bankCoin, writer.uint32(34).fork()).ldelim(); + } + if (message.senderEthAddr !== "") { + writer.uint32(50).string(message.senderEthAddr); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): EventConvertEvmToCoin { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseEventConvertEvmToCoin(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.sender = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.erc20ContractAddress = reader.string(); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.toAddress = reader.string(); + continue; + case 4: + if (tag !== 34) { + break; + } + + message.bankCoin = Coin.decode(reader, reader.uint32()); + continue; + case 6: + if (tag !== 50) { + break; + } + + message.senderEthAddr = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): EventConvertEvmToCoin { + return { + sender: isSet(object.sender) ? String(object.sender) : "", + erc20ContractAddress: isSet(object.erc20ContractAddress) ? String(object.erc20ContractAddress) : "", + toAddress: isSet(object.toAddress) ? String(object.toAddress) : "", + bankCoin: isSet(object.bankCoin) ? Coin.fromJSON(object.bankCoin) : undefined, + senderEthAddr: isSet(object.senderEthAddr) ? String(object.senderEthAddr) : "", + }; + }, + + toJSON(message: EventConvertEvmToCoin): unknown { + const obj: any = {}; + message.sender !== undefined && (obj.sender = message.sender); + message.erc20ContractAddress !== undefined && (obj.erc20ContractAddress = message.erc20ContractAddress); + message.toAddress !== undefined && (obj.toAddress = message.toAddress); + message.bankCoin !== undefined && (obj.bankCoin = message.bankCoin ? Coin.toJSON(message.bankCoin) : undefined); + message.senderEthAddr !== undefined && (obj.senderEthAddr = message.senderEthAddr); + return obj; + }, + + create, I>>(base?: I): EventConvertEvmToCoin { + return EventConvertEvmToCoin.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): EventConvertEvmToCoin { + const message = createBaseEventConvertEvmToCoin(); + message.sender = object.sender ?? ""; + message.erc20ContractAddress = object.erc20ContractAddress ?? ""; + message.toAddress = object.toAddress ?? ""; + message.bankCoin = (object.bankCoin !== undefined && object.bankCoin !== null) + ? Coin.fromPartial(object.bankCoin) + : undefined; + message.senderEthAddr = object.senderEthAddr ?? ""; + return message; + }, +}; + type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; type DeepPartial = T extends Builtin ? T diff --git a/src/protojs/eth/evm/v1/evm.ts b/src/protojs/eth/evm/v1/evm.ts index 6e9c5d78..2b3246de 100644 --- a/src/protojs/eth/evm/v1/evm.ts +++ b/src/protojs/eth/evm/v1/evm.ts @@ -34,6 +34,8 @@ export interface Params { * "evm_denom". */ createFuntokenFee: string; + /** Hexadecimal address of the canonical WNIBI contract on Nibiru mainnet */ + canonicalWnibi: string; } /** State represents a single Storage key value pair item. */ @@ -207,7 +209,7 @@ export const FunToken = { }; function createBaseParams(): Params { - return { extraEips: [], evmChannels: [], createFuntokenFee: "" }; + return { extraEips: [], evmChannels: [], createFuntokenFee: "", canonicalWnibi: "" }; } export const Params = { @@ -223,6 +225,9 @@ export const Params = { if (message.createFuntokenFee !== "") { writer.uint32(74).string(message.createFuntokenFee); } + if (message.canonicalWnibi !== "") { + writer.uint32(82).string(message.canonicalWnibi); + } return writer; }, @@ -264,6 +269,13 @@ export const Params = { message.createFuntokenFee = reader.string(); continue; + case 10: + if (tag !== 82) { + break; + } + + message.canonicalWnibi = reader.string(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -278,6 +290,7 @@ export const Params = { extraEips: Array.isArray(object?.extraEips) ? object.extraEips.map((e: any) => Long.fromValue(e)) : [], evmChannels: Array.isArray(object?.evmChannels) ? object.evmChannels.map((e: any) => String(e)) : [], createFuntokenFee: isSet(object.createFuntokenFee) ? String(object.createFuntokenFee) : "", + canonicalWnibi: isSet(object.canonicalWnibi) ? String(object.canonicalWnibi) : "", }; }, @@ -294,6 +307,7 @@ export const Params = { obj.evmChannels = []; } message.createFuntokenFee !== undefined && (obj.createFuntokenFee = message.createFuntokenFee); + message.canonicalWnibi !== undefined && (obj.canonicalWnibi = message.canonicalWnibi); return obj; }, @@ -306,6 +320,7 @@ export const Params = { message.extraEips = object.extraEips?.map((e) => Long.fromValue(e)) || []; message.evmChannels = object.evmChannels?.map((e) => e) || []; message.createFuntokenFee = object.createFuntokenFee ?? ""; + message.canonicalWnibi = object.canonicalWnibi ?? ""; return message; }, }; diff --git a/src/protojs/eth/evm/v1/tx.ts b/src/protojs/eth/evm/v1/tx.ts index 7aabbea0..dae21118 100644 --- a/src/protojs/eth/evm/v1/tx.ts +++ b/src/protojs/eth/evm/v1/tx.ts @@ -215,6 +215,15 @@ export interface MsgCreateFunToken { fromBankDenom: string; /** Sender: Address for the signer of the transaction. */ sender: string; + /** + * Optional flag to allow the `FunToken` mapping to be created with 0 decimals + * in the ERC20 sense. Often times, tokens are meant to behave like money and + * be divisible, meaning "decimals = 0" is often a mistake. This field defaults + * to false as a safety guard against accidental creation of FunTokens with + * missing metadata. + * Set this to true if the token is truly intended to have 0 decimals. + */ + allowZeroDecimals: boolean; } export interface MsgCreateFunTokenResponse { @@ -235,6 +244,34 @@ export interface MsgConvertCoinToEvm { export interface MsgConvertCoinToEvmResponse { } +/** MsgConvertEvmToCoin: Arguments to send an ERC20 token to bank coin representation */ +export interface MsgConvertEvmToCoin { + /** + * Sender: "nibi"-prefixed Bech32 address for the signer of the transaction. + * This is also the address whose ERC20 balance will be deducted. + */ + sender: string; + /** Hexadecimal address of the ERC20 token to be converted and sent */ + erc20Addr: string; + /** Amount of ERC20 tokens to convert */ + amount: string; + /** + * Recipient address for the bank coins in Ethereum hexadecimal or + * nibi-prefixed Bech32 format. + * + * Currently, accounts corresponding to Wasm contracts cannot hold ERC20 tokens + * because the function that maps between Bech32 and Eth hex addresses is not + * bijective for these types of accounts. + * + * See [bug(evm): nibid q evm account is not symmetric for wasm + * addresses](https://github.com/NibiruChain/nibiru/issues/2138) + */ + toAddr: string; +} + +export interface MsgConvertEvmToCoinResponse { +} + function createBaseMsgEthereumTx(): MsgEthereumTx { return { data: undefined, size: 0, hash: "", from: "" }; } @@ -1208,7 +1245,7 @@ export const MsgUpdateParamsResponse = { }; function createBaseMsgCreateFunToken(): MsgCreateFunToken { - return { fromErc20: "", fromBankDenom: "", sender: "" }; + return { fromErc20: "", fromBankDenom: "", sender: "", allowZeroDecimals: false }; } export const MsgCreateFunToken = { @@ -1222,6 +1259,9 @@ export const MsgCreateFunToken = { if (message.sender !== "") { writer.uint32(26).string(message.sender); } + if (message.allowZeroDecimals === true) { + writer.uint32(32).bool(message.allowZeroDecimals); + } return writer; }, @@ -1253,6 +1293,13 @@ export const MsgCreateFunToken = { message.sender = reader.string(); continue; + case 4: + if (tag !== 32) { + break; + } + + message.allowZeroDecimals = reader.bool(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -1267,6 +1314,7 @@ export const MsgCreateFunToken = { fromErc20: isSet(object.fromErc20) ? String(object.fromErc20) : "", fromBankDenom: isSet(object.fromBankDenom) ? String(object.fromBankDenom) : "", sender: isSet(object.sender) ? String(object.sender) : "", + allowZeroDecimals: isSet(object.allowZeroDecimals) ? Boolean(object.allowZeroDecimals) : false, }; }, @@ -1275,6 +1323,7 @@ export const MsgCreateFunToken = { message.fromErc20 !== undefined && (obj.fromErc20 = message.fromErc20); message.fromBankDenom !== undefined && (obj.fromBankDenom = message.fromBankDenom); message.sender !== undefined && (obj.sender = message.sender); + message.allowZeroDecimals !== undefined && (obj.allowZeroDecimals = message.allowZeroDecimals); return obj; }, @@ -1287,6 +1336,7 @@ export const MsgCreateFunToken = { message.fromErc20 = object.fromErc20 ?? ""; message.fromBankDenom = object.fromBankDenom ?? ""; message.sender = object.sender ?? ""; + message.allowZeroDecimals = object.allowZeroDecimals ?? false; return message; }, }; @@ -1484,6 +1534,147 @@ export const MsgConvertCoinToEvmResponse = { }, }; +function createBaseMsgConvertEvmToCoin(): MsgConvertEvmToCoin { + return { sender: "", erc20Addr: "", amount: "", toAddr: "" }; +} + +export const MsgConvertEvmToCoin = { + encode(message: MsgConvertEvmToCoin, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.sender !== "") { + writer.uint32(10).string(message.sender); + } + if (message.erc20Addr !== "") { + writer.uint32(18).string(message.erc20Addr); + } + if (message.amount !== "") { + writer.uint32(26).string(message.amount); + } + if (message.toAddr !== "") { + writer.uint32(34).string(message.toAddr); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): MsgConvertEvmToCoin { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseMsgConvertEvmToCoin(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.sender = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.erc20Addr = reader.string(); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.amount = reader.string(); + continue; + case 4: + if (tag !== 34) { + break; + } + + message.toAddr = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): MsgConvertEvmToCoin { + return { + sender: isSet(object.sender) ? String(object.sender) : "", + erc20Addr: isSet(object.erc20Addr) ? String(object.erc20Addr) : "", + amount: isSet(object.amount) ? String(object.amount) : "", + toAddr: isSet(object.toAddr) ? String(object.toAddr) : "", + }; + }, + + toJSON(message: MsgConvertEvmToCoin): unknown { + const obj: any = {}; + message.sender !== undefined && (obj.sender = message.sender); + message.erc20Addr !== undefined && (obj.erc20Addr = message.erc20Addr); + message.amount !== undefined && (obj.amount = message.amount); + message.toAddr !== undefined && (obj.toAddr = message.toAddr); + return obj; + }, + + create, I>>(base?: I): MsgConvertEvmToCoin { + return MsgConvertEvmToCoin.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): MsgConvertEvmToCoin { + const message = createBaseMsgConvertEvmToCoin(); + message.sender = object.sender ?? ""; + message.erc20Addr = object.erc20Addr ?? ""; + message.amount = object.amount ?? ""; + message.toAddr = object.toAddr ?? ""; + return message; + }, +}; + +function createBaseMsgConvertEvmToCoinResponse(): MsgConvertEvmToCoinResponse { + return {}; +} + +export const MsgConvertEvmToCoinResponse = { + encode(_: MsgConvertEvmToCoinResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): MsgConvertEvmToCoinResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseMsgConvertEvmToCoinResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): MsgConvertEvmToCoinResponse { + return {}; + }, + + toJSON(_: MsgConvertEvmToCoinResponse): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): MsgConvertEvmToCoinResponse { + return MsgConvertEvmToCoinResponse.fromPartial(base ?? {}); + }, + + fromPartial, I>>(_: I): MsgConvertEvmToCoinResponse { + const message = createBaseMsgConvertEvmToCoinResponse(); + return message; + }, +}; + /** Msg defines the evm Msg service. */ export interface Msg { /** EthereumTx defines a method submitting Ethereum transactions. */ @@ -1506,6 +1697,11 @@ export interface Msg { * representation. */ ConvertCoinToEvm(request: MsgConvertCoinToEvm): Promise; + /** + * ConvertEvmToCoin: Sends an ERC20 token with a valid "FunToken" mapping to the + * given recipient address as a bank coin. + */ + ConvertEvmToCoin(request: MsgConvertEvmToCoin): Promise; } export const MsgServiceName = "eth.evm.v1.Msg"; @@ -1519,6 +1715,7 @@ export class MsgClientImpl implements Msg { this.UpdateParams = this.UpdateParams.bind(this); this.CreateFunToken = this.CreateFunToken.bind(this); this.ConvertCoinToEvm = this.ConvertCoinToEvm.bind(this); + this.ConvertEvmToCoin = this.ConvertEvmToCoin.bind(this); } EthereumTx(request: MsgEthereumTx): Promise { const data = MsgEthereumTx.encode(request).finish(); @@ -1543,6 +1740,12 @@ export class MsgClientImpl implements Msg { const promise = this.rpc.request(this.service, "ConvertCoinToEvm", data); return promise.then((data) => MsgConvertCoinToEvmResponse.decode(_m0.Reader.create(data))); } + + ConvertEvmToCoin(request: MsgConvertEvmToCoin): Promise { + const data = MsgConvertEvmToCoin.encode(request).finish(); + const promise = this.rpc.request(this.service, "ConvertEvmToCoin", data); + return promise.then((data) => MsgConvertEvmToCoinResponse.decode(_m0.Reader.create(data))); + } } interface Rpc { diff --git a/src/protojs/index.eth.evm.v1.ts b/src/protojs/index.eth.evm.v1.ts index f3179cbd..4e16621b 100644 --- a/src/protojs/index.eth.evm.v1.ts +++ b/src/protojs/index.eth.evm.v1.ts @@ -1,4 +1,4 @@ /* eslint-disable */ export * from "./eth/evm/v1/evm"; -export * from "./eth/evm/v1/events"; +export * from "./eth/evm/v1/tx"; diff --git a/src/protojs/index.nibiru.devgas.v1.ts b/src/protojs/index.nibiru.devgas.v1.ts index 143a15b9..c4ebcfe0 100644 --- a/src/protojs/index.nibiru.devgas.v1.ts +++ b/src/protojs/index.nibiru.devgas.v1.ts @@ -1,3 +1,5 @@ /* eslint-disable */ -export * from "./nibiru/devgas/v1/event"; +export * from "./nibiru/devgas/v1/devgas"; +export * from "./nibiru/devgas/v1/genesis"; +export * from "./nibiru/devgas/v1/tx"; diff --git a/src/protojs/index.nibiru.epochs.v1.ts b/src/protojs/index.nibiru.epochs.v1.ts index 2871806e..b814312d 100644 --- a/src/protojs/index.nibiru.epochs.v1.ts +++ b/src/protojs/index.nibiru.epochs.v1.ts @@ -1,3 +1,3 @@ /* eslint-disable */ -export * from "./nibiru/epochs/v1/event"; +export * from "./nibiru/epochs/v1/state"; diff --git a/src/protojs/index.nibiru.evm.module.ts b/src/protojs/index.nibiru.evm.module.ts new file mode 100644 index 00000000..31c1327e --- /dev/null +++ b/src/protojs/index.nibiru.evm.module.ts @@ -0,0 +1,3 @@ +/* eslint-disable */ + +export * as v1 from "./index.nibiru.evm.module.v1"; diff --git a/src/protojs/index.nibiru.evm.module.v1.ts b/src/protojs/index.nibiru.evm.module.v1.ts new file mode 100644 index 00000000..fe36f48c --- /dev/null +++ b/src/protojs/index.nibiru.evm.module.v1.ts @@ -0,0 +1,3 @@ +/* eslint-disable */ + +export * from "./eth/evm/module/module"; diff --git a/src/protojs/index.nibiru.evm.ts b/src/protojs/index.nibiru.evm.ts new file mode 100644 index 00000000..7cd34ad4 --- /dev/null +++ b/src/protojs/index.nibiru.evm.ts @@ -0,0 +1,3 @@ +/* eslint-disable */ + +export * as module from "./index.nibiru.evm.module"; diff --git a/src/protojs/index.nibiru.inflation.v1.ts b/src/protojs/index.nibiru.inflation.v1.ts index 3de5b9db..fe47db74 100644 --- a/src/protojs/index.nibiru.inflation.v1.ts +++ b/src/protojs/index.nibiru.inflation.v1.ts @@ -1,3 +1,4 @@ /* eslint-disable */ -export * from "./nibiru/inflation/v1/event"; +export * from "./nibiru/inflation/v1/inflation"; +export * from "./nibiru/inflation/v1/tx"; diff --git a/src/protojs/index.nibiru.oracle.v1.ts b/src/protojs/index.nibiru.oracle.v1.ts index b22bf545..62f33089 100644 --- a/src/protojs/index.nibiru.oracle.v1.ts +++ b/src/protojs/index.nibiru.oracle.v1.ts @@ -1,4 +1,4 @@ /* eslint-disable */ export * from "./nibiru/oracle/v1/oracle"; -export * from "./nibiru/oracle/v1/event"; +export * from "./nibiru/oracle/v1/tx"; diff --git a/src/protojs/index.nibiru.sudo.v1.ts b/src/protojs/index.nibiru.sudo.v1.ts index 545236d3..a58d6c45 100644 --- a/src/protojs/index.nibiru.sudo.v1.ts +++ b/src/protojs/index.nibiru.sudo.v1.ts @@ -1,4 +1,3 @@ /* eslint-disable */ -export * from "./nibiru/sudo/v1/state"; -export * from "./nibiru/sudo/v1/event"; +export * from "./nibiru/sudo/v1/tx"; diff --git a/src/protojs/index.nibiru.tokenfactory.module.ts b/src/protojs/index.nibiru.tokenfactory.module.ts new file mode 100644 index 00000000..148ce8d1 --- /dev/null +++ b/src/protojs/index.nibiru.tokenfactory.module.ts @@ -0,0 +1,3 @@ +/* eslint-disable */ + +export * as v1 from "./index.nibiru.tokenfactory.module.v1"; diff --git a/src/protojs/index.nibiru.tokenfactory.module.v1.ts b/src/protojs/index.nibiru.tokenfactory.module.v1.ts new file mode 100644 index 00000000..7d97cf45 --- /dev/null +++ b/src/protojs/index.nibiru.tokenfactory.module.v1.ts @@ -0,0 +1,3 @@ +/* eslint-disable */ + +export * from "./nibiru/tokenfactory/module/module"; diff --git a/src/protojs/index.nibiru.tokenfactory.v1.ts b/src/protojs/index.nibiru.tokenfactory.v1.ts index 89e2a7c2..ec2bd889 100644 --- a/src/protojs/index.nibiru.tokenfactory.v1.ts +++ b/src/protojs/index.nibiru.tokenfactory.v1.ts @@ -1,3 +1,4 @@ /* eslint-disable */ -export * from "./nibiru/tokenfactory/v1/event"; +export * from "./nibiru/tokenfactory/v1/state"; +export * from "./nibiru/tokenfactory/v1/tx"; diff --git a/src/protojs/nibiru/oracle/v1/oracle.ts b/src/protojs/nibiru/oracle/v1/oracle.ts index bc8ce253..ba9f323a 100644 --- a/src/protojs/nibiru/oracle/v1/oracle.ts +++ b/src/protojs/nibiru/oracle/v1/oracle.ts @@ -14,7 +14,7 @@ export interface Params { */ voteThreshold: string; /** - * RewardBand defines a maxium divergence that a price vote can have from the + * RewardBand defines a maximum divergence that a price vote can have from the * weighted median in the ballot. If a vote lies within the valid range * defined by: * μ := weightedMedian, diff --git a/src/protojs/nibiru/oracle/v1/query.ts b/src/protojs/nibiru/oracle/v1/query.ts index 9fad31a4..c402910a 100644 --- a/src/protojs/nibiru/oracle/v1/query.ts +++ b/src/protojs/nibiru/oracle/v1/query.ts @@ -27,6 +27,8 @@ export interface QueryExchangeRateResponse { blockTimestampMs: Long; /** Block height when the oracle came to consensus for this price. */ blockHeight: Long; + /** True if this exchange rate has passed its expiration window. */ + isVintage: boolean; } /** @@ -263,7 +265,7 @@ export const QueryExchangeRateRequest = { }; function createBaseQueryExchangeRateResponse(): QueryExchangeRateResponse { - return { exchangeRate: "", blockTimestampMs: Long.ZERO, blockHeight: Long.UZERO }; + return { exchangeRate: "", blockTimestampMs: Long.ZERO, blockHeight: Long.UZERO, isVintage: false }; } export const QueryExchangeRateResponse = { @@ -277,6 +279,9 @@ export const QueryExchangeRateResponse = { if (!message.blockHeight.isZero()) { writer.uint32(24).uint64(message.blockHeight); } + if (message.isVintage === true) { + writer.uint32(32).bool(message.isVintage); + } return writer; }, @@ -308,6 +313,13 @@ export const QueryExchangeRateResponse = { message.blockHeight = reader.uint64() as Long; continue; + case 4: + if (tag !== 32) { + break; + } + + message.isVintage = reader.bool(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -322,6 +334,7 @@ export const QueryExchangeRateResponse = { exchangeRate: isSet(object.exchangeRate) ? String(object.exchangeRate) : "", blockTimestampMs: isSet(object.blockTimestampMs) ? Long.fromValue(object.blockTimestampMs) : Long.ZERO, blockHeight: isSet(object.blockHeight) ? Long.fromValue(object.blockHeight) : Long.UZERO, + isVintage: isSet(object.isVintage) ? Boolean(object.isVintage) : false, }; }, @@ -331,6 +344,7 @@ export const QueryExchangeRateResponse = { message.blockTimestampMs !== undefined && (obj.blockTimestampMs = (message.blockTimestampMs || Long.ZERO).toString()); message.blockHeight !== undefined && (obj.blockHeight = (message.blockHeight || Long.UZERO).toString()); + message.isVintage !== undefined && (obj.isVintage = message.isVintage); return obj; }, @@ -347,6 +361,7 @@ export const QueryExchangeRateResponse = { message.blockHeight = (object.blockHeight !== undefined && object.blockHeight !== null) ? Long.fromValue(object.blockHeight) : Long.UZERO; + message.isVintage = object.isVintage ?? false; return message; }, }; diff --git a/src/protojs/nibiru/sudo/v1/event.ts b/src/protojs/nibiru/sudo/v1/event.ts index aacd1540..3dc4c445 100644 --- a/src/protojs/nibiru/sudo/v1/event.ts +++ b/src/protojs/nibiru/sudo/v1/event.ts @@ -6,7 +6,7 @@ import { Sudoers } from "./state"; /** EventUpdateSudoers: ABCI event emitted upon execution of "MsgEditSudoers". */ export interface EventUpdateSudoers { sudoers?: Sudoers; - /** Action is the type of update that occured to the "sudoers" */ + /** Action is the type of update that occurred to the "sudoers" */ action: string; } diff --git a/src/protojs/nibiru/tokenfactory/module/module.ts b/src/protojs/nibiru/tokenfactory/module/module.ts new file mode 100644 index 00000000..3d1051b6 --- /dev/null +++ b/src/protojs/nibiru/tokenfactory/module/module.ts @@ -0,0 +1,172 @@ +/* eslint-disable */ +import Long from "long"; +import _m0 from "protobufjs/minimal"; + +/** Module is the config object for the tokenfactory module. */ +export interface Module { + /** authority defines the custom module authority. If not set, defaults to the governance module. */ + authority: string; +} + +/** ModuleAccountPermission represents permissions for a module account. */ +export interface ModuleAccountPermission { + /** account is the name of the module. */ + account: string; + /** + * permissions are the permissions this module has. Currently recognized + * values are minter, burner and staking. + */ + permissions: string[]; +} + +function createBaseModule(): Module { + return { authority: "" }; +} + +export const Module = { + encode(message: Module, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.authority !== "") { + writer.uint32(10).string(message.authority); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Module { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseModule(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.authority = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Module { + return { authority: isSet(object.authority) ? String(object.authority) : "" }; + }, + + toJSON(message: Module): unknown { + const obj: any = {}; + message.authority !== undefined && (obj.authority = message.authority); + return obj; + }, + + create, I>>(base?: I): Module { + return Module.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): Module { + const message = createBaseModule(); + message.authority = object.authority ?? ""; + return message; + }, +}; + +function createBaseModuleAccountPermission(): ModuleAccountPermission { + return { account: "", permissions: [] }; +} + +export const ModuleAccountPermission = { + encode(message: ModuleAccountPermission, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.account !== "") { + writer.uint32(10).string(message.account); + } + for (const v of message.permissions) { + writer.uint32(18).string(v!); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ModuleAccountPermission { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseModuleAccountPermission(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.account = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.permissions.push(reader.string()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ModuleAccountPermission { + return { + account: isSet(object.account) ? String(object.account) : "", + permissions: Array.isArray(object?.permissions) ? object.permissions.map((e: any) => String(e)) : [], + }; + }, + + toJSON(message: ModuleAccountPermission): unknown { + const obj: any = {}; + message.account !== undefined && (obj.account = message.account); + if (message.permissions) { + obj.permissions = message.permissions.map((e) => e); + } else { + obj.permissions = []; + } + return obj; + }, + + create, I>>(base?: I): ModuleAccountPermission { + return ModuleAccountPermission.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): ModuleAccountPermission { + const message = createBaseModuleAccountPermission(); + message.account = object.account ?? ""; + message.permissions = object.permissions?.map((e) => e) || []; + return message; + }, +}; + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +type DeepPartial = T extends Builtin ? T + : T extends Long ? string | number | Long : T extends Array ? Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any; + _m0.configure(); +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} diff --git a/src/sdk/msg/eth.test.ts b/src/sdk/msg/eth.test.ts index ae548c26..e9602664 100644 --- a/src/sdk/msg/eth.test.ts +++ b/src/sdk/msg/eth.test.ts @@ -17,6 +17,9 @@ describe("setupEthMsgExtension", () => { ConvertCoinToEvm: jest.fn().mockResolvedValue({ test: "Test", }), + ConvertEvmToCoin: jest.fn().mockResolvedValue({ + test: "Test", + }), } as unknown as query.MsgClientImpl) test("should setup extension correctly", () => { @@ -63,11 +66,13 @@ describe("setupEthMsgExtension", () => { createFuntokenFee: "", extraEips: [new Long(0)], evmChannels: [""], + canonicalWnibi: "", }, }) expect(msgUpdateParams).toHaveBeenCalledWith({ authority: "", params: { + canonicalWnibi: "", createFuntokenFee: "", extraEips: [new Long(0)], evmChannels: [""], @@ -88,11 +93,13 @@ describe("setupEthMsgExtension", () => { fromBankDenom: "", fromErc20: "", sender: "", + allowZeroDecimals: false, }) expect(msgCreateFunToken).toHaveBeenCalledWith({ fromBankDenom: "", fromErc20: "", sender: "", + allowZeroDecimals: false, }) expect(result).toEqual({ test: "Test" }) }) @@ -118,4 +125,27 @@ describe("setupEthMsgExtension", () => { expect(result).toEqual({ test: "Test" }) }) }) + + describe("convertEVMToCoin", () => { + test("should call MsgConvertEvmToCoin and return the response", async () => { + const msgConvertEvmToCoin = jest + .spyOn(query.MsgConvertEvmToCoin, "fromPartial") + .mockReturnValue({} as query.MsgConvertEvmToCoin) + + const extension = setupEthMsgExtension(mockBaseQueryClient) + const result = await extension.convertEvmToCoin({ + toAddr: "", + erc20Addr: "", + sender: "", + amount: "", + }) + expect(msgConvertEvmToCoin).toHaveBeenCalledWith({ + toAddr: "", + erc20Addr: "", + sender: "", + amount: "", + }) + expect(result).toEqual({ test: "Test" }) + }) + }) }) diff --git a/src/sdk/msg/eth.ts b/src/sdk/msg/eth.ts index d93db7bf..72a232ba 100644 --- a/src/sdk/msg/eth.ts +++ b/src/sdk/msg/eth.ts @@ -10,6 +10,8 @@ import { MsgEthereumTxResponse, MsgUpdateParams, MsgUpdateParamsResponse, + MsgConvertEvmToCoin, + MsgConvertEvmToCoinResponse, } from "../../protojs/eth/evm/v1/tx" import { GeneratedType } from "@cosmjs/proto-signing" @@ -18,6 +20,7 @@ export const ETH_MSG_TYPE_URLS = { MsgUpdateParams: `/${MsgServiceName}UpdateParams`, MsgCreateFunToken: `/${MsgServiceName}CreateFunToken`, MsgConvertCoinToEvm: `/${MsgServiceName}ConvertCoinToEvm`, + MsgConvertEvmToCoin: `/${MsgServiceName}ConvertEvmToCoin`, } export const ethTypes: ReadonlyArray<[string, GeneratedType]> = [ @@ -25,6 +28,7 @@ export const ethTypes: ReadonlyArray<[string, GeneratedType]> = [ [ETH_MSG_TYPE_URLS.MsgUpdateParams, MsgUpdateParams], [ETH_MSG_TYPE_URLS.MsgCreateFunToken, MsgCreateFunToken], [ETH_MSG_TYPE_URLS.MsgConvertCoinToEvm, MsgConvertCoinToEvm], + [ETH_MSG_TYPE_URLS.MsgConvertEvmToCoin, MsgConvertEvmToCoin], ] export interface EthMsgExtension { @@ -36,6 +40,9 @@ export interface EthMsgExtension { convertCoinToEVM: ( body: MsgConvertCoinToEvm ) => Promise + convertEvmToCoin: ( + body: MsgConvertEvmToCoin + ) => Promise } export const setupEthMsgExtension = (base: QueryClient): EthMsgExtension => { @@ -50,5 +57,7 @@ export const setupEthMsgExtension = (base: QueryClient): EthMsgExtension => { queryService.CreateFunToken(MsgCreateFunToken.fromPartial(body)), convertCoinToEVM: async (body: MsgConvertCoinToEvm) => queryService.ConvertCoinToEvm(MsgConvertCoinToEvm.fromPartial(body)), + convertEvmToCoin: async (body: MsgConvertEvmToCoin) => + queryService.ConvertEvmToCoin(MsgConvertEvmToCoin.fromPartial(body)), } } diff --git a/src/sdk/query/oracle.test.ts b/src/sdk/query/oracle.test.ts index 8deb6d2e..96ab118e 100644 --- a/src/sdk/query/oracle.test.ts +++ b/src/sdk/query/oracle.test.ts @@ -40,6 +40,7 @@ describe("setupOracleExtension", () => { exchangeRate: "123", blockHeight: Long.fromNumber(420), blockTimestampMs: Long.fromNumber(100000), + isVintage: false, } const mockExchangeRate = fromSdkDec(mockExchangeRateResponse.exchangeRate) const mockExchangeRatesResponse: query.QueryExchangeRatesResponse = {