diff --git a/.github/workflows/protocol-release.yml b/.github/workflows/protocol-release.yml index 66cb9527ca..6477838dc0 100644 --- a/.github/workflows/protocol-release.yml +++ b/.github/workflows/protocol-release.yml @@ -120,6 +120,9 @@ jobs: TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} run: | twine upload -r pypi dist/* + with: + ENVIRONMENT: release + secrets: inherit v4-proto-js-release: runs-on: ubuntu-latest diff --git a/indexer/packages/postgres/__tests__/stores/vault-pnl-ticks-view.test.ts b/indexer/packages/postgres/__tests__/stores/vault-pnl-ticks-view.test.ts new file mode 100644 index 0000000000..eaf69d671f --- /dev/null +++ b/indexer/packages/postgres/__tests__/stores/vault-pnl-ticks-view.test.ts @@ -0,0 +1,209 @@ +import { + PnlTickInterval, + PnlTicksFromDatabase, +} from '../../src/types'; +import * as VaultPnlTicksView from '../../src/stores/vault-pnl-ticks-view'; +import * as PnlTicksTable from '../../src/stores/pnl-ticks-table'; +import * as BlockTable from '../../src/stores/block-table'; +import * as VaultTable from '../../src/stores/vault-table'; +import { clearData, migrate, teardown } from '../../src/helpers/db-helpers'; +import { seedData } from '../helpers/mock-generators'; +import * as WalletTable from '../../src/stores/wallet-table'; +import * as SubaccountTable from '../../src/stores/subaccount-table'; +import { + defaultSubaccountId, + defaultSubaccountIdWithAlternateAddress, + defaultSubaccountWithAlternateAddress, + defaultWallet2, + defaultVault, + defaultSubaccount, +} from '../helpers/constants'; +import { DateTime } from 'luxon'; + +describe('PnlTicks store', () => { + beforeEach(async () => { + await seedData(); + await WalletTable.create(defaultWallet2); + await SubaccountTable.create(defaultSubaccountWithAlternateAddress); + await Promise.all([ + VaultTable.create({ + ...defaultVault, + address: defaultSubaccount.address, + }), + VaultTable.create({ + ...defaultVault, + address: defaultSubaccountWithAlternateAddress.address, + }), + ]); + }); + + beforeAll(async () => { + await migrate(); + }); + + afterEach(async () => { + await clearData(); + }); + + afterAll(async () => { + await teardown(); + }); + + it.each([ + { + description: 'Get hourly pnl ticks', + interval: PnlTickInterval.hour, + }, + { + description: 'Get daily pnl ticks', + interval: PnlTickInterval.day, + }, + ])('$description', async ({ + interval, + }: { + interval: PnlTickInterval, + }) => { + const createdTicks: PnlTicksFromDatabase[] = await setupIntervalPnlTicks(); + await VaultPnlTicksView.refreshDailyView(); + await VaultPnlTicksView.refreshHourlyView(); + const pnlTicks: PnlTicksFromDatabase[] = await VaultPnlTicksView.getVaultsPnl( + interval, + 7 * 24 * 60 * 60, // 1 week + DateTime.fromISO(createdTicks[8].blockTime).plus({ seconds: 1 }), + ); + // See setup function for created ticks. + // Should exclude tick that is within the same hour except the first. + const expectedHourlyTicks: PnlTicksFromDatabase[] = [ + createdTicks[7], + createdTicks[5], + createdTicks[2], + createdTicks[0], + ]; + // Should exclude ticks that is within the same day except for the first. + const expectedDailyTicks: PnlTicksFromDatabase[] = [ + createdTicks[7], + createdTicks[2], + ]; + + if (interval === PnlTickInterval.day) { + expect(pnlTicks).toEqual(expectedDailyTicks); + } else if (interval === PnlTickInterval.hour) { + expect(pnlTicks).toEqual(expectedHourlyTicks); + } + }); + + async function setupIntervalPnlTicks(): Promise { + const currentTime: DateTime = DateTime.utc().startOf('day'); + const tenMinAgo: string = currentTime.minus({ minute: 10 }).toISO(); + const almostTenMinAgo: string = currentTime.minus({ second: 603 }).toISO(); + const twoHoursAgo: string = currentTime.minus({ hour: 2 }).toISO(); + const twoDaysAgo: string = currentTime.minus({ day: 2 }).toISO(); + const monthAgo: string = currentTime.minus({ day: 30 }).toISO(); + await Promise.all([ + BlockTable.create({ + blockHeight: '3', + time: monthAgo, + }), + BlockTable.create({ + blockHeight: '4', + time: twoDaysAgo, + }), + BlockTable.create({ + blockHeight: '6', + time: twoHoursAgo, + }), + BlockTable.create({ + blockHeight: '8', + time: almostTenMinAgo, + }), + BlockTable.create({ + blockHeight: '10', + time: tenMinAgo, + }), + ]); + const createdTicks: PnlTicksFromDatabase[] = await PnlTicksTable.createMany([ + { + subaccountId: defaultSubaccountId, + equity: '1100', + createdAt: almostTenMinAgo, + totalPnl: '1200', + netTransfers: '50', + blockHeight: '10', + blockTime: almostTenMinAgo, + }, + { + subaccountId: defaultSubaccountId, + equity: '1090', + createdAt: tenMinAgo, + totalPnl: '1190', + netTransfers: '50', + blockHeight: '8', + blockTime: tenMinAgo, + }, + { + subaccountId: defaultSubaccountId, + equity: '1080', + createdAt: twoHoursAgo, + totalPnl: '1180', + netTransfers: '50', + blockHeight: '6', + blockTime: twoHoursAgo, + }, + { + subaccountId: defaultSubaccountId, + equity: '1070', + createdAt: twoDaysAgo, + totalPnl: '1170', + netTransfers: '50', + blockHeight: '4', + blockTime: twoDaysAgo, + }, + { + subaccountId: defaultSubaccountId, + equity: '1200', + createdAt: monthAgo, + totalPnl: '1170', + netTransfers: '50', + blockHeight: '3', + blockTime: monthAgo, + }, + { + subaccountId: defaultSubaccountIdWithAlternateAddress, + equity: '200', + createdAt: almostTenMinAgo, + totalPnl: '300', + netTransfers: '50', + blockHeight: '10', + blockTime: almostTenMinAgo, + }, + { + subaccountId: defaultSubaccountIdWithAlternateAddress, + equity: '210', + createdAt: tenMinAgo, + totalPnl: '310', + netTransfers: '50', + blockHeight: '8', + blockTime: tenMinAgo, + }, + { + subaccountId: defaultSubaccountIdWithAlternateAddress, + equity: '220', + createdAt: twoHoursAgo, + totalPnl: '320', + netTransfers: '50', + blockHeight: '6', + blockTime: twoHoursAgo, + }, + { + subaccountId: defaultSubaccountIdWithAlternateAddress, + equity: '230', + createdAt: twoDaysAgo, + totalPnl: '330', + netTransfers: '50', + blockHeight: '4', + blockTime: twoDaysAgo, + }, + ]); + return createdTicks; + } +}); diff --git a/indexer/packages/postgres/src/db/migrations/migration_files/20241119162238_create_vault_hourly_view.ts b/indexer/packages/postgres/src/db/migrations/migration_files/20241119162238_create_vault_hourly_view.ts new file mode 100644 index 0000000000..fe0e4336d1 --- /dev/null +++ b/indexer/packages/postgres/src/db/migrations/migration_files/20241119162238_create_vault_hourly_view.ts @@ -0,0 +1,47 @@ +import * as Knex from 'knex'; + +const RAW_VAULTS_PNL_HOURLY_QUERY: string = ` +CREATE MATERIALIZED VIEW IF NOT EXISTS vaults_hourly_pnl AS WITH vault_subaccounts AS +( + SELECT subaccounts.id + FROM vaults, + subaccounts + WHERE vaults.address = subaccounts.address + AND subaccounts."subaccountNumber" = 0), pnl_subaccounts AS +( + SELECT * + FROM vault_subaccounts + UNION + SELECT id + FROM subaccounts + WHERE address = 'dydx18tkxrnrkqc2t0lr3zxr5g6a4hdvqksylxqje4r' + AND "subaccountNumber" = 0) +SELECT "id", + "subaccountId", + "equity", + "totalPnl", + "netTransfers", + "createdAt", + "blockHeight", + "blockTime" +FROM ( + SELECT pnl_ticks.*, + ROW_NUMBER() OVER ( partition BY "subaccountId", DATE_TRUNC( 'hour', "blockTime" ) ORDER BY "blockTime" ) AS r + FROM pnl_ticks + WHERE "subaccountId" IN + ( + SELECT * + FROM pnl_subaccounts) + AND "blockTime" >= NOW() - interval '604800 second' ) AS pnl_intervals +WHERE r = 1 +ORDER BY "subaccountId"; +`; + +export async function up(knex: Knex): Promise { + await knex.raw(RAW_VAULTS_PNL_HOURLY_QUERY); + await knex.raw('CREATE UNIQUE INDEX ON vaults_hourly_pnl (id);'); +} + +export async function down(knex: Knex): Promise { + await knex.raw('DROP MATERIALIZED VIEW IF EXISTS vaults_hourly_pnl;'); +} diff --git a/indexer/packages/postgres/src/db/migrations/migration_files/20241119163402_create_vault_daily_view.ts b/indexer/packages/postgres/src/db/migrations/migration_files/20241119163402_create_vault_daily_view.ts new file mode 100644 index 0000000000..4469a8bec5 --- /dev/null +++ b/indexer/packages/postgres/src/db/migrations/migration_files/20241119163402_create_vault_daily_view.ts @@ -0,0 +1,47 @@ +import * as Knex from 'knex'; + +const RAW_VAULTS_PNL_DAILY_QUERY: string = ` +CREATE MATERIALIZED VIEW IF NOT EXISTS vaults_daily_pnl AS WITH vault_subaccounts AS +( + SELECT subaccounts.id + FROM vaults, + subaccounts + WHERE vaults.address = subaccounts.address + AND subaccounts."subaccountNumber" = 0), pnl_subaccounts AS +( + SELECT * + FROM vault_subaccounts + UNION + SELECT id + FROM subaccounts + WHERE address = 'dydx18tkxrnrkqc2t0lr3zxr5g6a4hdvqksylxqje4r' + AND "subaccountNumber" = 0) +SELECT "id", + "subaccountId", + "equity", + "totalPnl", + "netTransfers", + "createdAt", + "blockHeight", + "blockTime" +FROM ( + SELECT pnl_ticks.*, + ROW_NUMBER() OVER ( partition BY "subaccountId", DATE_TRUNC( 'day', "blockTime" ) ORDER BY "blockTime" ) AS r + FROM pnl_ticks + WHERE "subaccountId" IN + ( + SELECT * + FROM pnl_subaccounts) + AND "blockTime" >= NOW() - interval '7776000 second' ) AS pnl_intervals +WHERE r = 1 +ORDER BY "subaccountId"; +`; + +export async function up(knex: Knex): Promise { + await knex.raw(RAW_VAULTS_PNL_DAILY_QUERY); + await knex.raw('CREATE UNIQUE INDEX ON vaults_daily_pnl (id);'); +} + +export async function down(knex: Knex): Promise { + await knex.raw('DROP MATERIALIZED VIEW IF EXISTS vaults_daily_pnl;'); +} diff --git a/indexer/packages/postgres/src/index.ts b/indexer/packages/postgres/src/index.ts index 70c0d719a5..52b328a1e7 100644 --- a/indexer/packages/postgres/src/index.ts +++ b/indexer/packages/postgres/src/index.ts @@ -51,6 +51,7 @@ export * as AffiliateReferredUsersTable from './stores/affiliate-referred-users- export * as FirebaseNotificationTokenTable from './stores/firebase-notification-token-table'; export * as AffiliateInfoTable from './stores/affiliate-info-table'; export * as VaultTable from './stores/vault-table'; +export * as VaultPnlTicksView from './stores/vault-pnl-ticks-view'; export * as perpetualMarketRefresher from './loops/perpetual-market-refresher'; export * as assetRefresher from './loops/asset-refresher'; diff --git a/indexer/packages/postgres/src/stores/pnl-ticks-table.ts b/indexer/packages/postgres/src/stores/pnl-ticks-table.ts index 30181a751e..99cffb05c3 100644 --- a/indexer/packages/postgres/src/stores/pnl-ticks-table.ts +++ b/indexer/packages/postgres/src/stores/pnl-ticks-table.ts @@ -537,7 +537,8 @@ export async function getLatestPnlTick( pnl_ticks WHERE "subaccountId" in (${subaccountIds.map((id: string) => { return `'${id}'`; }).join(',')}) AND - "blockTime" <= '${beforeOrAt.toUTC().toISO()}'::timestamp + "blockTime" <= '${beforeOrAt.toUTC().toISO()}'::timestamp AND + "blockTime" >= '${beforeOrAt.toUTC().minus({ hours: 4 }).toISO()}'::timestamp ORDER BY "subaccountId", "blockTime" DESC diff --git a/indexer/packages/postgres/src/stores/vault-pnl-ticks-view.ts b/indexer/packages/postgres/src/stores/vault-pnl-ticks-view.ts new file mode 100644 index 0000000000..abac0a88b2 --- /dev/null +++ b/indexer/packages/postgres/src/stores/vault-pnl-ticks-view.ts @@ -0,0 +1,64 @@ +import { DateTime } from 'luxon'; + +import { knexReadReplica } from '../helpers/knex'; +import { rawQuery } from '../helpers/stores-helpers'; +import { + PnlTickInterval, + PnlTicksFromDatabase, +} from '../types'; + +const VAULT_HOURLY_PNL_VIEW: string = 'vaults_hourly_pnl'; +const VAULT_DAILY_PNL_VIEW: string = 'vaults_daily_pnl'; + +export async function refreshHourlyView(): Promise { + await rawQuery( + `REFRESH MATERIALIZED VIEW CONCURRENTLY ${VAULT_HOURLY_PNL_VIEW}`, + { + readReplica: false, + }, + ); +} + +export async function refreshDailyView(): Promise { + await rawQuery( + `REFRESH MATERIALIZED VIEW CONCURRENTLY ${VAULT_DAILY_PNL_VIEW}`, + { + readReplica: false, + }, + ); +} + +export async function getVaultsPnl( + interval: PnlTickInterval, + timeWindowSeconds: number, + earliestDate: DateTime, +): Promise { + let viewName: string = VAULT_DAILY_PNL_VIEW; + if (interval === PnlTickInterval.hour) { + viewName = VAULT_HOURLY_PNL_VIEW; + } + const result: { + rows: PnlTicksFromDatabase[], + } = await knexReadReplica.getConnection().raw( + ` + SELECT + "id", + "subaccountId", + "equity", + "totalPnl", + "netTransfers", + "createdAt", + "blockHeight", + "blockTime" + FROM ${viewName} + WHERE + "blockTime" >= '${earliestDate.toUTC().toISO()}'::timestamp AND + "blockTime" > NOW() - INTERVAL '${timeWindowSeconds} second' + ORDER BY "subaccountId", "blockTime"; + `, + ) as unknown as { + rows: PnlTicksFromDatabase[], + }; + + return result.rows; +} diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts index 42aaa1e67a..69bef10149 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/bundle.ts @@ -80,109 +80,110 @@ import * as _83 from "./prices/genesis"; import * as _84 from "./prices/market_param"; import * as _85 from "./prices/market_price"; import * as _86 from "./prices/query"; -import * as _87 from "./prices/tx"; -import * as _88 from "./ratelimit/capacity"; -import * as _89 from "./ratelimit/genesis"; -import * as _90 from "./ratelimit/limit_params"; -import * as _91 from "./ratelimit/pending_send_packet"; -import * as _92 from "./ratelimit/query"; -import * as _93 from "./ratelimit/tx"; -import * as _94 from "./revshare/genesis"; -import * as _95 from "./revshare/params"; -import * as _96 from "./revshare/query"; -import * as _97 from "./revshare/revshare"; -import * as _98 from "./revshare/tx"; -import * as _99 from "./rewards/genesis"; -import * as _100 from "./rewards/params"; -import * as _101 from "./rewards/query"; -import * as _102 from "./rewards/reward_share"; -import * as _103 from "./rewards/tx"; -import * as _104 from "./sending/genesis"; -import * as _105 from "./sending/query"; -import * as _106 from "./sending/transfer"; -import * as _107 from "./sending/tx"; -import * as _108 from "./stats/genesis"; -import * as _109 from "./stats/params"; -import * as _110 from "./stats/query"; -import * as _111 from "./stats/stats"; -import * as _112 from "./stats/tx"; -import * as _113 from "./subaccounts/asset_position"; -import * as _114 from "./subaccounts/genesis"; -import * as _115 from "./subaccounts/perpetual_position"; -import * as _116 from "./subaccounts/query"; -import * as _117 from "./subaccounts/streaming"; -import * as _118 from "./subaccounts/subaccount"; -import * as _119 from "./vault/genesis"; -import * as _120 from "./vault/params"; -import * as _121 from "./vault/query"; -import * as _122 from "./vault/share"; -import * as _123 from "./vault/tx"; -import * as _124 from "./vault/vault"; -import * as _125 from "./vest/genesis"; -import * as _126 from "./vest/query"; -import * as _127 from "./vest/tx"; -import * as _128 from "./vest/vest_entry"; -import * as _136 from "./accountplus/query.lcd"; -import * as _137 from "./affiliates/query.lcd"; -import * as _138 from "./assets/query.lcd"; -import * as _139 from "./blocktime/query.lcd"; -import * as _140 from "./bridge/query.lcd"; -import * as _141 from "./clob/query.lcd"; -import * as _142 from "./delaymsg/query.lcd"; -import * as _143 from "./epochs/query.lcd"; -import * as _144 from "./feetiers/query.lcd"; -import * as _145 from "./listing/query.lcd"; -import * as _146 from "./perpetuals/query.lcd"; -import * as _147 from "./prices/query.lcd"; -import * as _148 from "./ratelimit/query.lcd"; -import * as _149 from "./revshare/query.lcd"; -import * as _150 from "./rewards/query.lcd"; -import * as _151 from "./stats/query.lcd"; -import * as _152 from "./subaccounts/query.lcd"; -import * as _153 from "./vault/query.lcd"; -import * as _154 from "./vest/query.lcd"; -import * as _155 from "./accountplus/query.rpc.Query"; -import * as _156 from "./affiliates/query.rpc.Query"; -import * as _157 from "./assets/query.rpc.Query"; -import * as _158 from "./blocktime/query.rpc.Query"; -import * as _159 from "./bridge/query.rpc.Query"; -import * as _160 from "./clob/query.rpc.Query"; -import * as _161 from "./delaymsg/query.rpc.Query"; -import * as _162 from "./epochs/query.rpc.Query"; -import * as _163 from "./feetiers/query.rpc.Query"; -import * as _164 from "./govplus/query.rpc.Query"; -import * as _165 from "./listing/query.rpc.Query"; -import * as _166 from "./perpetuals/query.rpc.Query"; -import * as _167 from "./prices/query.rpc.Query"; -import * as _168 from "./ratelimit/query.rpc.Query"; -import * as _169 from "./revshare/query.rpc.Query"; -import * as _170 from "./rewards/query.rpc.Query"; -import * as _171 from "./sending/query.rpc.Query"; -import * as _172 from "./stats/query.rpc.Query"; -import * as _173 from "./subaccounts/query.rpc.Query"; -import * as _174 from "./vault/query.rpc.Query"; -import * as _175 from "./vest/query.rpc.Query"; -import * as _176 from "./accountplus/tx.rpc.msg"; -import * as _177 from "./affiliates/tx.rpc.msg"; -import * as _178 from "./blocktime/tx.rpc.msg"; -import * as _179 from "./bridge/tx.rpc.msg"; -import * as _180 from "./clob/tx.rpc.msg"; -import * as _181 from "./delaymsg/tx.rpc.msg"; -import * as _182 from "./feetiers/tx.rpc.msg"; -import * as _183 from "./govplus/tx.rpc.msg"; -import * as _184 from "./listing/tx.rpc.msg"; -import * as _185 from "./perpetuals/tx.rpc.msg"; -import * as _186 from "./prices/tx.rpc.msg"; -import * as _187 from "./ratelimit/tx.rpc.msg"; -import * as _188 from "./revshare/tx.rpc.msg"; -import * as _189 from "./rewards/tx.rpc.msg"; -import * as _190 from "./sending/tx.rpc.msg"; -import * as _191 from "./stats/tx.rpc.msg"; -import * as _192 from "./vault/tx.rpc.msg"; -import * as _193 from "./vest/tx.rpc.msg"; -import * as _194 from "./lcd"; -import * as _195 from "./rpc.query"; -import * as _196 from "./rpc.tx"; +import * as _87 from "./prices/streaming"; +import * as _88 from "./prices/tx"; +import * as _89 from "./ratelimit/capacity"; +import * as _90 from "./ratelimit/genesis"; +import * as _91 from "./ratelimit/limit_params"; +import * as _92 from "./ratelimit/pending_send_packet"; +import * as _93 from "./ratelimit/query"; +import * as _94 from "./ratelimit/tx"; +import * as _95 from "./revshare/genesis"; +import * as _96 from "./revshare/params"; +import * as _97 from "./revshare/query"; +import * as _98 from "./revshare/revshare"; +import * as _99 from "./revshare/tx"; +import * as _100 from "./rewards/genesis"; +import * as _101 from "./rewards/params"; +import * as _102 from "./rewards/query"; +import * as _103 from "./rewards/reward_share"; +import * as _104 from "./rewards/tx"; +import * as _105 from "./sending/genesis"; +import * as _106 from "./sending/query"; +import * as _107 from "./sending/transfer"; +import * as _108 from "./sending/tx"; +import * as _109 from "./stats/genesis"; +import * as _110 from "./stats/params"; +import * as _111 from "./stats/query"; +import * as _112 from "./stats/stats"; +import * as _113 from "./stats/tx"; +import * as _114 from "./subaccounts/asset_position"; +import * as _115 from "./subaccounts/genesis"; +import * as _116 from "./subaccounts/perpetual_position"; +import * as _117 from "./subaccounts/query"; +import * as _118 from "./subaccounts/streaming"; +import * as _119 from "./subaccounts/subaccount"; +import * as _120 from "./vault/genesis"; +import * as _121 from "./vault/params"; +import * as _122 from "./vault/query"; +import * as _123 from "./vault/share"; +import * as _124 from "./vault/tx"; +import * as _125 from "./vault/vault"; +import * as _126 from "./vest/genesis"; +import * as _127 from "./vest/query"; +import * as _128 from "./vest/tx"; +import * as _129 from "./vest/vest_entry"; +import * as _137 from "./accountplus/query.lcd"; +import * as _138 from "./affiliates/query.lcd"; +import * as _139 from "./assets/query.lcd"; +import * as _140 from "./blocktime/query.lcd"; +import * as _141 from "./bridge/query.lcd"; +import * as _142 from "./clob/query.lcd"; +import * as _143 from "./delaymsg/query.lcd"; +import * as _144 from "./epochs/query.lcd"; +import * as _145 from "./feetiers/query.lcd"; +import * as _146 from "./listing/query.lcd"; +import * as _147 from "./perpetuals/query.lcd"; +import * as _148 from "./prices/query.lcd"; +import * as _149 from "./ratelimit/query.lcd"; +import * as _150 from "./revshare/query.lcd"; +import * as _151 from "./rewards/query.lcd"; +import * as _152 from "./stats/query.lcd"; +import * as _153 from "./subaccounts/query.lcd"; +import * as _154 from "./vault/query.lcd"; +import * as _155 from "./vest/query.lcd"; +import * as _156 from "./accountplus/query.rpc.Query"; +import * as _157 from "./affiliates/query.rpc.Query"; +import * as _158 from "./assets/query.rpc.Query"; +import * as _159 from "./blocktime/query.rpc.Query"; +import * as _160 from "./bridge/query.rpc.Query"; +import * as _161 from "./clob/query.rpc.Query"; +import * as _162 from "./delaymsg/query.rpc.Query"; +import * as _163 from "./epochs/query.rpc.Query"; +import * as _164 from "./feetiers/query.rpc.Query"; +import * as _165 from "./govplus/query.rpc.Query"; +import * as _166 from "./listing/query.rpc.Query"; +import * as _167 from "./perpetuals/query.rpc.Query"; +import * as _168 from "./prices/query.rpc.Query"; +import * as _169 from "./ratelimit/query.rpc.Query"; +import * as _170 from "./revshare/query.rpc.Query"; +import * as _171 from "./rewards/query.rpc.Query"; +import * as _172 from "./sending/query.rpc.Query"; +import * as _173 from "./stats/query.rpc.Query"; +import * as _174 from "./subaccounts/query.rpc.Query"; +import * as _175 from "./vault/query.rpc.Query"; +import * as _176 from "./vest/query.rpc.Query"; +import * as _177 from "./accountplus/tx.rpc.msg"; +import * as _178 from "./affiliates/tx.rpc.msg"; +import * as _179 from "./blocktime/tx.rpc.msg"; +import * as _180 from "./bridge/tx.rpc.msg"; +import * as _181 from "./clob/tx.rpc.msg"; +import * as _182 from "./delaymsg/tx.rpc.msg"; +import * as _183 from "./feetiers/tx.rpc.msg"; +import * as _184 from "./govplus/tx.rpc.msg"; +import * as _185 from "./listing/tx.rpc.msg"; +import * as _186 from "./perpetuals/tx.rpc.msg"; +import * as _187 from "./prices/tx.rpc.msg"; +import * as _188 from "./ratelimit/tx.rpc.msg"; +import * as _189 from "./revshare/tx.rpc.msg"; +import * as _190 from "./rewards/tx.rpc.msg"; +import * as _191 from "./sending/tx.rpc.msg"; +import * as _192 from "./stats/tx.rpc.msg"; +import * as _193 from "./vault/tx.rpc.msg"; +import * as _194 from "./vest/tx.rpc.msg"; +import * as _195 from "./lcd"; +import * as _196 from "./rpc.query"; +import * as _197 from "./rpc.tx"; export namespace dydxprotocol { export const accountplus = { ..._5, ..._6, @@ -190,33 +191,33 @@ export namespace dydxprotocol { ..._8, ..._9, ..._10, - ..._136, - ..._155, - ..._176 + ..._137, + ..._156, + ..._177 }; export const affiliates = { ..._11, ..._12, ..._13, ..._14, - ..._137, - ..._156, - ..._177 + ..._138, + ..._157, + ..._178 }; export const assets = { ..._15, ..._16, ..._17, ..._18, - ..._138, - ..._157 + ..._139, + ..._158 }; export const blocktime = { ..._19, ..._20, ..._21, ..._22, ..._23, - ..._139, - ..._158, - ..._178 + ..._140, + ..._159, + ..._179 }; export const bridge = { ..._24, ..._25, @@ -224,9 +225,9 @@ export namespace dydxprotocol { ..._27, ..._28, ..._29, - ..._140, - ..._159, - ..._179 + ..._141, + ..._160, + ..._180 }; export const clob = { ..._30, ..._31, @@ -244,9 +245,9 @@ export namespace dydxprotocol { ..._43, ..._44, ..._45, - ..._141, - ..._160, - ..._180 + ..._142, + ..._161, + ..._181 }; export namespace daemons { export const bridge = { ..._46 @@ -261,29 +262,29 @@ export namespace dydxprotocol { ..._51, ..._52, ..._53, - ..._142, - ..._161, - ..._181 + ..._143, + ..._162, + ..._182 }; export const epochs = { ..._54, ..._55, ..._56, - ..._143, - ..._162 + ..._144, + ..._163 }; export const feetiers = { ..._57, ..._58, ..._59, ..._60, - ..._144, - ..._163, - ..._182 + ..._145, + ..._164, + ..._183 }; export const govplus = { ..._61, ..._62, ..._63, - ..._164, - ..._183 + ..._165, + ..._184 }; export namespace indexer { export const events = { ..._64 @@ -310,101 +311,102 @@ export namespace dydxprotocol { ..._75, ..._76, ..._77, - ..._145, - ..._165, - ..._184 + ..._146, + ..._166, + ..._185 }; export const perpetuals = { ..._78, ..._79, ..._80, ..._81, ..._82, - ..._146, - ..._166, - ..._185 + ..._147, + ..._167, + ..._186 }; export const prices = { ..._83, ..._84, ..._85, ..._86, ..._87, - ..._147, - ..._167, - ..._186 + ..._88, + ..._148, + ..._168, + ..._187 }; - export const ratelimit = { ..._88, - ..._89, + export const ratelimit = { ..._89, ..._90, ..._91, ..._92, ..._93, - ..._148, - ..._168, - ..._187 + ..._94, + ..._149, + ..._169, + ..._188 }; - export const revshare = { ..._94, - ..._95, + export const revshare = { ..._95, ..._96, ..._97, ..._98, - ..._149, - ..._169, - ..._188 + ..._99, + ..._150, + ..._170, + ..._189 }; - export const rewards = { ..._99, - ..._100, + export const rewards = { ..._100, ..._101, ..._102, ..._103, - ..._150, - ..._170, - ..._189 + ..._104, + ..._151, + ..._171, + ..._190 }; - export const sending = { ..._104, - ..._105, + export const sending = { ..._105, ..._106, ..._107, - ..._171, - ..._190 + ..._108, + ..._172, + ..._191 }; - export const stats = { ..._108, - ..._109, + export const stats = { ..._109, ..._110, ..._111, ..._112, - ..._151, - ..._172, - ..._191 + ..._113, + ..._152, + ..._173, + ..._192 }; - export const subaccounts = { ..._113, - ..._114, + export const subaccounts = { ..._114, ..._115, ..._116, ..._117, ..._118, - ..._152, - ..._173 + ..._119, + ..._153, + ..._174 }; - export const vault = { ..._119, - ..._120, + export const vault = { ..._120, ..._121, ..._122, ..._123, ..._124, - ..._153, - ..._174, - ..._192 - }; - export const vest = { ..._125, - ..._126, - ..._127, - ..._128, + ..._125, ..._154, ..._175, ..._193 }; - export const ClientFactory = { ..._194, - ..._195, - ..._196 + export const vest = { ..._126, + ..._127, + ..._128, + ..._129, + ..._155, + ..._176, + ..._194 + }; + export const ClientFactory = { ..._195, + ..._196, + ..._197 }; } \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts index a2abeab07e..b603256197 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts @@ -7,6 +7,7 @@ import { EquityTierLimitConfiguration, EquityTierLimitConfigurationSDKType } fro import { BlockRateLimitConfiguration, BlockRateLimitConfigurationSDKType } from "./block_rate_limit_config"; import { LiquidationsConfig, LiquidationsConfigSDKType } from "./liquidations_config"; import { StreamSubaccountUpdate, StreamSubaccountUpdateSDKType } from "../subaccounts/streaming"; +import { StreamPriceUpdate, StreamPriceUpdateSDKType } from "../prices/streaming"; import { OffChainUpdateV1, OffChainUpdateV1SDKType } from "../indexer/off_chain_updates/off_chain_updates"; import { ClobMatch, ClobMatchSDKType } from "./matches"; import * as _m0 from "protobufjs/minimal"; @@ -274,6 +275,9 @@ export interface StreamOrderbookUpdatesRequest { /** Subaccount ids to stream subaccount updates for. */ subaccountIds: SubaccountId[]; + /** Market ids for price updates. */ + + marketIds: number[]; } /** * StreamOrderbookUpdatesRequest is a request message for the @@ -286,6 +290,9 @@ export interface StreamOrderbookUpdatesRequestSDKType { /** Subaccount ids to stream subaccount updates for. */ subaccount_ids: SubaccountIdSDKType[]; + /** Market ids for price updates. */ + + market_ids: number[]; } /** * StreamOrderbookUpdatesResponse is a response message for the @@ -320,6 +327,7 @@ export interface StreamUpdate { orderFill?: StreamOrderbookFill; takerOrder?: StreamTakerOrder; subaccountUpdate?: StreamSubaccountUpdate; + priceUpdate?: StreamPriceUpdate; } /** * StreamUpdate is an update that will be pushed through the @@ -336,6 +344,7 @@ export interface StreamUpdateSDKType { order_fill?: StreamOrderbookFillSDKType; taker_order?: StreamTakerOrderSDKType; subaccount_update?: StreamSubaccountUpdateSDKType; + price_update?: StreamPriceUpdateSDKType; } /** * StreamOrderbookUpdate provides information on an orderbook update. Used in @@ -1288,7 +1297,8 @@ export const QueryNextClobPairIdResponse = { function createBaseStreamOrderbookUpdatesRequest(): StreamOrderbookUpdatesRequest { return { clobPairId: [], - subaccountIds: [] + subaccountIds: [], + marketIds: [] }; } @@ -1306,6 +1316,13 @@ export const StreamOrderbookUpdatesRequest = { SubaccountId.encode(v!, writer.uint32(18).fork()).ldelim(); } + writer.uint32(26).fork(); + + for (const v of message.marketIds) { + writer.uint32(v); + } + + writer.ldelim(); return writer; }, @@ -1335,6 +1352,19 @@ export const StreamOrderbookUpdatesRequest = { message.subaccountIds.push(SubaccountId.decode(reader, reader.uint32())); break; + case 3: + if ((tag & 7) === 2) { + const end2 = reader.uint32() + reader.pos; + + while (reader.pos < end2) { + message.marketIds.push(reader.uint32()); + } + } else { + message.marketIds.push(reader.uint32()); + } + + break; + default: reader.skipType(tag & 7); break; @@ -1348,6 +1378,7 @@ export const StreamOrderbookUpdatesRequest = { const message = createBaseStreamOrderbookUpdatesRequest(); message.clobPairId = object.clobPairId?.map(e => e) || []; message.subaccountIds = object.subaccountIds?.map(e => SubaccountId.fromPartial(e)) || []; + message.marketIds = object.marketIds?.map(e => e) || []; return message; } @@ -1405,7 +1436,8 @@ function createBaseStreamUpdate(): StreamUpdate { orderbookUpdate: undefined, orderFill: undefined, takerOrder: undefined, - subaccountUpdate: undefined + subaccountUpdate: undefined, + priceUpdate: undefined }; } @@ -1435,6 +1467,10 @@ export const StreamUpdate = { StreamSubaccountUpdate.encode(message.subaccountUpdate, writer.uint32(50).fork()).ldelim(); } + if (message.priceUpdate !== undefined) { + StreamPriceUpdate.encode(message.priceUpdate, writer.uint32(58).fork()).ldelim(); + } + return writer; }, @@ -1471,6 +1507,10 @@ export const StreamUpdate = { message.subaccountUpdate = StreamSubaccountUpdate.decode(reader, reader.uint32()); break; + case 7: + message.priceUpdate = StreamPriceUpdate.decode(reader, reader.uint32()); + break; + default: reader.skipType(tag & 7); break; @@ -1488,6 +1528,7 @@ export const StreamUpdate = { message.orderFill = object.orderFill !== undefined && object.orderFill !== null ? StreamOrderbookFill.fromPartial(object.orderFill) : undefined; message.takerOrder = object.takerOrder !== undefined && object.takerOrder !== null ? StreamTakerOrder.fromPartial(object.takerOrder) : undefined; message.subaccountUpdate = object.subaccountUpdate !== undefined && object.subaccountUpdate !== null ? StreamSubaccountUpdate.fromPartial(object.subaccountUpdate) : undefined; + message.priceUpdate = object.priceUpdate !== undefined && object.priceUpdate !== null ? StreamPriceUpdate.fromPartial(object.priceUpdate) : undefined; return message; } diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/streaming.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/streaming.ts index 1600c2e39c..d0ad4cd6ed 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/streaming.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/streaming.ts @@ -1,5 +1,6 @@ import { StreamOrderbookFill, StreamOrderbookFillSDKType, StreamOrderbookUpdate, StreamOrderbookUpdateSDKType } from "./query"; import { StreamSubaccountUpdate, StreamSubaccountUpdateSDKType } from "../subaccounts/streaming"; +import { StreamPriceUpdate, StreamPriceUpdateSDKType } from "../prices/streaming"; import * as _m0 from "protobufjs/minimal"; import { DeepPartial } from "../../helpers"; /** StagedFinalizeBlockEvent is an event staged during `FinalizeBlock`. */ @@ -8,6 +9,7 @@ export interface StagedFinalizeBlockEvent { orderFill?: StreamOrderbookFill; subaccountUpdate?: StreamSubaccountUpdate; orderbookUpdate?: StreamOrderbookUpdate; + priceUpdate?: StreamPriceUpdate; } /** StagedFinalizeBlockEvent is an event staged during `FinalizeBlock`. */ @@ -15,13 +17,15 @@ export interface StagedFinalizeBlockEventSDKType { order_fill?: StreamOrderbookFillSDKType; subaccount_update?: StreamSubaccountUpdateSDKType; orderbook_update?: StreamOrderbookUpdateSDKType; + price_update?: StreamPriceUpdateSDKType; } function createBaseStagedFinalizeBlockEvent(): StagedFinalizeBlockEvent { return { orderFill: undefined, subaccountUpdate: undefined, - orderbookUpdate: undefined + orderbookUpdate: undefined, + priceUpdate: undefined }; } @@ -39,6 +43,10 @@ export const StagedFinalizeBlockEvent = { StreamOrderbookUpdate.encode(message.orderbookUpdate, writer.uint32(26).fork()).ldelim(); } + if (message.priceUpdate !== undefined) { + StreamPriceUpdate.encode(message.priceUpdate, writer.uint32(34).fork()).ldelim(); + } + return writer; }, @@ -63,6 +71,10 @@ export const StagedFinalizeBlockEvent = { message.orderbookUpdate = StreamOrderbookUpdate.decode(reader, reader.uint32()); break; + case 4: + message.priceUpdate = StreamPriceUpdate.decode(reader, reader.uint32()); + break; + default: reader.skipType(tag & 7); break; @@ -77,6 +89,7 @@ export const StagedFinalizeBlockEvent = { message.orderFill = object.orderFill !== undefined && object.orderFill !== null ? StreamOrderbookFill.fromPartial(object.orderFill) : undefined; message.subaccountUpdate = object.subaccountUpdate !== undefined && object.subaccountUpdate !== null ? StreamSubaccountUpdate.fromPartial(object.subaccountUpdate) : undefined; message.orderbookUpdate = object.orderbookUpdate !== undefined && object.orderbookUpdate !== null ? StreamOrderbookUpdate.fromPartial(object.orderbookUpdate) : undefined; + message.priceUpdate = object.priceUpdate !== undefined && object.priceUpdate !== null ? StreamPriceUpdate.fromPartial(object.priceUpdate) : undefined; return message; } diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/tx.rpc.msg.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/tx.rpc.msg.ts index 170cf4f3bf..61a0bdf54b 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/tx.rpc.msg.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/tx.rpc.msg.ts @@ -1,6 +1,6 @@ import { Rpc } from "../../helpers"; import * as _m0 from "protobufjs/minimal"; -import { MsgSetMarketsHardCap, MsgSetMarketsHardCapResponse, MsgCreateMarketPermissionless, MsgCreateMarketPermissionlessResponse, MsgSetListingVaultDepositParams, MsgSetListingVaultDepositParamsResponse } from "./tx"; +import { MsgSetMarketsHardCap, MsgSetMarketsHardCapResponse, MsgCreateMarketPermissionless, MsgCreateMarketPermissionlessResponse, MsgSetListingVaultDepositParams, MsgSetListingVaultDepositParamsResponse, MsgUpgradeIsolatedPerpetualToCross, MsgUpgradeIsolatedPerpetualToCrossResponse } from "./tx"; /** Msg defines the Msg service. */ export interface Msg { @@ -12,6 +12,12 @@ export interface Msg { /** SetListingVaultDepositParams sets PML megavault deposit params */ setListingVaultDepositParams(request: MsgSetListingVaultDepositParams): Promise; + /** + * UpgradeIsolatedPerpetualToCross upgrades a perpetual from isolated to cross + * margin + */ + + upgradeIsolatedPerpetualToCross(request: MsgUpgradeIsolatedPerpetualToCross): Promise; } export class MsgClientImpl implements Msg { private readonly rpc: Rpc; @@ -21,6 +27,7 @@ export class MsgClientImpl implements Msg { this.setMarketsHardCap = this.setMarketsHardCap.bind(this); this.createMarketPermissionless = this.createMarketPermissionless.bind(this); this.setListingVaultDepositParams = this.setListingVaultDepositParams.bind(this); + this.upgradeIsolatedPerpetualToCross = this.upgradeIsolatedPerpetualToCross.bind(this); } setMarketsHardCap(request: MsgSetMarketsHardCap): Promise { @@ -41,4 +48,10 @@ export class MsgClientImpl implements Msg { return promise.then(data => MsgSetListingVaultDepositParamsResponse.decode(new _m0.Reader(data))); } + upgradeIsolatedPerpetualToCross(request: MsgUpgradeIsolatedPerpetualToCross): Promise { + const data = MsgUpgradeIsolatedPerpetualToCross.encode(request).finish(); + const promise = this.rpc.request("dydxprotocol.listing.Msg", "UpgradeIsolatedPerpetualToCross", data); + return promise.then(data => MsgUpgradeIsolatedPerpetualToCrossResponse.decode(new _m0.Reader(data))); + } + } \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/tx.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/tx.ts index 7e8d14a123..111d29fc37 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/tx.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/listing/tx.ts @@ -100,6 +100,40 @@ export interface MsgSetListingVaultDepositParamsResponse {} */ export interface MsgSetListingVaultDepositParamsResponseSDKType {} +/** + * MsgUpgradeIsolatedPerpetualToCross is used to upgrade a market from + * isolated margin to cross margin. + */ + +export interface MsgUpgradeIsolatedPerpetualToCross { + authority: string; + /** ID of the perpetual to be upgraded to CROSS */ + + perpetualId: number; +} +/** + * MsgUpgradeIsolatedPerpetualToCross is used to upgrade a market from + * isolated margin to cross margin. + */ + +export interface MsgUpgradeIsolatedPerpetualToCrossSDKType { + authority: string; + /** ID of the perpetual to be upgraded to CROSS */ + + perpetual_id: number; +} +/** + * MsgUpgradeIsolatedPerpetualToCrossResponse defines the + * UpgradeIsolatedPerpetualToCross response type. + */ + +export interface MsgUpgradeIsolatedPerpetualToCrossResponse {} +/** + * MsgUpgradeIsolatedPerpetualToCrossResponse defines the + * UpgradeIsolatedPerpetualToCross response type. + */ + +export interface MsgUpgradeIsolatedPerpetualToCrossResponseSDKType {} function createBaseMsgSetMarketsHardCap(): MsgSetMarketsHardCap { return { @@ -366,4 +400,93 @@ export const MsgSetListingVaultDepositParamsResponse = { return message; } +}; + +function createBaseMsgUpgradeIsolatedPerpetualToCross(): MsgUpgradeIsolatedPerpetualToCross { + return { + authority: "", + perpetualId: 0 + }; +} + +export const MsgUpgradeIsolatedPerpetualToCross = { + encode(message: MsgUpgradeIsolatedPerpetualToCross, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.authority !== "") { + writer.uint32(10).string(message.authority); + } + + if (message.perpetualId !== 0) { + writer.uint32(16).uint32(message.perpetualId); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): MsgUpgradeIsolatedPerpetualToCross { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseMsgUpgradeIsolatedPerpetualToCross(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.authority = reader.string(); + break; + + case 2: + message.perpetualId = reader.uint32(); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): MsgUpgradeIsolatedPerpetualToCross { + const message = createBaseMsgUpgradeIsolatedPerpetualToCross(); + message.authority = object.authority ?? ""; + message.perpetualId = object.perpetualId ?? 0; + return message; + } + +}; + +function createBaseMsgUpgradeIsolatedPerpetualToCrossResponse(): MsgUpgradeIsolatedPerpetualToCrossResponse { + return {}; +} + +export const MsgUpgradeIsolatedPerpetualToCrossResponse = { + encode(_: MsgUpgradeIsolatedPerpetualToCrossResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): MsgUpgradeIsolatedPerpetualToCrossResponse { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseMsgUpgradeIsolatedPerpetualToCrossResponse(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(_: DeepPartial): MsgUpgradeIsolatedPerpetualToCrossResponse { + const message = createBaseMsgUpgradeIsolatedPerpetualToCrossResponse(); + return message; + } + }; \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/streaming.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/streaming.ts new file mode 100644 index 0000000000..185fe8dc4f --- /dev/null +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/prices/streaming.ts @@ -0,0 +1,92 @@ +import { MarketPrice, MarketPriceSDKType } from "./market_price"; +import * as _m0 from "protobufjs/minimal"; +import { DeepPartial } from "../../helpers"; +/** StreamPriceUpdate provides information on a price update. */ + +export interface StreamPriceUpdate { + /** The `Id` of the `Market`. */ + marketId: number; + /** The updated price. */ + + price?: MarketPrice; + /** Snapshot indicates if the response is from a snapshot of the price. */ + + snapshot: boolean; +} +/** StreamPriceUpdate provides information on a price update. */ + +export interface StreamPriceUpdateSDKType { + /** The `Id` of the `Market`. */ + market_id: number; + /** The updated price. */ + + price?: MarketPriceSDKType; + /** Snapshot indicates if the response is from a snapshot of the price. */ + + snapshot: boolean; +} + +function createBaseStreamPriceUpdate(): StreamPriceUpdate { + return { + marketId: 0, + price: undefined, + snapshot: false + }; +} + +export const StreamPriceUpdate = { + encode(message: StreamPriceUpdate, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.marketId !== 0) { + writer.uint32(8).uint32(message.marketId); + } + + if (message.price !== undefined) { + MarketPrice.encode(message.price, writer.uint32(18).fork()).ldelim(); + } + + if (message.snapshot === true) { + writer.uint32(24).bool(message.snapshot); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): StreamPriceUpdate { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseStreamPriceUpdate(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.marketId = reader.uint32(); + break; + + case 2: + message.price = MarketPrice.decode(reader, reader.uint32()); + break; + + case 3: + message.snapshot = reader.bool(); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): StreamPriceUpdate { + const message = createBaseStreamPriceUpdate(); + message.marketId = object.marketId ?? 0; + message.price = object.price !== undefined && object.price !== null ? MarketPrice.fromPartial(object.price) : undefined; + message.snapshot = object.snapshot ?? false; + return message; + } + +}; \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/gogoproto/bundle.ts b/indexer/packages/v4-protos/src/codegen/gogoproto/bundle.ts index 675007986c..7268721d90 100644 --- a/indexer/packages/v4-protos/src/codegen/gogoproto/bundle.ts +++ b/indexer/packages/v4-protos/src/codegen/gogoproto/bundle.ts @@ -1,3 +1,3 @@ -import * as _129 from "./gogo"; -export const gogoproto = { ..._129 +import * as _130 from "./gogo"; +export const gogoproto = { ..._130 }; \ No newline at end of file diff --git a/indexer/packages/v4-protos/src/codegen/google/bundle.ts b/indexer/packages/v4-protos/src/codegen/google/bundle.ts index 4617ba1a6e..c730dc4e52 100644 --- a/indexer/packages/v4-protos/src/codegen/google/bundle.ts +++ b/indexer/packages/v4-protos/src/codegen/google/bundle.ts @@ -1,16 +1,16 @@ -import * as _130 from "./api/annotations"; -import * as _131 from "./api/http"; -import * as _132 from "./protobuf/descriptor"; -import * as _133 from "./protobuf/duration"; -import * as _134 from "./protobuf/timestamp"; -import * as _135 from "./protobuf/any"; +import * as _131 from "./api/annotations"; +import * as _132 from "./api/http"; +import * as _133 from "./protobuf/descriptor"; +import * as _134 from "./protobuf/duration"; +import * as _135 from "./protobuf/timestamp"; +import * as _136 from "./protobuf/any"; export namespace google { - export const api = { ..._130, - ..._131 + export const api = { ..._131, + ..._132 }; - export const protobuf = { ..._132, - ..._133, + export const protobuf = { ..._133, ..._134, - ..._135 + ..._135, + ..._136 }; } \ No newline at end of file diff --git a/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts b/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts index 26304550fd..5d8a1ef709 100644 --- a/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts +++ b/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts @@ -16,6 +16,7 @@ import { MEGAVAULT_MODULE_ADDRESS, MEGAVAULT_SUBACCOUNT_ID, TransferTable, + VaultPnlTicksView, } from '@dydxprotocol-indexer/postgres'; import { RequestMethod, VaultHistoricalPnl } from '../../../../src/types'; import request from 'supertest'; @@ -127,20 +128,13 @@ describe('vault-controller#V4', () => { afterEach(async () => { await dbHelpers.clearData(); + await VaultPnlTicksView.refreshDailyView(); + await VaultPnlTicksView.refreshHourlyView(); config.VAULT_PNL_HISTORY_HOURS = vaultPnlHistoryHoursPrev; config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS = vaultPnlLastPnlWindowPrev; config.VAULT_PNL_START_DATE = vaultPnlStartDatePrev; }); - it('Get /megavault/historicalPnl with no vault subaccounts', async () => { - const response: request.Response = await sendRequest({ - type: RequestMethod.GET, - path: '/v4/vault/v1/megavault/historicalPnl', - }); - - expect(response.body.megavaultPnl).toEqual([]); - }); - it.each([ ['no resolution', '', [1, 2], 4, undefined], ['daily resolution', '?resolution=day', [1, 2], 4, undefined], @@ -652,6 +646,8 @@ describe('vault-controller#V4', () => { ]); createdTicks.push(...mainSubaccountTicks); } + await VaultPnlTicksView.refreshDailyView(); + await VaultPnlTicksView.refreshHourlyView(); return createdTicks; } diff --git a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts index dbc4043ab8..bd2c489478 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -29,6 +29,7 @@ import { TransferTable, TransferColumns, Ordering, + VaultPnlTicksView, } from '@dydxprotocol-indexer/postgres'; import Big from 'big.js'; import bounds from 'binary-searching'; @@ -343,10 +344,9 @@ async function getVaultSubaccountPnlTicks( PnlTicksFromDatabase[], PnlTicksFromDatabase[], ] = await Promise.all([ - PnlTicksTable.getPnlTicksAtIntervals( + VaultPnlTicksView.getVaultsPnl( resolution, windowSeconds, - vaultSubaccountIds, getVautlPnlStartDate(), ), PnlTicksTable.getLatestPnlTick( @@ -559,10 +559,9 @@ export async function getLatestPnlTick( PnlTicksFromDatabase[], PnlTicksFromDatabase[], ] = await Promise.all([ - PnlTicksTable.getPnlTicksAtIntervals( + VaultPnlTicksView.getVaultsPnl( PnlTickInterval.hour, config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS * 60 * 60, - vaultSubaccountIds, getVautlPnlStartDate(), ), PnlTicksTable.getLatestPnlTick( diff --git a/indexer/services/ender/__tests__/handlers/order-fills/liquidation-handler.test.ts b/indexer/services/ender/__tests__/handlers/order-fills/liquidation-handler.test.ts index 805ca676f0..a5cc41f3d6 100644 --- a/indexer/services/ender/__tests__/handlers/order-fills/liquidation-handler.test.ts +++ b/indexer/services/ender/__tests__/handlers/order-fills/liquidation-handler.test.ts @@ -137,7 +137,7 @@ describe('LiquidationHandler', () => { perpetualId: testConstants.defaultPerpetualMarket.id, side: PositionSide.LONG, status: PerpetualPositionStatus.OPEN, - size: '5', + size: '10', maxSize: '25', sumOpen: '10', entryPrice: '15000', @@ -392,7 +392,7 @@ describe('LiquidationHandler', () => { defaultPerpetualPosition.openEventId, ), { - sumOpen: Big(defaultPerpetualPosition.sumOpen!).plus(totalFilled).toFixed(), + sumOpen: Big(defaultPerpetualPosition.size).plus(totalFilled).toFixed(), entryPrice: getWeightedAverage( defaultPerpetualPosition.entryPrice!, defaultPerpetualPosition.size, diff --git a/indexer/services/ender/__tests__/handlers/order-fills/order-handler.test.ts b/indexer/services/ender/__tests__/handlers/order-fills/order-handler.test.ts index 65cb1c0422..ba9a62ab34 100644 --- a/indexer/services/ender/__tests__/handlers/order-fills/order-handler.test.ts +++ b/indexer/services/ender/__tests__/handlers/order-fills/order-handler.test.ts @@ -138,7 +138,7 @@ describe('OrderHandler', () => { perpetualId: testConstants.defaultPerpetualMarket.id, side: PositionSide.LONG, status: PerpetualPositionStatus.OPEN, - size: '5', + size: '10', maxSize: '25', sumOpen: '10', entryPrice: '15000', @@ -212,7 +212,6 @@ describe('OrderHandler', () => { { goodTilBlock: 15, }, - false, ], [ 'goodTilBlockTime', @@ -222,17 +221,6 @@ describe('OrderHandler', () => { { goodTilBlockTime: 1_000_005_000, }, - false, - ], - [ - 'goodTilBlock', - { - goodTilBlock: 10, - }, - { - goodTilBlock: 15, - }, - true, ], ])( 'creates fills and orders (with %s), sends vulcan messages for order updates and order ' + @@ -241,7 +229,6 @@ describe('OrderHandler', () => { _name: string, makerGoodTilOneof: Partial, takerGoodTilOneof: Partial, - useNegativeSize: boolean, ) => { const transactionIndex: number = 0; const eventIndex: number = 0; @@ -297,10 +284,7 @@ describe('OrderHandler', () => { // create PerpetualPositions await Promise.all([ - PerpetualPositionTable.create({ - ...defaultPerpetualPosition, - size: useNegativeSize ? '-5' : defaultPerpetualPosition.size, - }), + PerpetualPositionTable.create(defaultPerpetualPosition), PerpetualPositionTable.create({ ...defaultPerpetualPosition, subaccountId: testConstants.defaultSubaccountId2, @@ -455,7 +439,7 @@ describe('OrderHandler', () => { defaultPerpetualPosition.openEventId, ), { - sumOpen: Big(defaultPerpetualPosition.sumOpen!).plus(totalFilled).toFixed(), + sumOpen: Big(defaultPerpetualPosition.size).plus(totalFilled).toFixed(), entryPrice: getWeightedAverage( defaultPerpetualPosition.entryPrice!, defaultPerpetualPosition.size, diff --git a/indexer/services/ender/src/scripts/helpers/dydx_liquidation_fill_handler_per_order.sql b/indexer/services/ender/src/scripts/helpers/dydx_liquidation_fill_handler_per_order.sql index dc3dfa5e4c..493b1257d6 100644 --- a/indexer/services/ender/src/scripts/helpers/dydx_liquidation_fill_handler_per_order.sql +++ b/indexer/services/ender/src/scripts/helpers/dydx_liquidation_fill_handler_per_order.sql @@ -200,7 +200,7 @@ BEGIN perpetual_position_record."side", order_side) THEN sum_open = dydx_trim_scale(perpetual_position_record."sumOpen" + fill_amount); entry_price = dydx_get_weighted_average( - perpetual_position_record."entryPrice", ABS(perpetual_position_record."size"), + perpetual_position_record."entryPrice", perpetual_position_record."sumOpen", maker_price, fill_amount); perpetual_position_record."sumOpen" = sum_open; perpetual_position_record."entryPrice" = entry_price; diff --git a/indexer/services/ender/src/scripts/helpers/dydx_update_perpetual_position_aggregate_fields.sql b/indexer/services/ender/src/scripts/helpers/dydx_update_perpetual_position_aggregate_fields.sql index f6e269a0b1..d021eecf28 100644 --- a/indexer/services/ender/src/scripts/helpers/dydx_update_perpetual_position_aggregate_fields.sql +++ b/indexer/services/ender/src/scripts/helpers/dydx_update_perpetual_position_aggregate_fields.sql @@ -44,7 +44,7 @@ BEGIN IF dydx_perpetual_position_and_order_side_matching(perpetual_position_record."side", side) THEN sum_open := dydx_trim_scale(perpetual_position_record."sumOpen" + size); entry_price := dydx_get_weighted_average( - perpetual_position_record."entryPrice", ABS(perpetual_position_record."size"), price, size + perpetual_position_record."entryPrice", perpetual_position_record."sumOpen", price, size ); perpetual_position_record."sumOpen" = sum_open; perpetual_position_record."entryPrice" = entry_price; diff --git a/indexer/services/roundtable/__tests__/tasks/refresh-vault-pnl.test.ts b/indexer/services/roundtable/__tests__/tasks/refresh-vault-pnl.test.ts new file mode 100644 index 0000000000..0078dbb74a --- /dev/null +++ b/indexer/services/roundtable/__tests__/tasks/refresh-vault-pnl.test.ts @@ -0,0 +1,130 @@ +import config from '../../src/config'; +import refreshVaulPnlTask from '../../src/tasks/refresh-vault-pnl'; +import { Settings, DateTime } from 'luxon'; +import { + BlockTable, + PnlTickInterval, + PnlTicksFromDatabase, + PnlTicksTable, + VaultPnlTicksView, + VaultTable, + dbHelpers, + testConstants, + testMocks, +} from '@dydxprotocol-indexer/postgres'; + +jest.mock('../../src/helpers/aws'); + +describe('refresh-vault-pnl', () => { + const currentTime: DateTime = DateTime.utc(); + + beforeAll(async () => { + await dbHelpers.migrate(); + await dbHelpers.clearData(); + }); + + beforeEach(async () => { + await testMocks.seedData(); + await Promise.all([ + VaultTable.create({ + ...testConstants.defaultVault, + address: testConstants.defaultSubaccount.address, + }), + ]); + }); + + afterAll(async () => { + await dbHelpers.teardown(); + jest.resetAllMocks(); + }); + + afterEach(async () => { + await dbHelpers.clearData(); + await VaultPnlTicksView.refreshDailyView(); + await VaultPnlTicksView.refreshHourlyView(); + jest.clearAllMocks(); + Settings.now = () => new Date().valueOf(); + }); + + it('refreshes hourly view if within time window of an hour', async () => { + Settings.now = () => currentTime.startOf('hour').plus( + { milliseconds: config.TIME_WINDOW_FOR_REFRESH_VAULT_PNL_MS - 1 }, + ).valueOf(); + const pnlTick: PnlTicksFromDatabase = await setupPnlTick(); + await refreshVaulPnlTask(); + + const pnlTicks: PnlTicksFromDatabase[] = await VaultPnlTicksView.getVaultsPnl( + PnlTickInterval.hour, + 86400, + currentTime.minus({ day: 1 }), + ); + expect(pnlTicks).toEqual([pnlTick]); + }); + + it('refreshes daily view if within time window of a day', async () => { + Settings.now = () => currentTime.startOf('day').plus( + { milliseconds: config.TIME_WINDOW_FOR_REFRESH_VAULT_PNL_MS - 1 }, + ).valueOf(); + const pnlTick: PnlTicksFromDatabase = await setupPnlTick(); + await refreshVaulPnlTask(); + + const pnlTicks: PnlTicksFromDatabase[] = await VaultPnlTicksView.getVaultsPnl( + PnlTickInterval.day, + 608400, + currentTime.minus({ day: 7 }), + ); + expect(pnlTicks).toEqual([pnlTick]); + }); + + it('does not refresh hourly view if outside of time window of an hour', async () => { + Settings.now = () => currentTime.startOf('hour').plus( + { milliseconds: config.TIME_WINDOW_FOR_REFRESH_VAULT_PNL_MS + 1 }, + ).valueOf(); + await setupPnlTick(); + await refreshVaulPnlTask(); + + const pnlTicks: PnlTicksFromDatabase[] = await VaultPnlTicksView.getVaultsPnl( + PnlTickInterval.hour, + 86400, + currentTime.minus({ day: 1 }), + ); + expect(pnlTicks).toEqual([]); + }); + + it('does not refresh daily view if outside time window of a day', async () => { + Settings.now = () => currentTime.startOf('day').plus( + { milliseconds: config.TIME_WINDOW_FOR_REFRESH_VAULT_PNL_MS + 1 }, + ).valueOf(); + await setupPnlTick(); + await refreshVaulPnlTask(); + + const pnlTicks: PnlTicksFromDatabase[] = await VaultPnlTicksView.getVaultsPnl( + PnlTickInterval.day, + 608400, + currentTime.minus({ day: 7 }), + ); + expect(pnlTicks).toEqual([]); + }); + + async function setupPnlTick(): Promise { + const twoHoursAgo: string = currentTime.minus({ hour: 2 }).toISO(); + await Promise.all([ + BlockTable.create({ + blockHeight: '6', + time: twoHoursAgo, + }), + ]); + const createdTick: PnlTicksFromDatabase = await PnlTicksTable.create( + { + subaccountId: testConstants.defaultSubaccountId, + equity: '1080', + createdAt: twoHoursAgo, + totalPnl: '1180', + netTransfers: '50', + blockHeight: '6', + blockTime: twoHoursAgo, + }, + ); + return createdTick; + } +}); diff --git a/indexer/services/roundtable/src/config.ts b/indexer/services/roundtable/src/config.ts index 6d7efbaca6..3d03fd0e19 100644 --- a/indexer/services/roundtable/src/config.ts +++ b/indexer/services/roundtable/src/config.ts @@ -60,6 +60,7 @@ export const configSchema = { LOOPS_ENABLED_UPDATE_WALLET_TOTAL_VOLUME: parseBoolean({ default: true }), LOOPS_ENABLED_UPDATE_AFFILIATE_INFO: parseBoolean({ default: true }), LOOPS_ENABLED_DELETE_OLD_FIREBASE_NOTIFICATION_TOKENS: parseBoolean({ default: true }), + LOOPS_ENABLED_REFRESH_VAULT_PNL: parseBoolean({ default: true }), // Loop Timing LOOPS_INTERVAL_MS_MARKET_UPDATER: parseInteger({ @@ -140,6 +141,9 @@ export const configSchema = { LOOPS_INTERVAL_MS_CACHE_ORDERBOOK_MID_PRICES: parseInteger({ default: ONE_SECOND_IN_MILLISECONDS, }), + LOOPS_INTERVAL_MS_REFRESH_VAULT_PNL: parseInteger({ + default: 5 * ONE_MINUTE_IN_MILLISECONDS, + }), // Start delay START_DELAY_ENABLED: parseBoolean({ default: true }), @@ -215,6 +219,9 @@ export const configSchema = { SUBACCOUNT_USERNAME_BATCH_SIZE: parseInteger({ default: 2000 }), // number of attempts to generate username for a subaccount ATTEMPT_PER_SUBACCOUNT: parseInteger({ default: 3 }), + + // Refresh vault pnl view + TIME_WINDOW_FOR_REFRESH_VAULT_PNL_MS: parseInteger({ default: 15 * ONE_MINUTE_IN_MILLISECONDS }), }; export default parseSchema(configSchema); diff --git a/indexer/services/roundtable/src/index.ts b/indexer/services/roundtable/src/index.ts index 22f1697e67..5a2db7c728 100644 --- a/indexer/services/roundtable/src/index.ts +++ b/indexer/services/roundtable/src/index.ts @@ -20,6 +20,7 @@ import marketUpdaterTask from './tasks/market-updater'; import orderbookInstrumentationTask from './tasks/orderbook-instrumentation'; import performComplianceStatusTransitionsTask from './tasks/perform-compliance-status-transitions'; import pnlInstrumentationTask from './tasks/pnl-instrumentation'; +import refreshVaultPnlTask from './tasks/refresh-vault-pnl'; import removeExpiredOrdersTask from './tasks/remove-expired-orders'; import removeOldOrderUpdatesTask from './tasks/remove-old-order-updates'; import subaccountUsernameGeneratorTask from './tasks/subaccount-username-generator'; @@ -272,6 +273,13 @@ async function start(): Promise { config.LOOPS_INTERVAL_MS_DELETE_FIREBASE_NOTIFICATION_TOKENS_MONTHLY, ); } + if (config.LOOPS_ENABLED_REFRESH_VAULT_PNL) { + startLoop( + refreshVaultPnlTask, + 'refresh-vault-pnl', + config.LOOPS_INTERVAL_MS_REFRESH_VAULT_PNL, + ); + } logger.info({ at: 'index', diff --git a/indexer/services/roundtable/src/tasks/refresh-vault-pnl.ts b/indexer/services/roundtable/src/tasks/refresh-vault-pnl.ts new file mode 100644 index 0000000000..635ef5526f --- /dev/null +++ b/indexer/services/roundtable/src/tasks/refresh-vault-pnl.ts @@ -0,0 +1,53 @@ +import { logger, stats } from '@dydxprotocol-indexer/base'; +import { + VaultPnlTicksView, +} from '@dydxprotocol-indexer/postgres'; +import { DateTime } from 'luxon'; + +import config from '../config'; + +/** + * Refresh the vault pnl ticks views. + */ +export default async function runTask(): Promise { + const taskStart: number = Date.now(); + try { + const currentTime: DateTime = DateTime.utc(); + if (currentTime.diff( + currentTime.startOf('hour'), + ).toMillis() < config.TIME_WINDOW_FOR_REFRESH_VAULT_PNL_MS) { + logger.info({ + at: 'refresh-vault-pnl#runTask', + message: 'Refreshing vault hourly pnl view', + currentTime, + }); + await VaultPnlTicksView.refreshHourlyView(); + stats.timing( + `${config.SERVICE_NAME}.refresh-vault-pnl.hourly-view.timing`, + Date.now() - taskStart, + ); + } + + if (currentTime.diff( + currentTime.startOf('day'), + ).toMillis() < config.TIME_WINDOW_FOR_REFRESH_VAULT_PNL_MS) { + const refreshDailyStart: number = Date.now(); + logger.info({ + at: 'refresh-vault-pnl#runTask', + message: 'Refreshing vault daily pnl view', + currentTime, + }); + await VaultPnlTicksView.refreshDailyView(); + stats.timing( + `${config.SERVICE_NAME}.refresh-vault-pnl.daily-view.timing`, + Date.now() - refreshDailyStart, + ); + } + } catch (error) { + logger.error({ + at: 'refresh-vault-pnl#runTask', + message: 'Failed to refresh vault pnl views', + error, + }); + } +} diff --git a/proto/dydxprotocol/clob/query.proto b/proto/dydxprotocol/clob/query.proto index 62dd1995a8..5584a1e950 100644 --- a/proto/dydxprotocol/clob/query.proto +++ b/proto/dydxprotocol/clob/query.proto @@ -14,6 +14,7 @@ import "dydxprotocol/clob/mev.proto"; import "dydxprotocol/indexer/off_chain_updates/off_chain_updates.proto"; import "dydxprotocol/subaccounts/streaming.proto"; import "dydxprotocol/subaccounts/subaccount.proto"; +import "dydxprotocol/prices/streaming.proto"; option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/clob/types"; @@ -182,6 +183,9 @@ message StreamOrderbookUpdatesRequest { // Subaccount ids to stream subaccount updates for. repeated dydxprotocol.subaccounts.SubaccountId subaccount_ids = 2; + + // Market ids for price updates. + repeated uint32 market_ids = 3; } // StreamOrderbookUpdatesResponse is a response message for the @@ -207,6 +211,7 @@ message StreamUpdate { StreamOrderbookFill order_fill = 4; StreamTakerOrder taker_order = 5; dydxprotocol.subaccounts.StreamSubaccountUpdate subaccount_update = 6; + dydxprotocol.prices.StreamPriceUpdate price_update = 7; } } diff --git a/proto/dydxprotocol/clob/streaming.proto b/proto/dydxprotocol/clob/streaming.proto index ae3811134e..ad4ce7cc24 100644 --- a/proto/dydxprotocol/clob/streaming.proto +++ b/proto/dydxprotocol/clob/streaming.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package dydxprotocol.clob; import "dydxprotocol/subaccounts/streaming.proto"; +import "dydxprotocol/prices/streaming.proto"; import "dydxprotocol/clob/query.proto"; option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/clob/types"; @@ -13,5 +14,6 @@ message StagedFinalizeBlockEvent { StreamOrderbookFill order_fill = 1; dydxprotocol.subaccounts.StreamSubaccountUpdate subaccount_update = 2; StreamOrderbookUpdate orderbook_update = 3; + dydxprotocol.prices.StreamPriceUpdate price_update = 4; } } diff --git a/proto/dydxprotocol/listing/tx.proto b/proto/dydxprotocol/listing/tx.proto index 8f0808de9e..aa7d998452 100644 --- a/proto/dydxprotocol/listing/tx.proto +++ b/proto/dydxprotocol/listing/tx.proto @@ -22,6 +22,11 @@ service Msg { // SetListingVaultDepositParams sets PML megavault deposit params rpc SetListingVaultDepositParams(MsgSetListingVaultDepositParams) returns (MsgSetListingVaultDepositParamsResponse); + + // UpgradeIsolatedPerpetualToCross upgrades a perpetual from isolated to cross + // margin + rpc UpgradeIsolatedPerpetualToCross(MsgUpgradeIsolatedPerpetualToCross) + returns (MsgUpgradeIsolatedPerpetualToCrossResponse); } // MsgSetMarketsHardCap is used to set a hard cap on the number of markets @@ -69,4 +74,20 @@ message MsgSetListingVaultDepositParams { // MsgSetListingVaultDepositParamsResponse defines the // MsgSetListingVaultDepositParams response -message MsgSetListingVaultDepositParamsResponse {} \ No newline at end of file +message MsgSetListingVaultDepositParamsResponse {} + +// MsgUpgradeIsolatedPerpetualToCross is used to upgrade a market from +// isolated margin to cross margin. +message MsgUpgradeIsolatedPerpetualToCross { + // Authority is the address that controls the module. + option (cosmos.msg.v1.signer) = "authority"; + + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // ID of the perpetual to be upgraded to CROSS + uint32 perpetual_id = 2; +} + +// MsgUpgradeIsolatedPerpetualToCrossResponse defines the +// UpgradeIsolatedPerpetualToCross response type. +message MsgUpgradeIsolatedPerpetualToCrossResponse {} diff --git a/proto/dydxprotocol/prices/streaming.proto b/proto/dydxprotocol/prices/streaming.proto new file mode 100644 index 0000000000..fb5d44c1fe --- /dev/null +++ b/proto/dydxprotocol/prices/streaming.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package dydxprotocol.prices; + +import "gogoproto/gogo.proto"; +import "dydxprotocol/prices/market_price.proto"; + +option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/prices/types"; + +// StreamPriceUpdate provides information on a price update. +message StreamPriceUpdate { + // The `Id` of the `Market`. + uint32 market_id = 1; + + // The updated price. + MarketPrice price = 2 [ (gogoproto.nullable) = false ]; + + // Snapshot indicates if the response is from a snapshot of the price. + bool snapshot = 3; +} \ No newline at end of file diff --git a/protocol/app/app.go b/protocol/app/app.go index 89a10ce846..042bac91ea 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -1242,6 +1242,7 @@ func New( app.ClobKeeper, &app.MarketMapKeeper, app.PerpetualsKeeper, + app.SubaccountsKeeper, app.VaultKeeper, ) listingModule := listingmodule.NewAppModule( diff --git a/protocol/app/flags/flags.go b/protocol/app/flags/flags.go index b166f88352..1a0ad084e1 100644 --- a/protocol/app/flags/flags.go +++ b/protocol/app/flags/flags.go @@ -80,7 +80,7 @@ const ( DefaultVEOracleEnabled = true - DefaultOptimisticExecutionEnabled = false + DefaultOptimisticExecutionEnabled = true DefaultOptimisticExecutionTestAbortRate = 0 ) diff --git a/protocol/app/msgs/all_msgs.go b/protocol/app/msgs/all_msgs.go index 2369ef1056..9a6e072df0 100644 --- a/protocol/app/msgs/all_msgs.go +++ b/protocol/app/msgs/all_msgs.go @@ -228,12 +228,14 @@ var ( "/dydxprotocol.govplus.MsgSlashValidatorResponse": {}, // listing - "/dydxprotocol.listing.MsgSetMarketsHardCap": {}, - "/dydxprotocol.listing.MsgSetMarketsHardCapResponse": {}, - "/dydxprotocol.listing.MsgCreateMarketPermissionless": {}, - "/dydxprotocol.listing.MsgCreateMarketPermissionlessResponse": {}, - "/dydxprotocol.listing.MsgSetListingVaultDepositParams": {}, - "/dydxprotocol.listing.MsgSetListingVaultDepositParamsResponse": {}, + "/dydxprotocol.listing.MsgSetMarketsHardCap": {}, + "/dydxprotocol.listing.MsgSetMarketsHardCapResponse": {}, + "/dydxprotocol.listing.MsgCreateMarketPermissionless": {}, + "/dydxprotocol.listing.MsgCreateMarketPermissionlessResponse": {}, + "/dydxprotocol.listing.MsgSetListingVaultDepositParams": {}, + "/dydxprotocol.listing.MsgSetListingVaultDepositParamsResponse": {}, + "/dydxprotocol.listing.MsgUpgradeIsolatedPerpetualToCross": {}, + "/dydxprotocol.listing.MsgUpgradeIsolatedPerpetualToCrossResponse": {}, // perpetuals "/dydxprotocol.perpetuals.MsgAddPremiumVotes": {}, diff --git a/protocol/app/msgs/internal_msgs.go b/protocol/app/msgs/internal_msgs.go index 9c0e58f9f6..8587ff5e4c 100644 --- a/protocol/app/msgs/internal_msgs.go +++ b/protocol/app/msgs/internal_msgs.go @@ -156,10 +156,12 @@ var ( "/dydxprotocol.govplus.MsgSlashValidatorResponse": nil, // listing - "/dydxprotocol.listing.MsgSetMarketsHardCap": &listing.MsgSetMarketsHardCap{}, - "/dydxprotocol.listing.MsgSetMarketsHardCapResponse": nil, - "/dydxprotocol.listing.MsgSetListingVaultDepositParams": &listing.MsgSetListingVaultDepositParams{}, - "/dydxprotocol.listing.MsgSetListingVaultDepositParamsResponse": nil, + "/dydxprotocol.listing.MsgSetMarketsHardCap": &listing.MsgSetMarketsHardCap{}, + "/dydxprotocol.listing.MsgSetMarketsHardCapResponse": nil, + "/dydxprotocol.listing.MsgSetListingVaultDepositParams": &listing.MsgSetListingVaultDepositParams{}, + "/dydxprotocol.listing.MsgSetListingVaultDepositParamsResponse": nil, + "/dydxprotocol.listing.MsgUpgradeIsolatedPerpetualToCross": &listing.MsgUpgradeIsolatedPerpetualToCross{}, + "/dydxprotocol.listing.MsgUpgradeIsolatedPerpetualToCrossResponse": nil, // perpetuals "/dydxprotocol.perpetuals.MsgCreatePerpetual": &perpetuals.MsgCreatePerpetual{}, diff --git a/protocol/app/msgs/internal_msgs_test.go b/protocol/app/msgs/internal_msgs_test.go index 70e3549fe5..00bcbdc912 100644 --- a/protocol/app/msgs/internal_msgs_test.go +++ b/protocol/app/msgs/internal_msgs_test.go @@ -116,6 +116,8 @@ func TestInternalMsgSamples_Gov_Key(t *testing.T) { "/dydxprotocol.listing.MsgSetListingVaultDepositParamsResponse", "/dydxprotocol.listing.MsgSetMarketsHardCap", "/dydxprotocol.listing.MsgSetMarketsHardCapResponse", + "/dydxprotocol.listing.MsgUpgradeIsolatedPerpetualToCross", + "/dydxprotocol.listing.MsgUpgradeIsolatedPerpetualToCrossResponse", // perpeutals "/dydxprotocol.perpetuals.MsgCreatePerpetual", diff --git a/protocol/go.mod b/protocol/go.mod index 3abdb94611..5611346f40 100644 --- a/protocol/go.mod +++ b/protocol/go.mod @@ -4,7 +4,7 @@ go 1.22.2 require ( cosmossdk.io/api v0.7.6 - cosmossdk.io/math v1.3.0 + cosmossdk.io/math v1.4.0 github.com/Shopify/sarama v1.37.2 github.com/cometbft/cometbft v0.38.12 github.com/cometbft/cometbft-db v0.12.0 // indirect @@ -468,9 +468,9 @@ replace ( // Use dYdX fork of Cosmos SDK/store cosmossdk.io/store => github.com/dydxprotocol/cosmos-sdk/store v1.0.3-0.20240326192503-dd116391188d // Use dYdX fork of CometBFT - github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.38.6-0.20241106081823-31609289f401 + github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.38.6-0.20241120221529-56316dc17261 // Use dYdX fork of Cosmos SDK - github.com/cosmos/cosmos-sdk => github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20241022180223-cc8c850952c5 + github.com/cosmos/cosmos-sdk => github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20241120185835-38650041ec4d github.com/cosmos/iavl => github.com/dydxprotocol/iavl v1.1.1-0.20240509161911-1c8b8e787e85 ) diff --git a/protocol/go.sum b/protocol/go.sum index 647abaad46..44b6c99da5 100644 --- a/protocol/go.sum +++ b/protocol/go.sum @@ -624,8 +624,8 @@ cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= -cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= -cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= +cosmossdk.io/math v1.4.0 h1:XbgExXFnXmF/CccPPEto40gOO7FpWu9yWNAZPN3nkNQ= +cosmossdk.io/math v1.4.0/go.mod h1:O5PkD4apz2jZs4zqFdTr16e1dcaQCc5z6lkEnrrppuk= cosmossdk.io/tools/confix v0.1.2 h1:2hoM1oFCNisd0ltSAAZw2i4ponARPmlhuNu3yy0VwI4= cosmossdk.io/tools/confix v0.1.2/go.mod h1:7XfcbK9sC/KNgVGxgLM0BrFbVcR/+6Dg7MFfpx7duYo= cosmossdk.io/x/circuit v0.1.1 h1:KPJCnLChWrxD4jLwUiuQaf5mFD/1m7Omyo7oooefBVQ= @@ -959,10 +959,10 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= -github.com/dydxprotocol/cometbft v0.38.6-0.20241106081823-31609289f401 h1:zPNw80OB4L9tYCwU5ToRJRUotkzoPt4HVLX4CV985Ec= -github.com/dydxprotocol/cometbft v0.38.6-0.20241106081823-31609289f401/go.mod h1:EBEod7kZfNr4W0VooOrTEMSiXNrSyiQ/M2FL/rOcPCs= -github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20241022180223-cc8c850952c5 h1:C1WxxDRbNMrX8U57IsiTZuEp5R5i/nsEtGhPyU1TIQI= -github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20241022180223-cc8c850952c5/go.mod h1:TWUDGvgHJ49+QI6WOf03km3TuUOoAplzgnsjGQH3L7s= +github.com/dydxprotocol/cometbft v0.38.6-0.20241120221529-56316dc17261 h1:uspjqDKBvC5I98gKBdZxqX3q0M2UOE/UlGgg+1CLNyI= +github.com/dydxprotocol/cometbft v0.38.6-0.20241120221529-56316dc17261/go.mod h1:XSQX1hQbr54qaJb4/5YNNZGXkAQHHa6bi/KMcN1SQ7w= +github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20241120185835-38650041ec4d h1:6Qzg4IuX6LNdciU55jzpGuKxEVgD09rbU2cQaoJFo9Q= +github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20241120185835-38650041ec4d/go.mod h1:8EZnLstapHjZ2iGa9nGIhctJ3gU1yCqmRUPN8WI7jD0= github.com/dydxprotocol/cosmos-sdk/store v1.0.3-0.20240326192503-dd116391188d h1:HgLu1FD2oDFzlKW6/+SFXlH5Os8cwNTbplQIrQOWx8w= github.com/dydxprotocol/cosmos-sdk/store v1.0.3-0.20240326192503-dd116391188d/go.mod h1:zMcD3hfNwd0WMTpdRUhS3QxoCoEtBXWeoKsu3iaLBbQ= github.com/dydxprotocol/iavl v1.1.1-0.20240509161911-1c8b8e787e85 h1:5B/yGZyTBX/OZASQQMnk6Ms/TZja56MYd8OBaVc0Mho= diff --git a/protocol/lib/ante/internal_msg.go b/protocol/lib/ante/internal_msg.go index 4d578d4f10..3e1b44a917 100644 --- a/protocol/lib/ante/internal_msg.go +++ b/protocol/lib/ante/internal_msg.go @@ -103,6 +103,7 @@ func IsInternalMsg(msg sdk.Msg) bool { // listing *listing.MsgSetMarketsHardCap, *listing.MsgSetListingVaultDepositParams, + *listing.MsgUpgradeIsolatedPerpetualToCross, // perpetuals *perpetuals.MsgCreatePerpetual, diff --git a/protocol/mocks/ClobKeeper.go b/protocol/mocks/ClobKeeper.go index 4b786d6b81..84dd25c454 100644 --- a/protocol/mocks/ClobKeeper.go +++ b/protocol/mocks/ClobKeeper.go @@ -332,26 +332,6 @@ func (_m *ClobKeeper) GetIndexerEventManager() indexer_manager.IndexerEventManag return r0 } -// GetInsuranceFundBalance provides a mock function with given fields: ctx, perpetualId -func (_m *ClobKeeper) GetInsuranceFundBalance(ctx types.Context, perpetualId uint32) *big.Int { - ret := _m.Called(ctx, perpetualId) - - if len(ret) == 0 { - panic("no return value specified for GetInsuranceFundBalance") - } - - var r0 *big.Int - if rf, ok := ret.Get(0).(func(types.Context, uint32) *big.Int); ok { - r0 = rf(ctx, perpetualId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - return r0 -} - // GetLiquidationInsuranceFundDelta provides a mock function with given fields: ctx, subaccountId, perpetualId, isBuy, fillAmount, subticks func (_m *ClobKeeper) GetLiquidationInsuranceFundDelta(ctx types.Context, subaccountId subaccountstypes.SubaccountId, perpetualId uint32, isBuy bool, fillAmount uint64, subticks clobtypes.Subticks) (*big.Int, error) { ret := _m.Called(ctx, subaccountId, perpetualId, isBuy, fillAmount, subticks) diff --git a/protocol/streaming/full_node_streaming_manager.go b/protocol/streaming/full_node_streaming_manager.go index af0d5671cd..29717366fc 100644 --- a/protocol/streaming/full_node_streaming_manager.go +++ b/protocol/streaming/full_node_streaming_manager.go @@ -7,6 +7,7 @@ import ( "time" "github.com/dydxprotocol/v4-chain/protocol/lib" + pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "cosmossdk.io/log" @@ -52,6 +53,8 @@ type FullNodeStreamingManagerImpl struct { clobPairIdToSubscriptionIdMapping map[uint32][]uint32 // map from subaccount id to subscription ids. subaccountIdToSubscriptionIdMapping map[satypes.SubaccountId][]uint32 + // map from market id to subscription ids. + marketIdToSubscriptionIdMapping map[uint32][]uint32 maxUpdatesInCache uint32 maxSubscriptionChannelSize uint32 @@ -79,6 +82,9 @@ type OrderbookSubscription struct { // Subaccount ids to subscribe to. subaccountIds []satypes.SubaccountId + // market ids to subscribe to. + marketIds []uint32 + // Stream messageSender types.OutgoingMessageSender @@ -114,6 +120,7 @@ func NewFullNodeStreamingManager( streamUpdateSubscriptionCache: make([][]uint32, 0), clobPairIdToSubscriptionIdMapping: make(map[uint32][]uint32), subaccountIdToSubscriptionIdMapping: make(map[satypes.SubaccountId][]uint32), + marketIdToSubscriptionIdMapping: make(map[uint32][]uint32), maxUpdatesInCache: maxUpdatesInCache, maxSubscriptionChannelSize: maxSubscriptionChannelSize, @@ -184,6 +191,7 @@ func (sm *FullNodeStreamingManagerImpl) getNextAvailableSubscriptionId() uint32 func (sm *FullNodeStreamingManagerImpl) Subscribe( clobPairIds []uint32, subaccountIds []*satypes.SubaccountId, + marketIds []uint32, messageSender types.OutgoingMessageSender, ) ( err error, @@ -206,6 +214,7 @@ func (sm *FullNodeStreamingManagerImpl) Subscribe( initialized: &atomic.Bool{}, // False by default. clobPairIds: clobPairIds, subaccountIds: sIds, + marketIds: marketIds, messageSender: messageSender, updatesChannel: make(chan []clobtypes.StreamUpdate, sm.maxSubscriptionChannelSize), } @@ -231,6 +240,17 @@ func (sm *FullNodeStreamingManagerImpl) Subscribe( subscription.subscriptionId, ) } + for _, marketId := range marketIds { + // if subaccountId exists in the map, append the subscription id to the slice + // otherwise, create a new slice with the subscription id + if _, ok := sm.marketIdToSubscriptionIdMapping[marketId]; !ok { + sm.marketIdToSubscriptionIdMapping[marketId] = []uint32{} + } + sm.marketIdToSubscriptionIdMapping[marketId] = append( + sm.marketIdToSubscriptionIdMapping[marketId], + subscription.subscriptionId, + ) + } sm.logger.Info( fmt.Sprintf( @@ -325,6 +345,21 @@ func (sm *FullNodeStreamingManagerImpl) removeSubscription( } } + // Iterate over the marketIdToSubscriptionIdMapping to remove the subscriptionIdToRemove + for marketId, subscriptionIds := range sm.marketIdToSubscriptionIdMapping { + for i, id := range subscriptionIds { + if id == subscriptionIdToRemove { + // Remove the subscription ID from the slice + sm.marketIdToSubscriptionIdMapping[marketId] = append(subscriptionIds[:i], subscriptionIds[i+1:]...) + break + } + } + // If the list is empty after removal, delete the key from the map + if len(sm.marketIdToSubscriptionIdMapping[marketId]) == 0 { + delete(sm.marketIdToSubscriptionIdMapping, marketId) + } + } + sm.logger.Info( fmt.Sprintf("Removed streaming subscription id %+v", subscriptionIdToRemove), ) @@ -372,6 +407,24 @@ func toSubaccountStreamUpdates( return streamUpdates } +func toPriceStreamUpdates( + priceUpdates []*pricestypes.StreamPriceUpdate, + blockHeight uint32, + execMode sdk.ExecMode, +) []clobtypes.StreamUpdate { + streamUpdates := make([]clobtypes.StreamUpdate, 0) + for _, update := range priceUpdates { + streamUpdates = append(streamUpdates, clobtypes.StreamUpdate{ + UpdateMessage: &clobtypes.StreamUpdate_PriceUpdate{ + PriceUpdate: update, + }, + BlockHeight: blockHeight, + ExecMode: uint32(execMode), + }) + } + return streamUpdates +} + func (sm *FullNodeStreamingManagerImpl) sendStreamUpdates( subscriptionId uint32, streamUpdates []clobtypes.StreamUpdate, @@ -466,6 +519,7 @@ func (sm *FullNodeStreamingManagerImpl) GetStagedFinalizeBlockEvents( func (sm *FullNodeStreamingManagerImpl) SendCombinedSnapshot( offchainUpdates *clobtypes.OffchainUpdates, saUpdates []*satypes.StreamSubaccountUpdate, + priceUpdates []*pricestypes.StreamPriceUpdate, subscriptionId uint32, blockHeight uint32, execMode sdk.ExecMode, @@ -479,6 +533,7 @@ func (sm *FullNodeStreamingManagerImpl) SendCombinedSnapshot( var streamUpdates []clobtypes.StreamUpdate streamUpdates = append(streamUpdates, toOrderbookStreamUpdate(offchainUpdates, blockHeight, execMode)...) streamUpdates = append(streamUpdates, toSubaccountStreamUpdates(saUpdates, blockHeight, execMode)...) + streamUpdates = append(streamUpdates, toPriceStreamUpdates(priceUpdates, blockHeight, execMode)...) sm.sendStreamUpdates(subscriptionId, streamUpdates) } @@ -863,6 +918,30 @@ func (sm *FullNodeStreamingManagerImpl) GetSubaccountSnapshotsForInitStreams( return ret } +func (sm *FullNodeStreamingManagerImpl) GetPriceSnapshotsForInitStreams( + getPriceSnapshot func(marketId uint32) *pricestypes.StreamPriceUpdate, +) map[uint32]*pricestypes.StreamPriceUpdate { + sm.Lock() + defer sm.Unlock() + + ret := make(map[uint32]*pricestypes.StreamPriceUpdate) + for _, subscription := range sm.orderbookSubscriptions { + // If the subscription has been initialized, no need to grab the price snapshot. + if alreadyInitialized := subscription.initialized.Load(); alreadyInitialized { + continue + } + + for _, marketId := range subscription.marketIds { + if _, exists := ret[marketId]; exists { + continue + } + + ret[marketId] = getPriceSnapshot(marketId) + } + } + return ret +} + // cacheStreamUpdatesByClobPairWithLock adds stream updates to cache, // and store corresponding clob pair Ids. // This method requires the lock and assumes that the lock has already been @@ -1003,6 +1082,7 @@ func (sm *FullNodeStreamingManagerImpl) getStagedEventsFromFinalizeBlock( func (sm *FullNodeStreamingManagerImpl) InitializeNewStreams( getOrderbookSnapshot func(clobPairId clobtypes.ClobPairId) *clobtypes.OffchainUpdates, subaccountSnapshots map[satypes.SubaccountId]*satypes.StreamSubaccountUpdate, + pricesSnapshots map[uint32]*pricestypes.StreamPriceUpdate, blockHeight uint32, execMode sdk.ExecMode, ) { @@ -1038,7 +1118,28 @@ func (sm *FullNodeStreamingManagerImpl) InitializeNewStreams( } } - sm.SendCombinedSnapshot(allUpdates, saUpdates, subscriptionId, blockHeight, execMode) + priceUpdates := []*pricestypes.StreamPriceUpdate{} + for _, marketId := range subscription.marketIds { + if priceUpdate, ok := pricesSnapshots[marketId]; ok { + priceUpdates = append(priceUpdates, priceUpdate) + } else { + sm.logger.Error( + fmt.Sprintf( + "Price update not found for market id %v. This should not happen.", + marketId, + ), + ) + } + } + + sm.SendCombinedSnapshot( + allUpdates, + saUpdates, + priceUpdates, + subscriptionId, + blockHeight, + execMode, + ) if sm.snapshotBlockInterval != 0 { subscription.nextSnapshotBlock = blockHeight + sm.snapshotBlockInterval diff --git a/protocol/streaming/noop_streaming_manager.go b/protocol/streaming/noop_streaming_manager.go index 89250854c4..6d6dd41608 100644 --- a/protocol/streaming/noop_streaming_manager.go +++ b/protocol/streaming/noop_streaming_manager.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dydxprotocol/v4-chain/protocol/streaming/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" ) @@ -22,6 +23,7 @@ func (sm *NoopGrpcStreamingManager) Enabled() bool { func (sm *NoopGrpcStreamingManager) Subscribe( _ []uint32, _ []*satypes.SubaccountId, + _ []uint32, _ types.OutgoingMessageSender, ) ( err error, @@ -58,9 +60,16 @@ func (sm *NoopGrpcStreamingManager) GetSubaccountSnapshotsForInitStreams( return nil } +func (sm *NoopGrpcStreamingManager) GetPriceSnapshotsForInitStreams( + _ func(_ uint32) *pricestypes.StreamPriceUpdate, +) map[uint32]*pricestypes.StreamPriceUpdate { + return nil +} + func (sm *NoopGrpcStreamingManager) InitializeNewStreams( getOrderbookSnapshot func(clobPairId clobtypes.ClobPairId) *clobtypes.OffchainUpdates, subaccountSnapshots map[satypes.SubaccountId]*satypes.StreamSubaccountUpdate, + priceSnapshots map[uint32]*pricestypes.StreamPriceUpdate, blockHeight uint32, execMode sdk.ExecMode, ) { diff --git a/protocol/streaming/types/interface.go b/protocol/streaming/types/interface.go index 33907fc1ec..028352a10b 100644 --- a/protocol/streaming/types/interface.go +++ b/protocol/streaming/types/interface.go @@ -3,6 +3,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" ) @@ -14,6 +15,7 @@ type FullNodeStreamingManager interface { Subscribe( clobPairIds []uint32, subaccountIds []*satypes.SubaccountId, + marketIds []uint32, srv OutgoingMessageSender, ) ( err error, @@ -23,12 +25,16 @@ type FullNodeStreamingManager interface { InitializeNewStreams( getOrderbookSnapshot func(clobPairId clobtypes.ClobPairId) *clobtypes.OffchainUpdates, subaccountSnapshots map[satypes.SubaccountId]*satypes.StreamSubaccountUpdate, + priceSnapshots map[uint32]*pricestypes.StreamPriceUpdate, blockHeight uint32, execMode sdk.ExecMode, ) GetSubaccountSnapshotsForInitStreams( getSubaccountSnapshot func(subaccountId satypes.SubaccountId) *satypes.StreamSubaccountUpdate, ) map[satypes.SubaccountId]*satypes.StreamSubaccountUpdate + GetPriceSnapshotsForInitStreams( + getPriceSnapshot func(marketId uint32) *pricestypes.StreamPriceUpdate, + ) map[uint32]*pricestypes.StreamPriceUpdate SendOrderbookUpdates( offchainUpdates *clobtypes.OffchainUpdates, ctx sdk.Context, diff --git a/protocol/streaming/ws/websocket_server.go b/protocol/streaming/ws/websocket_server.go index ba4477d03b..3cbb9219a4 100644 --- a/protocol/streaming/ws/websocket_server.go +++ b/protocol/streaming/ws/websocket_server.go @@ -16,6 +16,11 @@ import ( "github.com/gorilla/websocket" ) +const ( + CLOB_PAIR_IDS_QUERY_PARAM = "clobPairIds" + MARKET_IDS_QUERY_PARAM = "marketIds" +) + var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, @@ -61,7 +66,7 @@ func (ws *WebsocketServer) Handler(w http.ResponseWriter, r *http.Request) { conn.SetReadLimit(10 * 1024 * 1024) // Parse clobPairIds from query parameters - clobPairIds, err := parseClobPairIds(r) + clobPairIds, err := parseUint32(r, CLOB_PAIR_IDS_QUERY_PARAM) if err != nil { ws.logger.Error( "Error parsing clobPairIds", @@ -70,6 +75,18 @@ func (ws *WebsocketServer) Handler(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } + + // Parse marketIds from query parameters + marketIds, err := parseUint32(r, MARKET_IDS_QUERY_PARAM) + if err != nil { + ws.logger.Error( + "Error parsing marketIds", + "err", err, + ) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + // Parse subaccountIds from query parameters subaccountIds, err := parseSubaccountIds(r) if err != nil { @@ -93,6 +110,7 @@ func (ws *WebsocketServer) Handler(w http.ResponseWriter, r *http.Request) { err = ws.streamingManager.Subscribe( clobPairIds, subaccountIds, + marketIds, websocketMessageSender, ) if err != nil { @@ -136,26 +154,26 @@ func parseSubaccountIds(r *http.Request) ([]*satypes.SubaccountId, error) { return subaccountIds, nil } -// parseClobPairIds is a helper function to parse the clobPairIds from the query parameters. -func parseClobPairIds(r *http.Request) ([]uint32, error) { - clobPairIdsParam := r.URL.Query().Get("clobPairIds") - if clobPairIdsParam == "" { +// parseUint32 is a helper function to parse the uint32 from the query parameters. +func parseUint32(r *http.Request, queryParam string) ([]uint32, error) { + param := r.URL.Query().Get(queryParam) + if param == "" { return []uint32{}, nil } - idStrs := strings.Split(clobPairIdsParam, ",") - clobPairIds := make([]uint32, 0) + idStrs := strings.Split(param, ",") + ids := make([]uint32, 0) for _, idStr := range idStrs { id, err := strconv.Atoi(idStr) if err != nil { - return nil, fmt.Errorf("invalid clobPairId: %s", idStr) + return nil, fmt.Errorf("invalid %s: %s", queryParam, idStr) } if id < 0 || id > math.MaxInt32 { - return nil, fmt.Errorf("invalid clob pair id: %s", idStr) + return nil, fmt.Errorf("invalid %s: %s", queryParam, idStr) } - clobPairIds = append(clobPairIds, uint32(id)) + ids = append(ids, uint32(id)) } - return clobPairIds, nil + return ids, nil } // Start the websocket server in a separate goroutine. diff --git a/protocol/testutil/app/app.go b/protocol/testutil/app/app.go index a4dbac0bc2..69d76021f3 100644 --- a/protocol/testutil/app/app.go +++ b/protocol/testutil/app/app.go @@ -1308,6 +1308,9 @@ func launchValidatorInDir( "--oracle.enabled=false", "--oracle.metrics_enabled=false", "--log_level=error", + // TODO(CT-1329): Currently, the TestApp framework does not work well with OE, + // since the non-deterministic test app instances does not handle go routines. + "--optimistic-execution-enabled=false", }) ctx := svrcmd.CreateExecuteContext(parentCtx) diff --git a/protocol/testutil/keeper/listing.go b/protocol/testutil/keeper/listing.go index 98f8e7f69f..1448645130 100644 --- a/protocol/testutil/keeper/listing.go +++ b/protocol/testutil/keeper/listing.go @@ -11,9 +11,11 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/lib" "github.com/dydxprotocol/v4-chain/protocol/mocks" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + assetskeeper "github.com/dydxprotocol/v4-chain/protocol/x/assets/keeper" clobkeeper "github.com/dydxprotocol/v4-chain/protocol/x/clob/keeper" perpetualskeeper "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/keeper" priceskeeper "github.com/dydxprotocol/v4-chain/protocol/x/prices/keeper" + subaccountskeeper "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/keeper" vaultkeeper "github.com/dydxprotocol/v4-chain/protocol/x/vault/keeper" marketmapkeeper "github.com/skip-mev/connect/v2/x/marketmap/keeper" "github.com/stretchr/testify/mock" @@ -37,6 +39,9 @@ func ListingKeepers( perpetualsKeeper *perpetualskeeper.Keeper, clobKeeper *clobkeeper.Keeper, marketMapKeeper *marketmapkeeper.Keeper, + assetsKeeper *assetskeeper.Keeper, + bankKeeper_out *bankkeeper.BaseKeeper, + subaccountsKeeper *subaccountskeeper.Keeper, ) { ctx = initKeepers( t, func( @@ -63,13 +68,13 @@ func ListingKeepers( db, cdc, ) - bankKeeper, _ = createBankKeeper(stateStore, db, cdc, accountsKeeper) + bankKeeper_out, _ = createBankKeeper(stateStore, db, cdc, accountsKeeper) stakingKeeper, _ := createStakingKeeper( stateStore, db, cdc, accountsKeeper, - bankKeeper, + bankKeeper_out, ) statsKeeper, _ := createStatsKeeper( stateStore, @@ -113,7 +118,7 @@ func ListingKeepers( epochsKeeper, transientStoreKey, ) - assetsKeeper, _ := createAssetsKeeper( + assetsKeeper, _ = createAssetsKeeper( stateStore, db, cdc, @@ -126,19 +131,19 @@ func ListingKeepers( rewardsKeeper, _ := createRewardsKeeper( stateStore, assetsKeeper, - bankKeeper, + bankKeeper_out, feeTiersKeeper, pricesKeeper, indexerEventManager, db, cdc, ) - subaccountsKeeper, _ := createSubaccountsKeeper( + subaccountsKeeper, _ = createSubaccountsKeeper( stateStore, db, cdc, assetsKeeper, - bankKeeper, + bankKeeper_out, perpetualsKeeper, blockTimeKeeper, transientStoreKey, @@ -151,7 +156,7 @@ func ListingKeepers( memClob, assetsKeeper, blockTimeKeeper, - bankKeeper, + bankKeeper_out, feeTiersKeeper, perpetualsKeeper, pricesKeeper, @@ -173,6 +178,7 @@ func ListingKeepers( perpetualsKeeper, clobKeeper, marketMapKeeper, + subaccountsKeeper, vaultKeeper, ) @@ -180,7 +186,8 @@ func ListingKeepers( }, ) - return ctx, keeper, storeKey, mockTimeProvider, pricesKeeper, perpetualsKeeper, clobKeeper, marketMapKeeper + return ctx, keeper, storeKey, mockTimeProvider, pricesKeeper, perpetualsKeeper, + clobKeeper, marketMapKeeper, assetsKeeper, bankKeeper_out, subaccountsKeeper } func createListingKeeper( @@ -191,6 +198,7 @@ func createListingKeeper( perpetualsKeeper *perpetualskeeper.Keeper, clobKeeper *clobkeeper.Keeper, marketMapKeeper *marketmapkeeper.Keeper, + subaccountsKeeper *subaccountskeeper.Keeper, vaultkeeper *vaultkeeper.Keeper, ) ( *keeper.Keeper, @@ -211,6 +219,7 @@ func createListingKeeper( clobKeeper, marketMapKeeper, perpetualsKeeper, + subaccountsKeeper, vaultkeeper, ) diff --git a/protocol/x/affiliates/keeper/keeper.go b/protocol/x/affiliates/keeper/keeper.go index f942e46418..ee068a7265 100644 --- a/protocol/x/affiliates/keeper/keeper.go +++ b/protocol/x/affiliates/keeper/keeper.go @@ -310,8 +310,12 @@ func (k Keeper) SetAffiliateWhitelist(ctx sdk.Context, whitelist types.Affiliate "taker fee share ppm %d is greater than the cap %d", tier.TakerFeeSharePpm, types.AffiliatesRevSharePpmCap) } - // Check for duplicate addresses. for _, address := range tier.Addresses { + // Check for invalid addresses. + if _, err := sdk.AccAddressFromBech32(address); err != nil { + return errorsmod.Wrapf(types.ErrInvalidAddress, "address to whitelist: %s", address) + } + // Check for duplicate addresses. if addressSet[address] { return errorsmod.Wrapf(types.ErrDuplicateAffiliateAddressForWhitelist, "address %s is duplicated in affiliate whitelist", address) diff --git a/protocol/x/affiliates/keeper/keeper_test.go b/protocol/x/affiliates/keeper/keeper_test.go index 96b25b83e5..aeb9efd139 100644 --- a/protocol/x/affiliates/keeper/keeper_test.go +++ b/protocol/x/affiliates/keeper/keeper_test.go @@ -484,6 +484,36 @@ func TestSetAffiliateWhitelist(t *testing.T) { }, expectedError: types.ErrRevShareSafetyViolation, }, + { + name: "Invalid bech32 address present", + whitelist: types.AffiliateWhitelist{ + Tiers: []types.AffiliateWhitelist_Tier{ + { + Addresses: []string{ + constants.AliceAccAddress.String(), + "dydxinvalidaddress", + }, + TakerFeeSharePpm: 500_000, // 50% + }, + }, + }, + expectedError: types.ErrInvalidAddress, + }, + { + name: "Validator operator address not accepted", + whitelist: types.AffiliateWhitelist{ + Tiers: []types.AffiliateWhitelist_Tier{ + { + Addresses: []string{ + constants.AliceAccAddress.String(), + "dydxvaloper1et2kxktzr6tav65uhrxsyr8gx82xvan6gl78xd", + }, + TakerFeeSharePpm: 500_000, // 50% + }, + }, + }, + expectedError: types.ErrInvalidAddress, + }, } for _, tc := range testCases { diff --git a/protocol/x/clob/keeper/deleveraging.go b/protocol/x/clob/keeper/deleveraging.go index c088887747..a525deb521 100644 --- a/protocol/x/clob/keeper/deleveraging.go +++ b/protocol/x/clob/keeper/deleveraging.go @@ -18,7 +18,6 @@ import ( assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" perplib "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/lib" - perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" ) @@ -130,43 +129,6 @@ func (k Keeper) MaybeDeleverageSubaccount( return quantumsDeleveraged, err } -// GetInsuranceFundBalance returns the current balance of the specific insurance fund based on the -// perpetual (in quote quantums). -// This calls the Bank Keeper’s GetBalance() function for the Module Address of the insurance fund. -func (k Keeper) GetInsuranceFundBalance(ctx sdk.Context, perpetualId uint32) (balance *big.Int) { - usdcAsset, exists := k.assetsKeeper.GetAsset(ctx, assettypes.AssetUsdc.Id) - if !exists { - panic("GetInsuranceFundBalance: Usdc asset not found in state") - } - insuranceFundAddr, err := k.perpetualsKeeper.GetInsuranceFundModuleAddress(ctx, perpetualId) - if err != nil { - return nil - } - insuranceFundBalance := k.bankKeeper.GetBalance( - ctx, - insuranceFundAddr, - usdcAsset.Denom, - ) - - // Return as big.Int. - return insuranceFundBalance.Amount.BigInt() -} - -func (k Keeper) GetCrossInsuranceFundBalance(ctx sdk.Context) (balance *big.Int) { - usdcAsset, exists := k.assetsKeeper.GetAsset(ctx, assettypes.AssetUsdc.Id) - if !exists { - panic("GetCrossInsuranceFundBalance: Usdc asset not found in state") - } - insuranceFundBalance := k.bankKeeper.GetBalance( - ctx, - perptypes.InsuranceFundModuleAddress, - usdcAsset.Denom, - ) - - // Return as big.Int. - return insuranceFundBalance.Amount.BigInt() -} - // CanDeleverageSubaccount returns true if a subaccount can be deleveraged. // This function returns two booleans, shouldDeleverageAtBankruptcyPrice and shouldDeleverageAtOraclePrice. // - shouldDeleverageAtBankruptcyPrice is true if the subaccount has negative TNC. @@ -279,7 +241,7 @@ func (k Keeper) IsValidInsuranceFundDelta(ctx sdk.Context, insuranceFundDelta *b // The insurance fund delta is valid if the insurance fund balance is non-negative after adding // the delta. - currentInsuranceFundBalance := k.GetInsuranceFundBalance(ctx, perpetualId) + currentInsuranceFundBalance := k.subaccountsKeeper.GetInsuranceFundBalance(ctx, perpetualId) return new(big.Int).Add(currentInsuranceFundBalance, insuranceFundDelta).Sign() >= 0 } diff --git a/protocol/x/clob/keeper/deleveraging_test.go b/protocol/x/clob/keeper/deleveraging_test.go index d3e6cb1ff0..f36f730061 100644 --- a/protocol/x/clob/keeper/deleveraging_test.go +++ b/protocol/x/clob/keeper/deleveraging_test.go @@ -1,8 +1,6 @@ package keeper_test import ( - "errors" - "math" "math/big" "testing" "time" @@ -19,7 +17,6 @@ import ( keepertest "github.com/dydxprotocol/v4-chain/protocol/testutil/keeper" perptest "github.com/dydxprotocol/v4-chain/protocol/testutil/perpetuals" testutil "github.com/dydxprotocol/v4-chain/protocol/testutil/util" - assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" blocktimetypes "github.com/dydxprotocol/v4-chain/protocol/x/blocktime/types" "github.com/dydxprotocol/v4-chain/protocol/x/clob/memclob" "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" @@ -30,133 +27,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestGetInsuranceFundBalance(t *testing.T) { - tests := map[string]struct { - // Setup - assets []assettypes.Asset - insuranceFundBalance *big.Int - perpetualId uint32 - perpetual *perptypes.Perpetual - - // Expectations. - expectedInsuranceFundBalance *big.Int - expectedError error - }{ - "can get zero balance": { - assets: []assettypes.Asset{ - *constants.Usdc, - }, - perpetualId: 0, - insuranceFundBalance: new(big.Int), - expectedInsuranceFundBalance: big.NewInt(0), - }, - "can get positive balance": { - assets: []assettypes.Asset{ - *constants.Usdc, - }, - perpetualId: 0, - insuranceFundBalance: big.NewInt(100), - expectedInsuranceFundBalance: big.NewInt(100), - }, - "can get greater than MaxUint64 balance": { - assets: []assettypes.Asset{ - *constants.Usdc, - }, - perpetualId: 0, - insuranceFundBalance: new(big.Int).Add( - new(big.Int).SetUint64(math.MaxUint64), - new(big.Int).SetUint64(math.MaxUint64), - ), - expectedInsuranceFundBalance: new(big.Int).Add( - new(big.Int).SetUint64(math.MaxUint64), - new(big.Int).SetUint64(math.MaxUint64), - ), - }, - "can get zero balance - isolated market": { - assets: []assettypes.Asset{ - *constants.Usdc, - }, - perpetualId: 3, // Isolated market. - insuranceFundBalance: new(big.Int), - expectedInsuranceFundBalance: big.NewInt(0), - }, - "can get positive balance - isolated market": { - assets: []assettypes.Asset{ - *constants.Usdc, - }, - perpetualId: 3, // Isolated market. - insuranceFundBalance: big.NewInt(100), - expectedInsuranceFundBalance: big.NewInt(100), - }, - "panics when asset not found in state": { - assets: []assettypes.Asset{}, - perpetualId: 0, - expectedError: errors.New("GetInsuranceFundBalance: Usdc asset not found in state"), - }, - } - - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - // Setup keeper state. - memClob := memclob.NewMemClobPriceTimePriority(false) - bankMock := &mocks.BankKeeper{} - ks := keepertest.NewClobKeepersTestContext(t, memClob, bankMock, &mocks.IndexerEventManager{}) - - ctx := ks.Ctx.WithIsCheckTx(true) - // Create the default markets. - keepertest.CreateTestMarkets(t, ctx, ks.PricesKeeper) - - // Create liquidity tiers. - keepertest.CreateTestLiquidityTiers(t, ctx, ks.PerpetualsKeeper) - - keepertest.CreateTestPerpetuals(t, ctx, ks.PerpetualsKeeper) - - for _, a := range tc.assets { - _, err := ks.AssetsKeeper.CreateAsset( - ks.Ctx, - a.Id, - a.Symbol, - a.Denom, - a.DenomExponent, - a.HasMarket, - a.MarketId, - a.AtomicResolution, - ) - require.NoError(t, err) - } - - insuranceFundAddr, err := ks.PerpetualsKeeper.GetInsuranceFundModuleAddress(ks.Ctx, tc.perpetualId) - require.NoError(t, err) - if tc.insuranceFundBalance != nil { - bankMock.On( - "GetBalance", - mock.Anything, - insuranceFundAddr, - constants.Usdc.Denom, - ).Return( - sdk.NewCoin(constants.Usdc.Denom, sdkmath.NewIntFromBigInt(tc.insuranceFundBalance)), - ) - } - - if tc.expectedError != nil { - require.PanicsWithValue( - t, - tc.expectedError.Error(), - func() { - ks.ClobKeeper.GetInsuranceFundBalance(ks.Ctx, tc.perpetualId) - }, - ) - } else { - require.Equal( - t, - tc.expectedInsuranceFundBalance, - ks.ClobKeeper.GetInsuranceFundBalance(ks.Ctx, tc.perpetualId), - ) - } - }) - } -} - func TestIsValidInsuranceFundDelta(t *testing.T) { tests := map[string]struct { // Setup diff --git a/protocol/x/clob/keeper/grpc_stream_orderbook.go b/protocol/x/clob/keeper/grpc_stream_orderbook.go index caca5fbfbe..029266901a 100644 --- a/protocol/x/clob/keeper/grpc_stream_orderbook.go +++ b/protocol/x/clob/keeper/grpc_stream_orderbook.go @@ -11,6 +11,7 @@ func (k Keeper) StreamOrderbookUpdates( err := k.GetFullNodeStreamingManager().Subscribe( req.GetClobPairId(), req.GetSubaccountIds(), + req.GetMarketIds(), stream, ) if err != nil { diff --git a/protocol/x/clob/keeper/keeper.go b/protocol/x/clob/keeper/keeper.go index 633a0725b9..4d2303bb0d 100644 --- a/protocol/x/clob/keeper/keeper.go +++ b/protocol/x/clob/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "errors" "fmt" + "math/big" "sync/atomic" "github.com/dydxprotocol/v4-chain/protocol/finalizeblock" @@ -22,6 +23,7 @@ import ( flags "github.com/dydxprotocol/v4-chain/protocol/x/clob/flags" "github.com/dydxprotocol/v4-chain/protocol/x/clob/rate_limit" "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" ) type ( @@ -162,6 +164,10 @@ func (k Keeper) GetFullNodeStreamingManager() streamingtypes.FullNodeStreamingMa return k.streamingManager } +func (k Keeper) GetCrossInsuranceFundBalance(ctx sdk.Context) *big.Int { + return k.subaccountsKeeper.GetCrossInsuranceFundBalance(ctx) +} + func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With( log.ModuleKey, "x/clob", @@ -326,6 +332,25 @@ func (k Keeper) GetSubaccountSnapshotsForInitStreams( ) } +func (k Keeper) GetPriceSnapshotsForInitStreams( + ctx sdk.Context, +) ( + priceSnapshots map[uint32]*pricestypes.StreamPriceUpdate, +) { + lib.AssertCheckTxMode(ctx) + + return k.GetFullNodeStreamingManager().GetPriceSnapshotsForInitStreams( + func(marketId uint32) *pricestypes.StreamPriceUpdate { + update := k.pricesKeeper.GetStreamPriceUpdate( + ctx, + marketId, + true, + ) + return &update + }, + ) +} + // InitializeNewStreams initializes new streams for all uninitialized clob pairs // by sending the corresponding orderbook snapshots. func (k Keeper) InitializeNewStreams( @@ -334,6 +359,8 @@ func (k Keeper) InitializeNewStreams( ) { streamingManager := k.GetFullNodeStreamingManager() + priceSnapshots := k.GetPriceSnapshotsForInitStreams(ctx) + streamingManager.InitializeNewStreams( func(clobPairId types.ClobPairId) *types.OffchainUpdates { return k.MemClob.GetOffchainUpdatesForOrderbookSnapshot( @@ -342,6 +369,7 @@ func (k Keeper) InitializeNewStreams( ) }, subaccountSnapshots, + priceSnapshots, lib.MustConvertIntegerToUint32(ctx.BlockHeight()), ctx.ExecMode(), ) diff --git a/protocol/x/clob/types/expected_keepers.go b/protocol/x/clob/types/expected_keepers.go index 846cc7d539..968db325a8 100644 --- a/protocol/x/clob/types/expected_keepers.go +++ b/protocol/x/clob/types/expected_keepers.go @@ -77,6 +77,17 @@ type SubaccountsKeeper interface { amount *big.Int, perpetualId uint32, ) error + GetInsuranceFundBalance( + ctx sdk.Context, + perpetualId uint32, + ) ( + balance *big.Int, + ) + GetCrossInsuranceFundBalance( + ctx sdk.Context, + ) ( + balance *big.Int, + ) GetCollateralPoolFromPerpetualId( ctx sdk.Context, perpetualId uint32, @@ -141,6 +152,7 @@ type PerpetualsKeeper interface { type PricesKeeper interface { GetMarketParam(ctx sdk.Context, id uint32) (param pricestypes.MarketParam, exists bool) + GetStreamPriceUpdate(ctx sdk.Context, id uint32, snapshot bool) (val pricestypes.StreamPriceUpdate) } type StatsKeeper interface { diff --git a/protocol/x/clob/types/liquidations_keeper.go b/protocol/x/clob/types/liquidations_keeper.go index b649a8e6c8..6bdf9f7a72 100644 --- a/protocol/x/clob/types/liquidations_keeper.go +++ b/protocol/x/clob/types/liquidations_keeper.go @@ -51,7 +51,6 @@ type LiquidationsKeeper interface { fillablePrice *big.Rat, err error, ) - GetInsuranceFundBalance(ctx sdk.Context, perpetualId uint32) (balance *big.Int) GetLiquidationInsuranceFundDelta( ctx sdk.Context, subaccountId satypes.SubaccountId, diff --git a/protocol/x/clob/types/query.pb.go b/protocol/x/clob/types/query.pb.go index 5d6f5df715..b259206910 100644 --- a/protocol/x/clob/types/query.pb.go +++ b/protocol/x/clob/types/query.pb.go @@ -11,7 +11,8 @@ import ( _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" - types1 "github.com/dydxprotocol/v4-chain/protocol/indexer/off_chain_updates/types" + types2 "github.com/dydxprotocol/v4-chain/protocol/indexer/off_chain_updates/types" + types1 "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" types "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" @@ -855,6 +856,8 @@ type StreamOrderbookUpdatesRequest struct { ClobPairId []uint32 `protobuf:"varint,1,rep,packed,name=clob_pair_id,json=clobPairId,proto3" json:"clob_pair_id,omitempty"` // Subaccount ids to stream subaccount updates for. SubaccountIds []*types.SubaccountId `protobuf:"bytes,2,rep,name=subaccount_ids,json=subaccountIds,proto3" json:"subaccount_ids,omitempty"` + // Market ids for price updates. + MarketIds []uint32 `protobuf:"varint,3,rep,packed,name=market_ids,json=marketIds,proto3" json:"market_ids,omitempty"` } func (m *StreamOrderbookUpdatesRequest) Reset() { *m = StreamOrderbookUpdatesRequest{} } @@ -904,6 +907,13 @@ func (m *StreamOrderbookUpdatesRequest) GetSubaccountIds() []*types.SubaccountId return nil } +func (m *StreamOrderbookUpdatesRequest) GetMarketIds() []uint32 { + if m != nil { + return m.MarketIds + } + return nil +} + // StreamOrderbookUpdatesResponse is a response message for the // StreamOrderbookUpdates method. type StreamOrderbookUpdatesResponse struct { @@ -967,6 +977,7 @@ type StreamUpdate struct { // *StreamUpdate_OrderFill // *StreamUpdate_TakerOrder // *StreamUpdate_SubaccountUpdate + // *StreamUpdate_PriceUpdate UpdateMessage isStreamUpdate_UpdateMessage `protobuf_oneof:"update_message"` } @@ -1021,11 +1032,15 @@ type StreamUpdate_TakerOrder struct { type StreamUpdate_SubaccountUpdate struct { SubaccountUpdate *types.StreamSubaccountUpdate `protobuf:"bytes,6,opt,name=subaccount_update,json=subaccountUpdate,proto3,oneof" json:"subaccount_update,omitempty"` } +type StreamUpdate_PriceUpdate struct { + PriceUpdate *types1.StreamPriceUpdate `protobuf:"bytes,7,opt,name=price_update,json=priceUpdate,proto3,oneof" json:"price_update,omitempty"` +} func (*StreamUpdate_OrderbookUpdate) isStreamUpdate_UpdateMessage() {} func (*StreamUpdate_OrderFill) isStreamUpdate_UpdateMessage() {} func (*StreamUpdate_TakerOrder) isStreamUpdate_UpdateMessage() {} func (*StreamUpdate_SubaccountUpdate) isStreamUpdate_UpdateMessage() {} +func (*StreamUpdate_PriceUpdate) isStreamUpdate_UpdateMessage() {} func (m *StreamUpdate) GetUpdateMessage() isStreamUpdate_UpdateMessage { if m != nil { @@ -1076,6 +1091,13 @@ func (m *StreamUpdate) GetSubaccountUpdate() *types.StreamSubaccountUpdate { return nil } +func (m *StreamUpdate) GetPriceUpdate() *types1.StreamPriceUpdate { + if x, ok := m.GetUpdateMessage().(*StreamUpdate_PriceUpdate); ok { + return x.PriceUpdate + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*StreamUpdate) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -1083,6 +1105,7 @@ func (*StreamUpdate) XXX_OneofWrappers() []interface{} { (*StreamUpdate_OrderFill)(nil), (*StreamUpdate_TakerOrder)(nil), (*StreamUpdate_SubaccountUpdate)(nil), + (*StreamUpdate_PriceUpdate)(nil), } } @@ -1096,7 +1119,7 @@ type StreamOrderbookUpdate struct { Snapshot bool `protobuf:"varint,1,opt,name=snapshot,proto3" json:"snapshot,omitempty"` // Orderbook updates for the clob pair. Can contain order place, removals, // or updates. - Updates []types1.OffChainUpdateV1 `protobuf:"bytes,2,rep,name=updates,proto3" json:"updates"` + Updates []types2.OffChainUpdateV1 `protobuf:"bytes,2,rep,name=updates,proto3" json:"updates"` } func (m *StreamOrderbookUpdate) Reset() { *m = StreamOrderbookUpdate{} } @@ -1139,7 +1162,7 @@ func (m *StreamOrderbookUpdate) GetSnapshot() bool { return false } -func (m *StreamOrderbookUpdate) GetUpdates() []types1.OffChainUpdateV1 { +func (m *StreamOrderbookUpdate) GetUpdates() []types2.OffChainUpdateV1 { if m != nil { return m.Updates } @@ -1417,115 +1440,118 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/clob/query.proto", fileDescriptor_3365c195b25c5bc0) } var fileDescriptor_3365c195b25c5bc0 = []byte{ - // 1723 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x58, 0xcf, 0x4f, 0xdc, 0xda, - 0x15, 0x1e, 0x33, 0x84, 0x07, 0x67, 0x02, 0x0f, 0x2e, 0x8f, 0xbc, 0x79, 0x03, 0x19, 0x88, 0xdf, - 0x0b, 0x99, 0xe1, 0xbd, 0x8c, 0x81, 0xf7, 0xf4, 0x94, 0x86, 0x2a, 0x15, 0xd0, 0x12, 0x90, 0x42, - 0x42, 0x0c, 0x49, 0x50, 0x1b, 0xc9, 0xf2, 0xd8, 0x97, 0xc1, 0xc2, 0xf6, 0x1d, 0xec, 0xeb, 0x11, - 0xa8, 0xaa, 0x2a, 0x75, 0x91, 0x4d, 0x5b, 0x29, 0x52, 0x17, 0x5d, 0x54, 0x5d, 0x75, 0xd5, 0x45, - 0xa5, 0x6e, 0xba, 0xec, 0xaf, 0x5d, 0x96, 0x91, 0xba, 0xe9, 0xa2, 0xaa, 0xaa, 0xa4, 0xeb, 0xfe, - 0x0d, 0x95, 0xef, 0xbd, 0x9e, 0xb1, 0xc7, 0xf6, 0x40, 0xd8, 0x80, 0x7d, 0xee, 0x39, 0xe7, 0x7e, - 0xe7, 0x9c, 0xef, 0x9e, 0x7b, 0x3c, 0x70, 0xd3, 0x3c, 0x37, 0xcf, 0xda, 0x1e, 0xa1, 0xc4, 0x20, - 0xb6, 0x62, 0xd8, 0xa4, 0xa9, 0x9c, 0x06, 0xd8, 0x3b, 0x6f, 0x30, 0x19, 0x9a, 0x8a, 0x2f, 0x37, - 0xc2, 0xe5, 0xca, 0x27, 0x2d, 0xd2, 0x22, 0x4c, 0xa4, 0x84, 0x4f, 0x5c, 0xb1, 0x32, 0xd7, 0x22, - 0xa4, 0x65, 0x63, 0x45, 0x6f, 0x5b, 0x8a, 0xee, 0xba, 0x84, 0xea, 0xd4, 0x22, 0xae, 0x2f, 0x56, - 0x97, 0x0c, 0xe2, 0x3b, 0xc4, 0x57, 0x9a, 0xba, 0x8f, 0xb9, 0x7f, 0xa5, 0xb3, 0xd2, 0xc4, 0x54, - 0x5f, 0x51, 0xda, 0x7a, 0xcb, 0x72, 0x99, 0xb2, 0xd0, 0x55, 0xd2, 0x88, 0x9a, 0x36, 0x31, 0x4e, - 0x34, 0x4f, 0xa7, 0x58, 0xb3, 0x2d, 0xc7, 0xa2, 0x9a, 0x41, 0xdc, 0x23, 0xab, 0x25, 0x0c, 0x6e, - 0xa5, 0x0d, 0xc2, 0x3f, 0x5a, 0x5b, 0xb7, 0x3c, 0xa1, 0xb2, 0x9c, 0x56, 0xc1, 0xa7, 0x81, 0x45, - 0xcf, 0x35, 0x6a, 0x61, 0x2f, 0xcb, 0x69, 0x46, 0x5e, 0x88, 0x67, 0xe2, 0xc8, 0xe1, 0x7c, 0x7a, - 0xd9, 0xd1, 0xa9, 0x71, 0x8c, 0xa3, 0x88, 0xbf, 0x4c, 0x2b, 0xd8, 0xd6, 0x69, 0x60, 0x99, 0x3c, - 0x2f, 0xc9, 0xcd, 0x66, 0x33, 0xbc, 0xe1, 0x8e, 0x58, 0x7c, 0x90, 0x58, 0xb4, 0x5c, 0x13, 0x9f, - 0x61, 0x4f, 0x21, 0x47, 0x47, 0x9a, 0x71, 0xac, 0x5b, 0xae, 0x16, 0xb4, 0x4d, 0x9d, 0x62, 0x3f, - 0x2d, 0x11, 0xf6, 0xb5, 0x84, 0xbd, 0x1f, 0x34, 0x75, 0xc3, 0x20, 0x81, 0x4b, 0x7d, 0xc5, 0xa7, - 0x1e, 0xd6, 0x1d, 0xcb, 0x8d, 0x60, 0xd4, 0xf3, 0x35, 0xbb, 0xcf, 0x5c, 0x55, 0xae, 0xc3, 0xa7, - 0x4f, 0xc3, 0x32, 0x3e, 0xc4, 0x74, 0xd3, 0x26, 0xcd, 0x3d, 0xdd, 0xf2, 0x54, 0x7c, 0x1a, 0x60, - 0x9f, 0xa2, 0x09, 0x18, 0xb2, 0xcc, 0xb2, 0xb4, 0x20, 0xd5, 0xc6, 0xd5, 0x21, 0xcb, 0x94, 0x5f, - 0xc0, 0x0c, 0x53, 0xed, 0xe9, 0xf9, 0x6d, 0xe2, 0xfa, 0x18, 0x3d, 0x80, 0xb1, 0x6e, 0x9d, 0x98, - 0x7e, 0x69, 0x75, 0xb6, 0x91, 0xe2, 0x5b, 0x23, 0xb2, 0xdb, 0x18, 0x7e, 0xf3, 0xef, 0xf9, 0x82, - 0x3a, 0x6a, 0x88, 0x77, 0x59, 0x17, 0x18, 0xd6, 0x6d, 0xbb, 0x1f, 0xc3, 0x16, 0x40, 0x8f, 0x57, - 0xc2, 0xf7, 0x62, 0x83, 0x93, 0xb0, 0x11, 0x92, 0xb0, 0xc1, 0x49, 0x2e, 0x48, 0xd8, 0xd8, 0xd3, - 0x5b, 0x58, 0xd8, 0xaa, 0x31, 0x4b, 0xf9, 0x77, 0x12, 0x94, 0x13, 0xe0, 0xd7, 0x6d, 0x3b, 0x0f, - 0x7f, 0xf1, 0x03, 0xf1, 0xa3, 0x87, 0x09, 0x90, 0x43, 0x0c, 0xe4, 0x9d, 0x0b, 0x41, 0xf2, 0xcd, - 0x13, 0x28, 0xff, 0x25, 0xc1, 0xfc, 0x2e, 0xee, 0x3c, 0x26, 0x26, 0x3e, 0x20, 0xe1, 0xdf, 0x4d, - 0xdd, 0x36, 0x02, 0x9b, 0x2d, 0x46, 0x19, 0x79, 0x09, 0x37, 0xf8, 0x29, 0x6a, 0x7b, 0xa4, 0x4d, - 0x7c, 0xec, 0x69, 0x82, 0xaf, 0xdd, 0xec, 0xa4, 0x91, 0x3f, 0xd7, 0xed, 0x90, 0xaf, 0xc4, 0xdb, - 0xc5, 0x9d, 0x5d, 0xae, 0xad, 0x7e, 0xc2, 0xbc, 0xec, 0x09, 0x27, 0x42, 0x8a, 0x7e, 0x04, 0x33, - 0x9d, 0x48, 0x59, 0x73, 0x70, 0x47, 0x73, 0x30, 0xf5, 0x2c, 0xc3, 0xef, 0x46, 0x95, 0x76, 0x9e, - 0x00, 0xbc, 0xcb, 0xd5, 0xd5, 0xe9, 0x4e, 0x7c, 0x4b, 0x2e, 0x94, 0xff, 0x27, 0xc1, 0x42, 0x7e, - 0x78, 0xa2, 0x18, 0x2d, 0xf8, 0xc8, 0xc3, 0x7e, 0x60, 0x53, 0x5f, 0x94, 0xe2, 0xe1, 0x45, 0x7b, - 0x66, 0x78, 0x09, 0x15, 0xd6, 0x5d, 0xf3, 0x39, 0xb1, 0x03, 0x07, 0xef, 0x61, 0x2f, 0x2c, 0x9d, - 0x28, 0x5b, 0xe4, 0xbd, 0xa2, 0xc3, 0x74, 0x86, 0x16, 0x5a, 0x80, 0xeb, 0x5d, 0x32, 0x68, 0x5d, - 0xfe, 0x43, 0x54, 0xec, 0x1d, 0x13, 0x4d, 0x42, 0xd1, 0xc1, 0x1d, 0x96, 0x91, 0x21, 0x35, 0x7c, - 0x44, 0x37, 0x60, 0xa4, 0xc3, 0x9c, 0x94, 0x8b, 0x0b, 0x52, 0x6d, 0x58, 0x15, 0x6f, 0xf2, 0x12, - 0xd4, 0x18, 0xe9, 0x7e, 0xc0, 0x5a, 0xd4, 0x81, 0x85, 0xbd, 0x47, 0x61, 0x83, 0xda, 0x64, 0x2d, - 0x23, 0xf0, 0xe2, 0x75, 0x95, 0x7f, 0x23, 0x41, 0xfd, 0x12, 0xca, 0x22, 0x4b, 0x2e, 0x94, 0xf3, - 0xfa, 0x9e, 0xe0, 0x81, 0x92, 0x91, 0xb6, 0x41, 0xae, 0x45, 0x7a, 0x66, 0x70, 0x96, 0x8e, 0x5c, - 0x87, 0x3b, 0x0c, 0xdc, 0x46, 0x48, 0x1a, 0x55, 0xa7, 0x38, 0x3f, 0x90, 0x5f, 0x4b, 0x22, 0xea, - 0x81, 0xba, 0x22, 0x8e, 0x13, 0xf8, 0x34, 0xe7, 0x4e, 0x10, 0x61, 0x34, 0x32, 0xc2, 0x18, 0xe0, - 0x58, 0x44, 0xc1, 0xc9, 0xdd, 0xa7, 0x22, 0x1f, 0xc2, 0x67, 0x0c, 0xd8, 0x3e, 0xd5, 0x29, 0x3e, - 0x0a, 0xec, 0x27, 0xe1, 0x3d, 0x10, 0x9d, 0xab, 0x35, 0x18, 0x65, 0xf7, 0x42, 0x54, 0xf3, 0xd2, - 0x6a, 0x25, 0x63, 0x6b, 0x66, 0xb2, 0x63, 0x46, 0x5c, 0x22, 0xfc, 0x55, 0xfe, 0x93, 0x04, 0x95, - 0x2c, 0xd7, 0x22, 0xca, 0x43, 0xf8, 0x98, 0xfb, 0x6e, 0xdb, 0xba, 0x81, 0x1d, 0xec, 0x52, 0xb1, - 0x45, 0x3d, 0x63, 0x8b, 0x47, 0xc4, 0x6d, 0x1d, 0x60, 0xcf, 0x61, 0x2e, 0xf6, 0x22, 0x03, 0xb1, - 0xe3, 0x04, 0x49, 0x48, 0xd1, 0x3c, 0x94, 0x8e, 0x2c, 0xdb, 0xd6, 0x74, 0x27, 0xec, 0xe9, 0x8c, - 0x93, 0xc3, 0x2a, 0x84, 0xa2, 0x75, 0x26, 0x41, 0x73, 0x30, 0x46, 0x3d, 0xab, 0xd5, 0xc2, 0x1e, - 0x36, 0x19, 0x3b, 0x47, 0xd5, 0x9e, 0x40, 0xbe, 0x03, 0xb7, 0x19, 0xec, 0x47, 0xb1, 0x1b, 0x2d, - 0xb3, 0xa8, 0xaf, 0x24, 0x58, 0xbc, 0x48, 0x53, 0x04, 0xfb, 0x12, 0xa6, 0x33, 0x2e, 0x48, 0x11, - 0xf0, 0xed, 0xac, 0x80, 0x53, 0x2e, 0x45, 0xb0, 0xc8, 0x4e, 0xad, 0xc8, 0x73, 0x22, 0xd1, 0x8f, - 0xf1, 0x59, 0xf7, 0xc2, 0xda, 0x31, 0x23, 0x98, 0xdb, 0x30, 0x9b, 0xb9, 0x2a, 0xa0, 0xd5, 0x61, - 0xca, 0xc5, 0x67, 0x54, 0xcb, 0x38, 0xe0, 0x13, 0x6e, 0xc2, 0x44, 0x7e, 0x2d, 0xc1, 0xcd, 0x7d, - 0x76, 0xad, 0xb2, 0x3a, 0x34, 0x09, 0x39, 0x79, 0xc6, 0x6f, 0xe3, 0x88, 0x30, 0xe9, 0x46, 0x51, - 0xec, 0x6b, 0x14, 0xbb, 0x30, 0xd1, 0xbb, 0x6f, 0x35, 0xcb, 0x0c, 0xbb, 0x68, 0x31, 0xdd, 0xa2, - 0x63, 0xf7, 0x73, 0x63, 0xbf, 0xfb, 0xbc, 0x63, 0xaa, 0xe3, 0x7e, 0xec, 0xcd, 0x97, 0x75, 0xa8, - 0xe6, 0x21, 0x12, 0xf1, 0x7d, 0x0f, 0x3e, 0x12, 0x23, 0x83, 0xe8, 0x9d, 0xf3, 0x19, 0xe9, 0xe6, - 0x3e, 0xb8, 0x69, 0xc4, 0x63, 0x61, 0x25, 0xff, 0xbe, 0x08, 0xd7, 0xe3, 0xeb, 0xe8, 0x16, 0x5c, - 0xe7, 0xe7, 0xf3, 0x18, 0x5b, 0xad, 0x63, 0x2a, 0x92, 0x55, 0x62, 0xb2, 0x6d, 0x26, 0x42, 0xb3, - 0x30, 0x86, 0xcf, 0xb0, 0xa1, 0x39, 0xc4, 0xc4, 0x8c, 0x80, 0xe3, 0xea, 0x68, 0x28, 0xd8, 0x25, - 0x26, 0x46, 0xcf, 0x60, 0x92, 0x44, 0x68, 0xc5, 0x38, 0xc3, 0x58, 0x58, 0x5a, 0xad, 0xe5, 0x42, - 0xeb, 0x0b, 0x6f, 0xbb, 0xa0, 0x7e, 0x4c, 0x92, 0xa2, 0xf0, 0xc6, 0xe5, 0x07, 0x2a, 0x64, 0x7a, - 0x79, 0x38, 0xf7, 0xe2, 0xeb, 0x73, 0xb8, 0x65, 0xd9, 0xf6, 0x76, 0x41, 0x1d, 0x63, 0xb6, 0xe1, - 0x0b, 0xda, 0x82, 0x12, 0xd5, 0x4f, 0xb0, 0xa7, 0x31, 0x51, 0xf9, 0x1a, 0xf3, 0xf4, 0x79, 0xae, - 0xa7, 0x83, 0x50, 0x97, 0xb9, 0xdb, 0x2e, 0xa8, 0x40, 0xbb, 0x6f, 0x48, 0x83, 0xa9, 0x58, 0xa9, - 0x45, 0xa0, 0x23, 0xcc, 0xdb, 0xf2, 0x80, 0x6a, 0x33, 0xa7, 0xbd, 0x9a, 0x77, 0x03, 0x9e, 0xf4, - 0xfb, 0x64, 0x1b, 0x93, 0x30, 0xc1, 0xbd, 0x6a, 0x0e, 0xf6, 0x7d, 0xbd, 0x85, 0xe5, 0x5f, 0x4a, - 0x30, 0x93, 0x99, 0x30, 0x54, 0x81, 0x51, 0xdf, 0xd5, 0xdb, 0xfe, 0x31, 0xe1, 0x05, 0x1b, 0x55, - 0xbb, 0xef, 0xe8, 0xb0, 0x47, 0x11, 0x4e, 0xc6, 0x7b, 0x49, 0x78, 0x62, 0x2c, 0x6d, 0xa4, 0x87, - 0xd0, 0x27, 0x47, 0x47, 0x9b, 0xa1, 0x80, 0x6f, 0xf2, 0x7c, 0xa5, 0x9f, 0x3b, 0x7f, 0x90, 0x60, - 0x3a, 0x23, 0xdf, 0x68, 0x0d, 0xd8, 0x99, 0xe0, 0x63, 0x8a, 0x68, 0x03, 0x73, 0x39, 0xe3, 0x15, - 0x1b, 0x43, 0x54, 0x36, 0x8d, 0xb1, 0x47, 0xf4, 0x2d, 0x8c, 0xb0, 0xca, 0x44, 0x68, 0xcb, 0x79, - 0x3d, 0x59, 0xa0, 0x11, 0xda, 0x21, 0x6f, 0x63, 0x7d, 0xd1, 0x2f, 0x17, 0x17, 0x8a, 0xb5, 0x61, - 0xb5, 0xd4, 0x6b, 0x8c, 0xbe, 0xfc, 0x6a, 0x08, 0x26, 0xfb, 0xab, 0x8a, 0x96, 0xe1, 0x1a, 0x67, - 0x02, 0xc7, 0x99, 0xbb, 0xdd, 0x76, 0x41, 0xe5, 0x8a, 0xe8, 0x10, 0xa6, 0x62, 0x6d, 0x4a, 0xf0, - 0x68, 0x28, 0xb7, 0xbb, 0xf3, 0x1d, 0x63, 0x2d, 0x2f, 0x72, 0x37, 0x69, 0xf7, 0xc9, 0xd0, 0x0b, - 0x40, 0x31, 0x6e, 0x6a, 0x3e, 0xd5, 0x69, 0xe0, 0x8b, 0xd3, 0x53, 0xbf, 0x04, 0x45, 0xf7, 0x99, - 0x81, 0x3a, 0x49, 0xfb, 0x24, 0x1b, 0xe3, 0x09, 0xd2, 0xcb, 0x7f, 0x94, 0xe0, 0x46, 0xb6, 0x6d, - 0x98, 0xc6, 0xc4, 0xe6, 0xe2, 0xf8, 0x93, 0x98, 0xca, 0x5d, 0x40, 0x1e, 0x76, 0x74, 0xcb, 0xb5, - 0xdc, 0x96, 0x76, 0x1a, 0xe8, 0x2e, 0x0d, 0x1c, 0x5f, 0x5c, 0x44, 0x53, 0xdd, 0x95, 0xa7, 0x62, - 0x01, 0x7d, 0x1f, 0xaa, 0xa4, 0x4d, 0x2d, 0xc7, 0xf2, 0xa9, 0x65, 0xe8, 0xb6, 0x7d, 0xce, 0x8e, - 0x30, 0x36, 0x7b, 0xa6, 0x7c, 0x84, 0x9a, 0x4b, 0x6a, 0x6d, 0x31, 0xa5, 0xc8, 0xcb, 0xea, 0x5f, - 0x4a, 0x70, 0x8d, 0x35, 0x7a, 0xf4, 0x73, 0x09, 0x46, 0xa3, 0xb6, 0x8d, 0x96, 0x32, 0xb2, 0x92, - 0xf3, 0x75, 0x53, 0xa9, 0xe5, 0xe9, 0xf6, 0x7f, 0xde, 0xc8, 0xf5, 0x9f, 0xfd, 0xe3, 0xbf, 0xbf, - 0x1a, 0xfa, 0x1c, 0xdd, 0x52, 0x06, 0x7c, 0x9f, 0x2a, 0x3f, 0xb6, 0xcc, 0x9f, 0xa0, 0x5f, 0x48, - 0x50, 0x8a, 0x7d, 0x61, 0xe4, 0x03, 0x4a, 0x7f, 0xea, 0x54, 0xbe, 0xbc, 0x08, 0x50, 0xec, 0x93, - 0x45, 0xfe, 0x82, 0x61, 0xaa, 0xa2, 0xb9, 0x41, 0x98, 0xd0, 0x5f, 0x25, 0x28, 0xe7, 0x8d, 0xca, - 0x68, 0xf5, 0x83, 0xe6, 0x6a, 0x8e, 0xf1, 0xeb, 0x2b, 0xcc, 0xe2, 0xf2, 0x7d, 0x86, 0xf5, 0x9b, - 0xfb, 0xd2, 0x92, 0xac, 0x28, 0x99, 0x1f, 0xc8, 0x9a, 0x4b, 0x4c, 0xac, 0x51, 0xc2, 0xff, 0x1b, - 0x31, 0x90, 0x7f, 0x97, 0x60, 0x6e, 0xd0, 0xd4, 0x8a, 0xd6, 0xf2, 0xb2, 0x76, 0x89, 0x99, 0xbb, - 0xf2, 0xdd, 0xab, 0x19, 0x8b, 0xb8, 0x16, 0x59, 0x5c, 0x0b, 0xa8, 0xaa, 0x0c, 0xfc, 0x51, 0x02, - 0xfd, 0x59, 0x82, 0xd9, 0x01, 0x23, 0x2b, 0xba, 0x9f, 0x87, 0xe2, 0xe2, 0x61, 0xbb, 0xb2, 0x76, - 0x25, 0x5b, 0x11, 0xc0, 0x6d, 0x16, 0xc0, 0x3c, 0xba, 0x39, 0xf0, 0x97, 0x1a, 0xf4, 0x37, 0x09, - 0x3e, 0xcb, 0x1d, 0xfb, 0xd0, 0xbd, 0x3c, 0x04, 0x17, 0xcd, 0x94, 0x95, 0xef, 0x5c, 0xc1, 0x52, - 0x20, 0x6f, 0x30, 0xe4, 0x35, 0xb4, 0xa8, 0x5c, 0xea, 0xd7, 0x19, 0xe4, 0xc2, 0x78, 0x62, 0x32, - 0x47, 0x5f, 0xe5, 0xed, 0x9d, 0xf5, 0x6d, 0x50, 0xb9, 0x7b, 0x49, 0x6d, 0x81, 0xae, 0x80, 0x7e, - 0x2b, 0xc1, 0x44, 0x72, 0x06, 0x45, 0xb9, 0x3e, 0x32, 0x27, 0xd9, 0x4a, 0xe3, 0xb2, 0xea, 0x62, - 0xcf, 0xaf, 0x58, 0x46, 0x16, 0xd1, 0x17, 0x19, 0x19, 0x49, 0xcd, 0xbc, 0xe8, 0xa7, 0x51, 0xc7, - 0xef, 0x1f, 0x25, 0xd1, 0xf2, 0x65, 0xc7, 0xb2, 0x68, 0x0e, 0xae, 0xac, 0x7c, 0x80, 0x05, 0x07, - 0xbb, 0x2c, 0x6d, 0xec, 0xbd, 0x79, 0x57, 0x95, 0xde, 0xbe, 0xab, 0x4a, 0xff, 0x79, 0x57, 0x95, - 0x5e, 0xbf, 0xaf, 0x16, 0xde, 0xbe, 0xaf, 0x16, 0xfe, 0xf9, 0xbe, 0x5a, 0xf8, 0xe1, 0xb7, 0x2d, - 0x8b, 0x1e, 0x07, 0xcd, 0x86, 0x41, 0x9c, 0x64, 0x28, 0x9d, 0x6f, 0xee, 0xb2, 0x81, 0x44, 0xe9, - 0x4a, 0xce, 0x78, 0x78, 0xf4, 0xbc, 0x8d, 0xfd, 0xe6, 0x08, 0x13, 0x7f, 0xfd, 0xff, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x73, 0xde, 0x4d, 0xf8, 0x08, 0x15, 0x00, 0x00, + // 1770 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x58, 0x4d, 0x6c, 0xdc, 0xc6, + 0x15, 0x5e, 0x4a, 0xb2, 0x2d, 0xbd, 0xb5, 0x14, 0x69, 0x1c, 0x3b, 0x9b, 0x95, 0xbc, 0x92, 0xe9, + 0x58, 0xd6, 0x3a, 0xf1, 0x52, 0x56, 0x82, 0x20, 0xb5, 0x8b, 0x14, 0x96, 0x5b, 0x59, 0x42, 0xad, + 0x44, 0xa1, 0x14, 0x47, 0x68, 0x03, 0x10, 0xb3, 0xe4, 0x68, 0x35, 0x10, 0xc9, 0x59, 0x91, 0xc3, + 0x85, 0x84, 0xa2, 0x28, 0xd0, 0x43, 0x2e, 0x6d, 0x81, 0x02, 0x3d, 0xf4, 0x50, 0xf4, 0xd4, 0x73, + 0xd1, 0x5e, 0x7a, 0xec, 0xdf, 0x2d, 0x47, 0x03, 0xbd, 0xf4, 0x50, 0x14, 0x85, 0xdd, 0x73, 0x8f, + 0x3d, 0x07, 0x9c, 0x19, 0xee, 0x92, 0x4b, 0x72, 0x25, 0xeb, 0x22, 0x71, 0xde, 0xbc, 0xf7, 0xcd, + 0xf7, 0x66, 0xde, 0xbc, 0xf7, 0x66, 0xe1, 0xa6, 0x73, 0xea, 0x9c, 0x74, 0x03, 0xc6, 0x99, 0xcd, + 0x5c, 0xc3, 0x76, 0x59, 0xdb, 0x38, 0x8e, 0x48, 0x70, 0xda, 0x12, 0x32, 0x34, 0x97, 0x9e, 0x6e, + 0xc5, 0xd3, 0xf5, 0x37, 0x3b, 0xac, 0xc3, 0x84, 0xc8, 0x88, 0xbf, 0xa4, 0x62, 0x7d, 0xa1, 0xc3, + 0x58, 0xc7, 0x25, 0x06, 0xee, 0x52, 0x03, 0xfb, 0x3e, 0xe3, 0x98, 0x53, 0xe6, 0x87, 0x6a, 0xf6, + 0x9e, 0xcd, 0x42, 0x8f, 0x85, 0x46, 0x1b, 0x87, 0x44, 0xe2, 0x1b, 0xbd, 0x07, 0x6d, 0xc2, 0xf1, + 0x03, 0xa3, 0x8b, 0x3b, 0xd4, 0x17, 0xca, 0x4a, 0xd7, 0xc8, 0x33, 0x6a, 0xbb, 0xcc, 0x3e, 0xb2, + 0x02, 0xcc, 0x89, 0xe5, 0x52, 0x8f, 0x72, 0xcb, 0x66, 0xfe, 0x01, 0xed, 0x28, 0x83, 0x5b, 0x79, + 0x83, 0xf8, 0x8f, 0xd5, 0xc5, 0x34, 0x50, 0x2a, 0xab, 0x79, 0x15, 0x72, 0x1c, 0x51, 0x7e, 0x6a, + 0x71, 0x4a, 0x82, 0x22, 0xd0, 0x82, 0x7d, 0x61, 0x81, 0x43, 0x12, 0xc0, 0xc5, 0xfc, 0xb4, 0x87, + 0xb9, 0x7d, 0x48, 0x12, 0x8f, 0xdf, 0xcd, 0x2b, 0xb8, 0xf4, 0x38, 0xa2, 0x8e, 0xdc, 0x97, 0xec, + 0x62, 0xf3, 0x05, 0x68, 0xa4, 0xa7, 0x26, 0x3f, 0xce, 0x4c, 0x52, 0xdf, 0x21, 0x27, 0x24, 0x30, + 0xd8, 0xc1, 0x81, 0x65, 0x1f, 0x62, 0xea, 0x5b, 0x51, 0xd7, 0xc1, 0x9c, 0x84, 0x79, 0x89, 0xb2, + 0x5f, 0xc9, 0xd8, 0x87, 0x51, 0x1b, 0xdb, 0x36, 0x8b, 0x7c, 0x1e, 0x1a, 0x21, 0x0f, 0x08, 0xf6, + 0xa8, 0x9f, 0xd0, 0x68, 0x96, 0x6b, 0xf6, 0xbf, 0x95, 0xea, 0xed, 0x8c, 0x6a, 0x37, 0xa0, 0x36, + 0xc9, 0xe1, 0xe9, 0x4d, 0x78, 0xeb, 0xb3, 0xf8, 0xac, 0x9f, 0x12, 0xfe, 0xc4, 0x65, 0xed, 0x1d, + 0x4c, 0x03, 0x93, 0x1c, 0x47, 0x24, 0xe4, 0x68, 0x06, 0xc6, 0xa8, 0x53, 0xd3, 0x96, 0xb4, 0x95, + 0x69, 0x73, 0x8c, 0x3a, 0xfa, 0x17, 0x70, 0x5d, 0xa8, 0x0e, 0xf4, 0xc2, 0x2e, 0xf3, 0x43, 0x82, + 0x3e, 0x86, 0xa9, 0xfe, 0x61, 0x0a, 0xfd, 0xea, 0xda, 0x7c, 0x2b, 0x17, 0x94, 0xad, 0xc4, 0x6e, + 0x7d, 0xe2, 0xeb, 0x7f, 0x2f, 0x56, 0xcc, 0x49, 0x5b, 0x8d, 0x75, 0xac, 0x38, 0x3c, 0x76, 0xdd, + 0x61, 0x0e, 0x1b, 0x00, 0x83, 0xe0, 0x53, 0xd8, 0xcb, 0x2d, 0x19, 0xa9, 0xad, 0x38, 0x52, 0x5b, + 0xf2, 0x26, 0xa8, 0x48, 0x6d, 0xed, 0xe0, 0x0e, 0x51, 0xb6, 0x66, 0xca, 0x52, 0xff, 0x9d, 0x06, + 0xb5, 0x0c, 0xf9, 0xc7, 0xae, 0x5b, 0xc6, 0x7f, 0xfc, 0x35, 0xf9, 0xa3, 0xa7, 0x19, 0x92, 0x63, + 0x82, 0xe4, 0xdd, 0x33, 0x49, 0xca, 0xc5, 0x33, 0x2c, 0xff, 0xa5, 0xc1, 0xe2, 0x36, 0xe9, 0x7d, + 0xc2, 0x1c, 0xb2, 0xc7, 0xe2, 0xbf, 0x4f, 0xb0, 0x6b, 0x47, 0xae, 0x98, 0x4c, 0x76, 0xe4, 0x4b, + 0xb8, 0x21, 0xaf, 0x5a, 0x37, 0x60, 0x5d, 0x16, 0x92, 0xc0, 0x52, 0x41, 0xdd, 0xdf, 0x9d, 0x3c, + 0xf3, 0xe7, 0xd8, 0x8d, 0x83, 0x9a, 0x05, 0xdb, 0xa4, 0xb7, 0x2d, 0xb5, 0xcd, 0x37, 0x05, 0xca, + 0x8e, 0x02, 0x51, 0x52, 0xf4, 0x43, 0xb8, 0xde, 0x4b, 0x94, 0x2d, 0x8f, 0xf4, 0x2c, 0x8f, 0xf0, + 0x80, 0xda, 0x61, 0xdf, 0xab, 0x3c, 0x78, 0x86, 0xf0, 0xb6, 0x54, 0x37, 0xaf, 0xf5, 0xd2, 0x4b, + 0x4a, 0xa1, 0xfe, 0x3f, 0x0d, 0x96, 0xca, 0xdd, 0x53, 0x87, 0xd1, 0x81, 0x2b, 0x01, 0x09, 0x23, + 0x97, 0x87, 0xea, 0x28, 0x9e, 0x9e, 0xb5, 0x66, 0x01, 0x4a, 0xac, 0xf0, 0xd8, 0x77, 0x9e, 0x33, + 0x37, 0xf2, 0xc8, 0x0e, 0x09, 0xe2, 0xa3, 0x53, 0xc7, 0x96, 0xa0, 0xd7, 0x31, 0x5c, 0x2b, 0xd0, + 0x42, 0x4b, 0x70, 0xb5, 0x1f, 0x0c, 0x56, 0x3f, 0xfe, 0x21, 0x39, 0xec, 0x2d, 0x07, 0xcd, 0xc2, + 0xb8, 0x47, 0x7a, 0x62, 0x47, 0xc6, 0xcc, 0xf8, 0x13, 0xdd, 0x80, 0xcb, 0x3d, 0x01, 0x52, 0x1b, + 0x5f, 0xd2, 0x56, 0x26, 0x4c, 0x35, 0xd2, 0xef, 0xc1, 0x8a, 0x08, 0xba, 0xef, 0x89, 0x3c, 0xb6, + 0x47, 0x49, 0xf0, 0x2c, 0xce, 0x62, 0x4f, 0x44, 0x5e, 0x89, 0x82, 0xf4, 0xb9, 0xea, 0xbf, 0xd1, + 0xa0, 0x79, 0x0e, 0x65, 0xb5, 0x4b, 0x3e, 0xd4, 0xca, 0x92, 0xa3, 0x8a, 0x03, 0xa3, 0x60, 0xdb, + 0x46, 0x41, 0xab, 0xed, 0xb9, 0x4e, 0x8a, 0x74, 0xf4, 0x26, 0xdc, 0x15, 0xe4, 0xd6, 0xe3, 0xa0, + 0x31, 0x31, 0x27, 0xe5, 0x8e, 0xfc, 0x5a, 0x53, 0x5e, 0x8f, 0xd4, 0x55, 0x7e, 0x1c, 0xc1, 0x5b, + 0x25, 0x85, 0x43, 0xb9, 0xd1, 0x2a, 0x70, 0x63, 0x04, 0xb0, 0xf2, 0x42, 0x06, 0xf7, 0x90, 0x8a, + 0xbe, 0x0f, 0x6f, 0x0b, 0x62, 0xbb, 0x1c, 0x73, 0x72, 0x10, 0xb9, 0x9f, 0xc6, 0xc5, 0x22, 0xb9, + 0x57, 0x8f, 0x60, 0x52, 0x14, 0x8f, 0xe4, 0xcc, 0xab, 0x6b, 0xf5, 0x82, 0xa5, 0x85, 0xc9, 0x96, + 0x93, 0xc4, 0x12, 0x93, 0x43, 0xfd, 0x4f, 0x1a, 0xd4, 0x8b, 0xa0, 0x95, 0x97, 0xfb, 0xf0, 0x86, + 0xc4, 0xee, 0xba, 0xd8, 0x26, 0x1e, 0xf1, 0xb9, 0x5a, 0xa2, 0x59, 0xb0, 0xc4, 0x33, 0xe6, 0x77, + 0xf6, 0x48, 0xe0, 0x09, 0x88, 0x9d, 0xc4, 0x40, 0xad, 0x38, 0xc3, 0x32, 0x52, 0xb4, 0x08, 0xd5, + 0x03, 0xea, 0xba, 0x16, 0xf6, 0xe2, 0xc4, 0x2f, 0x62, 0x72, 0xc2, 0x84, 0x58, 0xf4, 0x58, 0x48, + 0xd0, 0x02, 0x4c, 0xf1, 0x80, 0x76, 0x3a, 0x24, 0x20, 0x8e, 0x88, 0xce, 0x49, 0x73, 0x20, 0xd0, + 0xef, 0xc2, 0x1d, 0x41, 0xfb, 0x59, 0xaa, 0xec, 0x15, 0x1e, 0xea, 0x57, 0x1a, 0x2c, 0x9f, 0xa5, + 0xa9, 0x9c, 0xfd, 0x12, 0xae, 0x15, 0x54, 0x51, 0xe5, 0xf0, 0x9d, 0x22, 0x87, 0x73, 0x90, 0xca, + 0x59, 0xe4, 0xe6, 0x66, 0xf4, 0x05, 0xb5, 0xd1, 0x9f, 0x90, 0x93, 0x7e, 0xc1, 0xda, 0x72, 0x12, + 0x9a, 0x9b, 0x30, 0x5f, 0x38, 0xab, 0xa8, 0x35, 0x61, 0xce, 0x27, 0x27, 0xdc, 0x2a, 0xb8, 0xe0, + 0x33, 0x7e, 0xc6, 0x44, 0xff, 0x83, 0x06, 0x37, 0x77, 0x45, 0xad, 0x14, 0xe7, 0xd0, 0x66, 0xec, + 0xe8, 0x73, 0x59, 0xb2, 0x93, 0x80, 0xc9, 0x27, 0x8a, 0xf1, 0xa1, 0x44, 0xb1, 0x0d, 0x33, 0x83, + 0xa2, 0x6c, 0x51, 0x27, 0xce, 0xa2, 0xe3, 0xf9, 0x14, 0x9d, 0x2a, 0xe2, 0xad, 0xdd, 0xfe, 0xf7, + 0x96, 0x63, 0x4e, 0x87, 0xa9, 0x51, 0x88, 0x6e, 0x02, 0x78, 0x38, 0x38, 0x22, 0x12, 0x6a, 0x5c, + 0x2c, 0x37, 0x25, 0x25, 0x5b, 0x4e, 0xa8, 0x63, 0x68, 0x94, 0x11, 0x56, 0xee, 0x7f, 0x07, 0xae, + 0xa8, 0xb6, 0x43, 0xa5, 0xd6, 0xc5, 0x82, 0xd3, 0x90, 0x18, 0xd2, 0x34, 0x09, 0x73, 0x65, 0xa5, + 0xff, 0x7f, 0x1c, 0xae, 0xa6, 0xe7, 0xd1, 0x2d, 0xb8, 0x2a, 0xaf, 0xef, 0x21, 0xa1, 0x9d, 0x43, + 0xae, 0xf6, 0xb2, 0x2a, 0x64, 0x9b, 0x42, 0x84, 0xe6, 0x61, 0x8a, 0x9c, 0x10, 0xdb, 0xf2, 0x98, + 0x43, 0x44, 0x7c, 0x4e, 0x9b, 0x93, 0xb1, 0x60, 0x9b, 0x39, 0x04, 0x7d, 0x0e, 0xb3, 0x2c, 0x61, + 0xab, 0x5a, 0x22, 0x11, 0xa4, 0xd5, 0xb5, 0x95, 0x52, 0x6a, 0x43, 0xee, 0x6d, 0x56, 0xcc, 0x37, + 0x58, 0x56, 0x14, 0x17, 0x64, 0x79, 0xdf, 0xe2, 0x8b, 0x50, 0x9b, 0x28, 0xad, 0x8b, 0x43, 0x80, + 0x1b, 0xd4, 0x75, 0x37, 0x2b, 0xe6, 0x94, 0xb0, 0x8d, 0x07, 0x68, 0x03, 0xaa, 0x1c, 0x1f, 0x91, + 0xc0, 0x12, 0xa2, 0xda, 0x25, 0x81, 0x74, 0xbb, 0x14, 0x69, 0x2f, 0xd6, 0x15, 0x70, 0x9b, 0x15, + 0x13, 0x78, 0x7f, 0x84, 0x2c, 0x98, 0x4b, 0x45, 0x82, 0x72, 0xf4, 0xb2, 0x40, 0x5b, 0x1d, 0x11, + 0x0c, 0x02, 0x74, 0x10, 0x12, 0x7d, 0x87, 0x67, 0xc3, 0x21, 0x19, 0xfa, 0x3e, 0x5c, 0x15, 0x0d, + 0x5e, 0x82, 0x7d, 0xa5, 0xc8, 0x67, 0xd9, 0x02, 0x2a, 0xd8, 0x9d, 0x78, 0xd0, 0x47, 0xac, 0x76, + 0x07, 0xc3, 0xf5, 0x59, 0x98, 0x91, 0x30, 0x96, 0x47, 0xc2, 0x10, 0x77, 0x88, 0xfe, 0x0b, 0x0d, + 0xae, 0x17, 0xee, 0x3e, 0xaa, 0xc3, 0x64, 0xe8, 0xe3, 0x6e, 0x78, 0xc8, 0xe4, 0xe9, 0x4f, 0x9a, + 0xfd, 0x31, 0xda, 0x1f, 0xc4, 0x9b, 0x0c, 0xfc, 0x8f, 0xb2, 0x7c, 0x54, 0x9f, 0xdc, 0xca, 0x77, + 0xc5, 0x9f, 0x1e, 0x1c, 0x3c, 0x89, 0x05, 0x72, 0x91, 0xe7, 0x0f, 0x86, 0x03, 0xf1, 0xf7, 0x1a, + 0x5c, 0x2b, 0x38, 0x3c, 0xf4, 0x08, 0xc4, 0xfd, 0x93, 0x2d, 0x91, 0x4a, 0x39, 0x0b, 0x25, 0xad, + 0x9c, 0x68, 0x79, 0x4c, 0xd1, 0xf9, 0x89, 0x4f, 0xf4, 0x21, 0x5c, 0x16, 0xc7, 0x9c, 0xb0, 0xad, + 0x95, 0xe5, 0x7f, 0xc5, 0x46, 0x69, 0xc7, 0x97, 0x20, 0x95, 0x83, 0xe5, 0xcd, 0x9c, 0x30, 0xab, + 0x83, 0x24, 0x1c, 0xea, 0x5f, 0x8d, 0xc1, 0xec, 0x70, 0x88, 0xa0, 0x55, 0xb8, 0x24, 0xc3, 0x4a, + 0xf2, 0x2c, 0x5d, 0x6e, 0xb3, 0x62, 0x4a, 0x45, 0xb4, 0x0f, 0x73, 0xa9, 0x94, 0xa8, 0x82, 0x72, + 0xac, 0xb4, 0x92, 0xc8, 0x15, 0x53, 0xe9, 0x35, 0x81, 0x9b, 0x75, 0x87, 0x64, 0xe8, 0x0b, 0x40, + 0xa9, 0x40, 0xb7, 0x42, 0x8e, 0x79, 0x14, 0xaa, 0xab, 0xd8, 0x3c, 0x47, 0xbc, 0xef, 0x0a, 0x03, + 0x73, 0x96, 0x0f, 0x49, 0xd6, 0xa7, 0x33, 0x37, 0x48, 0xff, 0xa3, 0x06, 0x37, 0x8a, 0x6d, 0xe3, + 0x6d, 0xcc, 0x2c, 0xae, 0x72, 0x09, 0x4b, 0xa9, 0xdc, 0x07, 0x14, 0x10, 0x0f, 0x53, 0x9f, 0xfa, + 0x1d, 0xeb, 0x38, 0xc2, 0x3e, 0x8f, 0xbc, 0x50, 0x15, 0xbd, 0xb9, 0xfe, 0xcc, 0x67, 0x6a, 0x02, + 0x7d, 0x17, 0x1a, 0xac, 0xcb, 0xa9, 0x47, 0x43, 0x4e, 0x6d, 0xec, 0xba, 0xa7, 0x22, 0x1f, 0x10, + 0x67, 0x60, 0x2a, 0xdb, 0xb5, 0x85, 0xac, 0xd6, 0x86, 0x50, 0x4a, 0x50, 0xd6, 0xfe, 0x52, 0x85, + 0x4b, 0xa2, 0xa8, 0xa0, 0x9f, 0x69, 0x30, 0x99, 0x94, 0x08, 0x74, 0xaf, 0x60, 0x57, 0x4a, 0x5e, + 0x52, 0xf5, 0x95, 0x32, 0xdd, 0xe1, 0xa7, 0x94, 0xde, 0xfc, 0xe9, 0x3f, 0xfe, 0xfb, 0xab, 0xb1, + 0xdb, 0xe8, 0x96, 0x31, 0xe2, 0xc1, 0x6c, 0xfc, 0x88, 0x3a, 0x3f, 0x46, 0x3f, 0xd7, 0xa0, 0x9a, + 0x7a, 0xcd, 0x94, 0x13, 0xca, 0x3f, 0xab, 0xea, 0xef, 0x9e, 0x45, 0x28, 0xf5, 0x3c, 0xd2, 0xdf, + 0x11, 0x9c, 0x1a, 0x68, 0x61, 0x14, 0x27, 0xf4, 0x57, 0x0d, 0x6a, 0x65, 0x6d, 0x39, 0x5a, 0x7b, + 0xad, 0x1e, 0x5e, 0x72, 0x7c, 0xff, 0x02, 0x7d, 0xbf, 0xfe, 0x50, 0x70, 0xfd, 0xe0, 0xa1, 0x76, + 0x4f, 0x37, 0x8c, 0xc2, 0x17, 0xbb, 0xe5, 0x33, 0x87, 0x58, 0x9c, 0xc9, 0xff, 0x76, 0x8a, 0xe4, + 0xdf, 0x35, 0x58, 0x18, 0xd5, 0x21, 0xa3, 0x47, 0x65, 0xbb, 0x76, 0x8e, 0xfe, 0xbe, 0xfe, 0xed, + 0x8b, 0x19, 0x2b, 0xbf, 0x96, 0x85, 0x5f, 0x4b, 0xa8, 0x61, 0x8c, 0xfc, 0x95, 0x04, 0xfd, 0x59, + 0x83, 0xf9, 0x11, 0xed, 0x31, 0x7a, 0x58, 0xc6, 0xe2, 0xec, 0xc6, 0xbe, 0xfe, 0xe8, 0x42, 0xb6, + 0xca, 0x81, 0x3b, 0xc2, 0x81, 0x45, 0x74, 0x73, 0xe4, 0x4f, 0x47, 0xe8, 0x6f, 0x1a, 0xbc, 0x5d, + 0xda, 0x62, 0xa2, 0x8f, 0xca, 0x18, 0x9c, 0xd5, 0xbf, 0xd6, 0xbf, 0x75, 0x01, 0x4b, 0xc5, 0xbc, + 0x25, 0x98, 0xaf, 0xa0, 0x65, 0xe3, 0x5c, 0x3f, 0x17, 0x21, 0x1f, 0xa6, 0x33, 0xaf, 0x00, 0xf4, + 0x5e, 0xd9, 0xda, 0x45, 0xef, 0x90, 0xfa, 0xfd, 0x73, 0x6a, 0x2b, 0x76, 0x15, 0xf4, 0x5b, 0x0d, + 0x66, 0xb2, 0xfd, 0x2e, 0x2a, 0xc5, 0x28, 0xec, 0x9a, 0xeb, 0xad, 0xf3, 0xaa, 0xab, 0x35, 0xdf, + 0x13, 0x3b, 0xb2, 0x8c, 0xde, 0x29, 0xd8, 0x91, 0x5c, 0x7f, 0x8d, 0x7e, 0x92, 0x64, 0xfc, 0xe1, + 0xbe, 0x14, 0xad, 0x9e, 0xb7, 0xc7, 0x4b, 0x7a, 0xee, 0xfa, 0x83, 0xd7, 0xb0, 0x90, 0x64, 0x57, + 0xb5, 0xf5, 0x9d, 0xaf, 0x5f, 0x36, 0xb4, 0x17, 0x2f, 0x1b, 0xda, 0x7f, 0x5e, 0x36, 0xb4, 0x5f, + 0xbe, 0x6a, 0x54, 0x5e, 0xbc, 0x6a, 0x54, 0xfe, 0xf9, 0xaa, 0x51, 0xf9, 0xc1, 0x87, 0x1d, 0xca, + 0x0f, 0xa3, 0x76, 0xcb, 0x66, 0x5e, 0xd6, 0x95, 0xde, 0x07, 0xf7, 0x45, 0x43, 0x62, 0xf4, 0x25, + 0x27, 0xd2, 0x3d, 0x7e, 0xda, 0x25, 0x61, 0xfb, 0xb2, 0x10, 0xbf, 0xff, 0x4d, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x9d, 0x29, 0x28, 0xfb, 0x99, 0x15, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2532,6 +2558,24 @@ func (m *StreamOrderbookUpdatesRequest) MarshalToSizedBuffer(dAtA []byte) (int, _ = i var l int _ = l + if len(m.MarketIds) > 0 { + dAtA12 := make([]byte, len(m.MarketIds)*10) + var j11 int + for _, num := range m.MarketIds { + for num >= 1<<7 { + dAtA12[j11] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j11++ + } + dAtA12[j11] = uint8(num) + j11++ + } + i -= j11 + copy(dAtA[i:], dAtA12[:j11]) + i = encodeVarintQuery(dAtA, i, uint64(j11)) + i-- + dAtA[i] = 0x1a + } if len(m.SubaccountIds) > 0 { for iNdEx := len(m.SubaccountIds) - 1; iNdEx >= 0; iNdEx-- { { @@ -2547,20 +2591,20 @@ func (m *StreamOrderbookUpdatesRequest) MarshalToSizedBuffer(dAtA []byte) (int, } } if len(m.ClobPairId) > 0 { - dAtA12 := make([]byte, len(m.ClobPairId)*10) - var j11 int + dAtA14 := make([]byte, len(m.ClobPairId)*10) + var j13 int for _, num := range m.ClobPairId { for num >= 1<<7 { - dAtA12[j11] = uint8(uint64(num)&0x7f | 0x80) + dAtA14[j13] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j11++ + j13++ } - dAtA12[j11] = uint8(num) - j11++ + dAtA14[j13] = uint8(num) + j13++ } - i -= j11 - copy(dAtA[i:], dAtA12[:j11]) - i = encodeVarintQuery(dAtA, i, uint64(j11)) + i -= j13 + copy(dAtA[i:], dAtA14[:j13]) + i = encodeVarintQuery(dAtA, i, uint64(j13)) i-- dAtA[i] = 0xa } @@ -2730,6 +2774,27 @@ func (m *StreamUpdate_SubaccountUpdate) MarshalToSizedBuffer(dAtA []byte) (int, } return len(dAtA) - i, nil } +func (m *StreamUpdate_PriceUpdate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StreamUpdate_PriceUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.PriceUpdate != nil { + { + size, err := m.PriceUpdate.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + return len(dAtA) - i, nil +} func (m *StreamOrderbookUpdate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2798,20 +2863,20 @@ func (m *StreamOrderbookFill) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if len(m.FillAmounts) > 0 { - dAtA18 := make([]byte, len(m.FillAmounts)*10) - var j17 int + dAtA21 := make([]byte, len(m.FillAmounts)*10) + var j20 int for _, num := range m.FillAmounts { for num >= 1<<7 { - dAtA18[j17] = uint8(uint64(num)&0x7f | 0x80) + dAtA21[j20] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j17++ + j20++ } - dAtA18[j17] = uint8(num) - j17++ + dAtA21[j20] = uint8(num) + j20++ } - i -= j17 - copy(dAtA[i:], dAtA18[:j17]) - i = encodeVarintQuery(dAtA, i, uint64(j17)) + i -= j20 + copy(dAtA[i:], dAtA21[:j20]) + i = encodeVarintQuery(dAtA, i, uint64(j20)) i-- dAtA[i] = 0x1a } @@ -3212,6 +3277,13 @@ func (m *StreamOrderbookUpdatesRequest) Size() (n int) { n += 1 + l + sovQuery(uint64(l)) } } + if len(m.MarketIds) > 0 { + l = 0 + for _, e := range m.MarketIds { + l += sovQuery(uint64(e)) + } + n += 1 + sovQuery(uint64(l)) + l + } return n } @@ -3296,6 +3368,18 @@ func (m *StreamUpdate_SubaccountUpdate) Size() (n int) { } return n } +func (m *StreamUpdate_PriceUpdate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PriceUpdate != nil { + l = m.PriceUpdate.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} func (m *StreamOrderbookUpdate) Size() (n int) { if m == nil { return 0 @@ -4929,6 +5013,82 @@ func (m *StreamOrderbookUpdatesRequest) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType == 0 { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MarketIds = append(m.MarketIds, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.MarketIds) == 0 { + m.MarketIds = make([]uint32, 0, elementCount) + } + for iNdEx < postIndex { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MarketIds = append(m.MarketIds, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field MarketIds", wireType) + } default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) @@ -5241,6 +5401,41 @@ func (m *StreamUpdate) Unmarshal(dAtA []byte) error { } m.UpdateMessage = &StreamUpdate_SubaccountUpdate{v} iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PriceUpdate", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.StreamPriceUpdate{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.UpdateMessage = &StreamUpdate_PriceUpdate{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) @@ -5340,7 +5535,7 @@ func (m *StreamOrderbookUpdate) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Updates = append(m.Updates, types1.OffChainUpdateV1{}) + m.Updates = append(m.Updates, types2.OffChainUpdateV1{}) if err := m.Updates[len(m.Updates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/protocol/x/clob/types/streaming.pb.go b/protocol/x/clob/types/streaming.pb.go index 1f6f552fb3..68bb706ca7 100644 --- a/protocol/x/clob/types/streaming.pb.go +++ b/protocol/x/clob/types/streaming.pb.go @@ -6,6 +6,7 @@ package types import ( fmt "fmt" proto "github.com/cosmos/gogoproto/proto" + types1 "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" types "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" io "io" math "math" @@ -31,6 +32,7 @@ type StagedFinalizeBlockEvent struct { // *StagedFinalizeBlockEvent_OrderFill // *StagedFinalizeBlockEvent_SubaccountUpdate // *StagedFinalizeBlockEvent_OrderbookUpdate + // *StagedFinalizeBlockEvent_PriceUpdate Event isStagedFinalizeBlockEvent_Event `protobuf_oneof:"event"` } @@ -82,10 +84,14 @@ type StagedFinalizeBlockEvent_SubaccountUpdate struct { type StagedFinalizeBlockEvent_OrderbookUpdate struct { OrderbookUpdate *StreamOrderbookUpdate `protobuf:"bytes,3,opt,name=orderbook_update,json=orderbookUpdate,proto3,oneof" json:"orderbook_update,omitempty"` } +type StagedFinalizeBlockEvent_PriceUpdate struct { + PriceUpdate *types1.StreamPriceUpdate `protobuf:"bytes,4,opt,name=price_update,json=priceUpdate,proto3,oneof" json:"price_update,omitempty"` +} func (*StagedFinalizeBlockEvent_OrderFill) isStagedFinalizeBlockEvent_Event() {} func (*StagedFinalizeBlockEvent_SubaccountUpdate) isStagedFinalizeBlockEvent_Event() {} func (*StagedFinalizeBlockEvent_OrderbookUpdate) isStagedFinalizeBlockEvent_Event() {} +func (*StagedFinalizeBlockEvent_PriceUpdate) isStagedFinalizeBlockEvent_Event() {} func (m *StagedFinalizeBlockEvent) GetEvent() isStagedFinalizeBlockEvent_Event { if m != nil { @@ -115,12 +121,20 @@ func (m *StagedFinalizeBlockEvent) GetOrderbookUpdate() *StreamOrderbookUpdate { return nil } +func (m *StagedFinalizeBlockEvent) GetPriceUpdate() *types1.StreamPriceUpdate { + if x, ok := m.GetEvent().(*StagedFinalizeBlockEvent_PriceUpdate); ok { + return x.PriceUpdate + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*StagedFinalizeBlockEvent) XXX_OneofWrappers() []interface{} { return []interface{}{ (*StagedFinalizeBlockEvent_OrderFill)(nil), (*StagedFinalizeBlockEvent_SubaccountUpdate)(nil), (*StagedFinalizeBlockEvent_OrderbookUpdate)(nil), + (*StagedFinalizeBlockEvent_PriceUpdate)(nil), } } @@ -131,26 +145,29 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/clob/streaming.proto", fileDescriptor_cecf6ffcf2554dee) } var fileDescriptor_cecf6ffcf2554dee = []byte{ - // 303 bytes of a gzipped FileDescriptorProto + // 339 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4c, 0xa9, 0x4c, 0xa9, 0x28, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0x4f, 0xce, 0xc9, 0x4f, 0xd2, 0x2f, 0x2e, 0x29, 0x4a, 0x4d, 0xcc, 0xcd, 0xcc, 0x4b, 0xd7, 0x03, 0x8b, 0x0b, 0x09, 0x22, 0x2b, 0xd1, 0x03, 0x29, 0x91, 0xd2, 0x40, 0xd1, 0x55, 0x5c, 0x9a, 0x94, 0x98, 0x9c, 0x9c, 0x5f, 0x9a, 0x57, 0x52, - 0x8c, 0xae, 0x59, 0x4a, 0x16, 0xd3, 0xfc, 0xc2, 0xd2, 0xd4, 0xa2, 0x4a, 0x88, 0xb4, 0xd2, 0x12, - 0x26, 0x2e, 0x89, 0xe0, 0x92, 0xc4, 0xf4, 0xd4, 0x14, 0xb7, 0xcc, 0xbc, 0xc4, 0x9c, 0xcc, 0xaa, - 0x54, 0xa7, 0x9c, 0xfc, 0xe4, 0x6c, 0xd7, 0xb2, 0xd4, 0xbc, 0x12, 0x21, 0x77, 0x2e, 0xae, 0xfc, - 0xa2, 0x94, 0xd4, 0xa2, 0xf8, 0xb4, 0xcc, 0x9c, 0x1c, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, - 0x35, 0x3d, 0x0c, 0xd7, 0xe8, 0x05, 0x83, 0xed, 0xf4, 0x07, 0x29, 0x4d, 0xca, 0xcf, 0xcf, 0x76, - 0xcb, 0xcc, 0xc9, 0xf1, 0x60, 0x08, 0xe2, 0x04, 0xeb, 0x05, 0x71, 0x84, 0xe2, 0xb9, 0x04, 0x11, - 0x6e, 0x8c, 0x2f, 0x2d, 0x48, 0x49, 0x2c, 0x49, 0x95, 0x60, 0x02, 0x9b, 0x67, 0x80, 0x6a, 0x1e, - 0x92, 0x57, 0xa0, 0xc6, 0x06, 0xc3, 0x45, 0x42, 0xc1, 0xfa, 0x3c, 0x18, 0x82, 0x04, 0x8a, 0xd1, - 0xc4, 0x84, 0x42, 0xb9, 0x04, 0xf2, 0x61, 0xd6, 0xc3, 0xcc, 0x67, 0x06, 0x9b, 0xaf, 0x41, 0xd8, - 0xbd, 0x70, 0x73, 0xf9, 0xf3, 0x51, 0x85, 0x9c, 0xd8, 0xb9, 0x58, 0x53, 0x41, 0x21, 0xe1, 0x14, - 0x70, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, - 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x66, 0xe9, 0x99, 0x25, 0x19, - 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x28, 0x41, 0x5d, 0x66, 0xa2, 0x9b, 0x9c, 0x91, 0x98, - 0x99, 0xa7, 0x0f, 0x17, 0xa9, 0x80, 0x04, 0x7f, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0x58, - 0xd8, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0xe1, 0xc0, 0xbc, 0x6c, 0x00, 0x02, 0x00, 0x00, + 0x8c, 0xae, 0x59, 0x4a, 0x19, 0x45, 0x65, 0x41, 0x51, 0x66, 0x72, 0x2a, 0xa6, 0x22, 0x59, 0x4c, + 0x47, 0x14, 0x96, 0xa6, 0x16, 0x55, 0x42, 0xa4, 0x95, 0x3e, 0x32, 0x71, 0x49, 0x04, 0x97, 0x24, + 0xa6, 0xa7, 0xa6, 0xb8, 0x65, 0xe6, 0x25, 0xe6, 0x64, 0x56, 0xa5, 0x3a, 0xe5, 0xe4, 0x27, 0x67, + 0xbb, 0x96, 0xa5, 0xe6, 0x95, 0x08, 0xb9, 0x73, 0x71, 0xe5, 0x17, 0xa5, 0xa4, 0x16, 0xc5, 0xa7, + 0x65, 0xe6, 0xe4, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0xa9, 0xe9, 0x61, 0x38, 0x59, 0x2f, + 0x18, 0x6c, 0xa7, 0x3f, 0x48, 0x69, 0x52, 0x7e, 0x7e, 0xb6, 0x5b, 0x66, 0x4e, 0x8e, 0x07, 0x43, + 0x10, 0x27, 0x58, 0x2f, 0x88, 0x23, 0x14, 0xcf, 0x25, 0x88, 0xf0, 0x48, 0x7c, 0x69, 0x41, 0x4a, + 0x62, 0x49, 0xaa, 0x04, 0x13, 0xd8, 0x3c, 0x03, 0x54, 0xf3, 0x90, 0xfc, 0x0b, 0x35, 0x36, 0x18, + 0x2e, 0x12, 0x0a, 0xd6, 0xe7, 0xc1, 0x10, 0x24, 0x50, 0x8c, 0x26, 0x26, 0x14, 0xca, 0x25, 0x90, + 0x0f, 0xb3, 0x1e, 0x66, 0x3e, 0x33, 0xd8, 0x7c, 0x0d, 0xc2, 0xee, 0x85, 0x9b, 0xcb, 0x9f, 0x8f, + 0x2a, 0x24, 0xe4, 0xcd, 0xc5, 0x03, 0x0e, 0x56, 0x98, 0x91, 0x2c, 0xd8, 0x82, 0x00, 0x12, 0xf0, + 0x50, 0x43, 0x03, 0x40, 0x1c, 0xb8, 0x81, 0xdc, 0x05, 0x08, 0xae, 0x13, 0x3b, 0x17, 0x6b, 0x2a, + 0x28, 0x58, 0x9d, 0x02, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, + 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x2c, + 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x1f, 0x25, 0xde, 0xca, 0x4c, 0x74, + 0x93, 0x33, 0x12, 0x33, 0xf3, 0xf4, 0xe1, 0x22, 0x15, 0x90, 0xb8, 0x2c, 0xa9, 0x2c, 0x48, 0x2d, + 0x4e, 0x62, 0x03, 0x0b, 0x1b, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x8f, 0x8f, 0x58, 0x41, 0x72, + 0x02, 0x00, 0x00, } func (m *StagedFinalizeBlockEvent) Marshal() (dAtA []byte, err error) { @@ -248,6 +265,27 @@ func (m *StagedFinalizeBlockEvent_OrderbookUpdate) MarshalToSizedBuffer(dAtA []b } return len(dAtA) - i, nil } +func (m *StagedFinalizeBlockEvent_PriceUpdate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StagedFinalizeBlockEvent_PriceUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.PriceUpdate != nil { + { + size, err := m.PriceUpdate.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStreaming(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + return len(dAtA) - i, nil +} func encodeVarintStreaming(dAtA []byte, offset int, v uint64) int { offset -= sovStreaming(v) base := offset @@ -307,6 +345,18 @@ func (m *StagedFinalizeBlockEvent_OrderbookUpdate) Size() (n int) { } return n } +func (m *StagedFinalizeBlockEvent_PriceUpdate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PriceUpdate != nil { + l = m.PriceUpdate.Size() + n += 1 + l + sovStreaming(uint64(l)) + } + return n +} func sovStreaming(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 @@ -448,6 +498,41 @@ func (m *StagedFinalizeBlockEvent) Unmarshal(dAtA []byte) error { } m.Event = &StagedFinalizeBlockEvent_OrderbookUpdate{v} iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PriceUpdate", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStreaming + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStreaming + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStreaming + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &types1.StreamPriceUpdate{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Event = &StagedFinalizeBlockEvent_PriceUpdate{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipStreaming(dAtA[iNdEx:]) diff --git a/protocol/x/listing/keeper/keeper.go b/protocol/x/listing/keeper/keeper.go index 881fa63fe5..662fea98f4 100644 --- a/protocol/x/listing/keeper/keeper.go +++ b/protocol/x/listing/keeper/keeper.go @@ -13,14 +13,15 @@ import ( type ( Keeper struct { - cdc codec.BinaryCodec - storeKey storetypes.StoreKey - authorities map[string]struct{} - PricesKeeper types.PricesKeeper - ClobKeeper types.ClobKeeper - MarketMapKeeper types.MarketMapKeeper - PerpetualsKeeper types.PerpetualsKeeper - VaultKeeper types.VaultKeeper + cdc codec.BinaryCodec + storeKey storetypes.StoreKey + authorities map[string]struct{} + PricesKeeper types.PricesKeeper + ClobKeeper types.ClobKeeper + MarketMapKeeper types.MarketMapKeeper + PerpetualsKeeper types.PerpetualsKeeper + SubaccountsKeeper types.SubaccountsKeeper + VaultKeeper types.VaultKeeper } ) @@ -32,17 +33,19 @@ func NewKeeper( clobKeeper types.ClobKeeper, marketMapKeeper types.MarketMapKeeper, perpetualsKeeper types.PerpetualsKeeper, + subaccountsKeeper types.SubaccountsKeeper, vaultKeeper types.VaultKeeper, ) *Keeper { return &Keeper{ - cdc: cdc, - storeKey: storeKey, - authorities: lib.UniqueSliceToSet(authorities), - PricesKeeper: pricesKeeper, - ClobKeeper: clobKeeper, - MarketMapKeeper: marketMapKeeper, - PerpetualsKeeper: perpetualsKeeper, - VaultKeeper: vaultKeeper, + cdc: cdc, + storeKey: storeKey, + authorities: lib.UniqueSliceToSet(authorities), + PricesKeeper: pricesKeeper, + ClobKeeper: clobKeeper, + MarketMapKeeper: marketMapKeeper, + PerpetualsKeeper: perpetualsKeeper, + SubaccountsKeeper: subaccountsKeeper, + VaultKeeper: vaultKeeper, } } diff --git a/protocol/x/listing/keeper/listing.go b/protocol/x/listing/keeper/listing.go index 1a126dd527..e8329344a8 100644 --- a/protocol/x/listing/keeper/listing.go +++ b/protocol/x/listing/keeper/listing.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "fmt" "math" "math/big" @@ -152,6 +153,43 @@ func (k Keeper) CreatePerpetual( return perpetual.GetId(), nil } +func (k Keeper) UpgradeIsolatedPerpetualToCross( + ctx sdk.Context, + perpetualId uint32, +) error { + // Validate perpetual exists and is in isolated mode + perpetual, err := k.PerpetualsKeeper.GetPerpetual(ctx, perpetualId) + if err != nil { + return err + } + if perpetual.Params.GetMarketType() != perpetualtypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED { + return fmt.Errorf("perpetual %d is not an isolated perpetual and cannot be upgraded to cross", perpetualId) + } + + err = k.SubaccountsKeeper.TransferIsolatedInsuranceFundToCross(ctx, perpetualId) + if err != nil { + return err + } + + err = k.SubaccountsKeeper.TransferIsolatedCollateralToCross(ctx, perpetualId) + if err != nil { + return err + } + + _, err = k.PerpetualsKeeper.SetPerpetualMarketType( + ctx, + perpetualId, + perpetualtypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS, + ) + if err != nil { + return err + } + + // TODO Propagate changes to indexer + + return nil +} + // Function to set listing vault deposit params in module store func (k Keeper) SetListingVaultDepositParams( ctx sdk.Context, diff --git a/protocol/x/listing/keeper/listing_test.go b/protocol/x/listing/keeper/listing_test.go index 18c9a8778f..5f75bfb5c0 100644 --- a/protocol/x/listing/keeper/listing_test.go +++ b/protocol/x/listing/keeper/listing_test.go @@ -62,7 +62,7 @@ func TestCreateMarket(t *testing.T) { t.Run( name, func(t *testing.T) { mockIndexerEventManager := &mocks.IndexerEventManager{} - ctx, keeper, _, _, pricesKeeper, _, _, marketMapKeeper := keepertest.ListingKeepers( + ctx, keeper, _, _, pricesKeeper, _, _, marketMapKeeper, _, _, _ := keepertest.ListingKeepers( t, &mocks.BankKeeper{}, mockIndexerEventManager, @@ -131,7 +131,7 @@ func TestCreatePerpetual(t *testing.T) { t.Run( name, func(t *testing.T) { mockIndexerEventManager := &mocks.IndexerEventManager{} - ctx, keeper, _, _, pricesKeeper, perpetualsKeeper, _, marketMapKeeper := keepertest.ListingKeepers( + ctx, keeper, _, _, pricesKeeper, perpetualsKeeper, _, marketMapKeeper, _, _, _ := keepertest.ListingKeepers( t, &mocks.BankKeeper{}, mockIndexerEventManager, @@ -217,7 +217,8 @@ func TestCreateClobPair(t *testing.T) { t.Run( name, func(t *testing.T) { mockIndexerEventManager := &mocks.IndexerEventManager{} - ctx, keeper, _, _, pricesKeeper, perpetualsKeeper, clobKeeper, marketMapKeeper := keepertest.ListingKeepers( + ctx, keeper, _, _, pricesKeeper, perpetualsKeeper, clobKeeper, marketMapKeeper, + _, _, _ := keepertest.ListingKeepers( t, &mocks.BankKeeper{}, mockIndexerEventManager, diff --git a/protocol/x/listing/keeper/msg_server_upgrade_isolated_perpetual_to_cross.go b/protocol/x/listing/keeper/msg_server_upgrade_isolated_perpetual_to_cross.go new file mode 100644 index 0000000000..a7599eb65f --- /dev/null +++ b/protocol/x/listing/keeper/msg_server_upgrade_isolated_perpetual_to_cross.go @@ -0,0 +1,35 @@ +package keeper + +import ( + "context" + + errorsmod "cosmossdk.io/errors" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/dydxprotocol/v4-chain/protocol/lib" + "github.com/dydxprotocol/v4-chain/protocol/x/listing/types" +) + +func (k msgServer) UpgradeIsolatedPerpetualToCross( + goCtx context.Context, + msg *types.MsgUpgradeIsolatedPerpetualToCross, +) (*types.MsgUpgradeIsolatedPerpetualToCrossResponse, error) { + if !k.Keeper.HasAuthority(msg.Authority) { + return nil, errorsmod.Wrapf( + govtypes.ErrInvalidSigner, + "invalid authority %s", + msg.Authority, + ) + } + + ctx := lib.UnwrapSDKContext(goCtx, types.ModuleName) + + err := k.Keeper.UpgradeIsolatedPerpetualToCross( + ctx, + msg.PerpetualId, + ) + if err != nil { + return nil, err + } + + return &types.MsgUpgradeIsolatedPerpetualToCrossResponse{}, nil +} diff --git a/protocol/x/listing/keeper/msg_server_upgrade_isolated_perpetual_to_cross_test.go b/protocol/x/listing/keeper/msg_server_upgrade_isolated_perpetual_to_cross_test.go new file mode 100644 index 0000000000..1ee4846391 --- /dev/null +++ b/protocol/x/listing/keeper/msg_server_upgrade_isolated_perpetual_to_cross_test.go @@ -0,0 +1,230 @@ +package keeper_test + +import ( + "math/big" + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dydxprotocol/v4-chain/protocol/lib" + "github.com/dydxprotocol/v4-chain/protocol/mocks" + bank_testutil "github.com/dydxprotocol/v4-chain/protocol/testutil/bank" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + keepertest "github.com/dydxprotocol/v4-chain/protocol/testutil/keeper" + asstypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" + listingkeeper "github.com/dydxprotocol/v4-chain/protocol/x/listing/keeper" + types "github.com/dydxprotocol/v4-chain/protocol/x/listing/types" + perpetualtypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" + satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" + "github.com/stretchr/testify/require" +) + +var ( + validAuthority = lib.GovModuleAddress.String() +) + +func TestMsgUpgradeIsolatedPerpetualToCross(t *testing.T) { + tests := map[string]struct { + msg *types.MsgUpgradeIsolatedPerpetualToCross + isolatedInsuranceFundBalance *big.Int + isolatedCollateralPoolBalance *big.Int + crossInsuranceFundBalance *big.Int + crossCollateralPoolBalance *big.Int + + expectedErr string + }{ + "Success": { + msg: &types.MsgUpgradeIsolatedPerpetualToCross{ + Authority: validAuthority, + PerpetualId: 3, // isolated + }, + isolatedInsuranceFundBalance: big.NewInt(1), + isolatedCollateralPoolBalance: big.NewInt(1), + crossInsuranceFundBalance: big.NewInt(1), + crossCollateralPoolBalance: big.NewInt(1), + expectedErr: "", + }, + "Success - empty isolated insurance fund": { + msg: &types.MsgUpgradeIsolatedPerpetualToCross{ + Authority: validAuthority, + PerpetualId: 3, // isolated + }, + isolatedInsuranceFundBalance: big.NewInt(0), + isolatedCollateralPoolBalance: big.NewInt(1), + crossInsuranceFundBalance: big.NewInt(1), + crossCollateralPoolBalance: big.NewInt(1), + expectedErr: "", + }, + "Success - empty isolated collateral fund": { + msg: &types.MsgUpgradeIsolatedPerpetualToCross{ + Authority: validAuthority, + PerpetualId: 3, // isolated + }, + isolatedInsuranceFundBalance: big.NewInt(1), + isolatedCollateralPoolBalance: big.NewInt(0), + crossInsuranceFundBalance: big.NewInt(1), + crossCollateralPoolBalance: big.NewInt(1), + expectedErr: "", + }, + "Success - empty isolated insurance fund + empty isolated collateral fund": { + msg: &types.MsgUpgradeIsolatedPerpetualToCross{ + Authority: validAuthority, + PerpetualId: 3, // isolated + }, + isolatedInsuranceFundBalance: big.NewInt(0), + isolatedCollateralPoolBalance: big.NewInt(0), + crossInsuranceFundBalance: big.NewInt(1), + crossCollateralPoolBalance: big.NewInt(1), + expectedErr: "", + }, + "Failure: Empty authority": { + msg: &types.MsgUpgradeIsolatedPerpetualToCross{ + Authority: "", + PerpetualId: 3, // isolated + }, + isolatedInsuranceFundBalance: big.NewInt(1), + isolatedCollateralPoolBalance: big.NewInt(1), + crossInsuranceFundBalance: big.NewInt(1), + crossCollateralPoolBalance: big.NewInt(1), + expectedErr: "invalid authority", + }, + "Failure: Invalid authority": { + msg: &types.MsgUpgradeIsolatedPerpetualToCross{ + Authority: "invalid", + PerpetualId: 3, // isolated + }, + isolatedInsuranceFundBalance: big.NewInt(1), + isolatedCollateralPoolBalance: big.NewInt(1), + crossInsuranceFundBalance: big.NewInt(1), + crossCollateralPoolBalance: big.NewInt(1), + expectedErr: "invalid authority", + }, + "Failure: Invalid perpetual ID": { + msg: &types.MsgUpgradeIsolatedPerpetualToCross{ + Authority: validAuthority, + PerpetualId: 99999999, // invalid + }, + expectedErr: "Perpetual does not exist", + }, + "Failure - perpetual already has cross market type": { + msg: &types.MsgUpgradeIsolatedPerpetualToCross{ + Authority: validAuthority, + PerpetualId: 1, // cross + }, + isolatedInsuranceFundBalance: big.NewInt(1), + isolatedCollateralPoolBalance: big.NewInt(1), + crossInsuranceFundBalance: big.NewInt(1), + crossCollateralPoolBalance: big.NewInt(1), + expectedErr: "perpetual 1 is not an isolated perpetual and cannot be upgraded to cross", + }, + } + + for name, tc := range tests { + t.Run( + name, func(t *testing.T) { + mockIndexerEventManager := &mocks.IndexerEventManager{} + + ctx, keeper, _, _, pricesKeeper, perpetualsKeeper, _, _, assetsKeeper, + bankKeeper, subaccountsKeeper := keepertest.ListingKeepers( + t, + &mocks.BankKeeper{}, + mockIndexerEventManager, + ) + + // Create the default markets. + keepertest.CreateTestMarkets(t, ctx, pricesKeeper) + + // Create liquidity tiers. + keepertest.CreateTestLiquidityTiers(t, ctx, perpetualsKeeper) + + // Create USDC asset. + err := keepertest.CreateUsdcAsset(ctx, assetsKeeper) + require.NoError(t, err) + + // Create test perpetuals. + keepertest.CreateTestPerpetuals(t, ctx, perpetualsKeeper) + + var isolatedInsuranceFundAddr, crossInsuranceFundAddr, isolatedCollateralPoolAddr, + crossCollateralPoolAddr sdk.AccAddress + if tc.isolatedInsuranceFundBalance != nil { + // Get addresses for isolated/cross insurance funds and collateral pools. + isolatedInsuranceFundAddr, err = perpetualsKeeper.GetInsuranceFundModuleAddress(ctx, tc.msg.PerpetualId) + require.NoError(t, err) + + isolatedCollateralPoolAddr, err = subaccountsKeeper.GetCollateralPoolFromPerpetualId(ctx, tc.msg.PerpetualId) + require.NoError(t, err) + + crossInsuranceFundAddr = perpetualtypes.InsuranceFundModuleAddress + + crossCollateralPoolAddr = satypes.ModuleAddress + + // Fund the isolated insurance account, cross insurance account, + // isolated collateral pool, and cross collateral pool. + fundingData := [][]interface{}{ + {isolatedInsuranceFundAddr, tc.isolatedInsuranceFundBalance}, + {crossInsuranceFundAddr, tc.crossInsuranceFundBalance}, + {isolatedCollateralPoolAddr, tc.isolatedCollateralPoolBalance}, + {crossCollateralPoolAddr, tc.crossCollateralPoolBalance}, + } + + for _, data := range fundingData { + addr := data[0].(sdk.AccAddress) + amount := data[1].(*big.Int) + + if amount.Cmp(big.NewInt(0)) != 0 { + err = bank_testutil.FundAccount( + ctx, + addr, + sdk.Coins{ + sdk.NewCoin(constants.Usdc.Denom, sdkmath.NewIntFromBigInt(amount)), + }, + *bankKeeper, + ) + require.NoError(t, err) + } + } + } + + // Upgrade perpetual from isolated to cross. + ms := listingkeeper.NewMsgServerImpl(*keeper) + _, err = ms.UpgradeIsolatedPerpetualToCross(ctx, tc.msg) + if tc.expectedErr != "" { + require.ErrorContains(t, err, tc.expectedErr) + return + } + require.NoError(t, err) + + // Check perpetual market type has been upgraded to cross. + perpetual, err := perpetualsKeeper.GetPerpetual(ctx, tc.msg.PerpetualId) + require.NoError(t, err) + require.Equal( + t, + perpetualtypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS, + perpetual.Params.MarketType, + ) + + // Check expected balance for isolated/cross insurance funds and collateral pools. + expectedBalances := [][]interface{}{ + {isolatedInsuranceFundAddr, big.NewInt(0)}, + {crossInsuranceFundAddr, big.NewInt(0).Add(tc.isolatedInsuranceFundBalance, tc.crossInsuranceFundBalance)}, + {isolatedCollateralPoolAddr, big.NewInt(0)}, + {crossCollateralPoolAddr, big.NewInt(0).Add(tc.isolatedCollateralPoolBalance, tc.crossCollateralPoolBalance)}, + } + + for _, data := range expectedBalances { + addr := data[0].(sdk.AccAddress) + amount := data[1].(*big.Int) + + require.Equal( + t, + sdk.NewCoin( + asstypes.AssetUsdc.Denom, + sdkmath.NewIntFromBigInt(amount), + ), + bankKeeper.GetBalance(ctx, addr, asstypes.AssetUsdc.Denom), + ) + } + }, + ) + } +} diff --git a/protocol/x/listing/types/expected_keepers.go b/protocol/x/listing/types/expected_keepers.go index e5a8b6693a..5fd30efa1b 100644 --- a/protocol/x/listing/types/expected_keepers.go +++ b/protocol/x/listing/types/expected_keepers.go @@ -64,7 +64,16 @@ type PerpetualsKeeper interface { marketType perpetualtypes.PerpetualMarketType, ) (perpetualtypes.Perpetual, error) AcquireNextPerpetualID(ctx sdk.Context) uint32 + GetPerpetual( + ctx sdk.Context, + id uint32, + ) (val perpetualtypes.Perpetual, err error) GetAllPerpetuals(ctx sdk.Context) (list []perpetualtypes.Perpetual) + SetPerpetualMarketType( + ctx sdk.Context, + id uint32, + marketType perpetualtypes.PerpetualMarketType, + ) (perpetualtypes.Perpetual, error) } type VaultKeeper interface { @@ -90,3 +99,14 @@ type VaultKeeper interface { status vaulttypes.VaultStatus, ) error } + +type SubaccountsKeeper interface { + TransferIsolatedInsuranceFundToCross( + ctx sdk.Context, + perpetualId uint32, + ) error + TransferIsolatedCollateralToCross( + ctx sdk.Context, + perpetualId uint32, + ) error +} diff --git a/protocol/x/listing/types/tx.pb.go b/protocol/x/listing/types/tx.pb.go index 4d8ce4644e..c1ba7f2abf 100644 --- a/protocol/x/listing/types/tx.pb.go +++ b/protocol/x/listing/types/tx.pb.go @@ -312,6 +312,103 @@ func (m *MsgSetListingVaultDepositParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgSetListingVaultDepositParamsResponse proto.InternalMessageInfo +// MsgUpgradeIsolatedPerpetualToCross is used to upgrade a market from +// isolated margin to cross margin. +type MsgUpgradeIsolatedPerpetualToCross struct { + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // ID of the perpetual to be upgraded to CROSS + PerpetualId uint32 `protobuf:"varint,2,opt,name=perpetual_id,json=perpetualId,proto3" json:"perpetual_id,omitempty"` +} + +func (m *MsgUpgradeIsolatedPerpetualToCross) Reset() { *m = MsgUpgradeIsolatedPerpetualToCross{} } +func (m *MsgUpgradeIsolatedPerpetualToCross) String() string { return proto.CompactTextString(m) } +func (*MsgUpgradeIsolatedPerpetualToCross) ProtoMessage() {} +func (*MsgUpgradeIsolatedPerpetualToCross) Descriptor() ([]byte, []int) { + return fileDescriptor_144a579c1e2dcb94, []int{6} +} +func (m *MsgUpgradeIsolatedPerpetualToCross) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpgradeIsolatedPerpetualToCross) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpgradeIsolatedPerpetualToCross.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpgradeIsolatedPerpetualToCross) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpgradeIsolatedPerpetualToCross.Merge(m, src) +} +func (m *MsgUpgradeIsolatedPerpetualToCross) XXX_Size() int { + return m.Size() +} +func (m *MsgUpgradeIsolatedPerpetualToCross) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpgradeIsolatedPerpetualToCross.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpgradeIsolatedPerpetualToCross proto.InternalMessageInfo + +func (m *MsgUpgradeIsolatedPerpetualToCross) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpgradeIsolatedPerpetualToCross) GetPerpetualId() uint32 { + if m != nil { + return m.PerpetualId + } + return 0 +} + +// MsgUpgradeIsolatedPerpetualToCrossResponse defines the +// UpgradeIsolatedPerpetualToCross response type. +type MsgUpgradeIsolatedPerpetualToCrossResponse struct { +} + +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) Reset() { + *m = MsgUpgradeIsolatedPerpetualToCrossResponse{} +} +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) String() string { + return proto.CompactTextString(m) +} +func (*MsgUpgradeIsolatedPerpetualToCrossResponse) ProtoMessage() {} +func (*MsgUpgradeIsolatedPerpetualToCrossResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_144a579c1e2dcb94, []int{7} +} +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpgradeIsolatedPerpetualToCrossResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpgradeIsolatedPerpetualToCrossResponse.Merge(m, src) +} +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpgradeIsolatedPerpetualToCrossResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpgradeIsolatedPerpetualToCrossResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgSetMarketsHardCap)(nil), "dydxprotocol.listing.MsgSetMarketsHardCap") proto.RegisterType((*MsgSetMarketsHardCapResponse)(nil), "dydxprotocol.listing.MsgSetMarketsHardCapResponse") @@ -319,46 +416,52 @@ func init() { proto.RegisterType((*MsgCreateMarketPermissionlessResponse)(nil), "dydxprotocol.listing.MsgCreateMarketPermissionlessResponse") proto.RegisterType((*MsgSetListingVaultDepositParams)(nil), "dydxprotocol.listing.MsgSetListingVaultDepositParams") proto.RegisterType((*MsgSetListingVaultDepositParamsResponse)(nil), "dydxprotocol.listing.MsgSetListingVaultDepositParamsResponse") + proto.RegisterType((*MsgUpgradeIsolatedPerpetualToCross)(nil), "dydxprotocol.listing.MsgUpgradeIsolatedPerpetualToCross") + proto.RegisterType((*MsgUpgradeIsolatedPerpetualToCrossResponse)(nil), "dydxprotocol.listing.MsgUpgradeIsolatedPerpetualToCrossResponse") } func init() { proto.RegisterFile("dydxprotocol/listing/tx.proto", fileDescriptor_144a579c1e2dcb94) } var fileDescriptor_144a579c1e2dcb94 = []byte{ - // 535 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0xce, 0x52, 0x54, 0xa9, 0x0b, 0x45, 0xaa, 0x15, 0x41, 0xb0, 0x5a, 0xb7, 0x44, 0x82, 0xfe, - 0x48, 0xb5, 0x45, 0x0a, 0x48, 0x14, 0x71, 0x20, 0x45, 0x08, 0x04, 0x91, 0x2a, 0x47, 0xe2, 0xc0, - 0xc5, 0xda, 0xd8, 0x8b, 0xbd, 0x6a, 0xec, 0xb5, 0x76, 0xd6, 0x55, 0x72, 0xe5, 0x01, 0x80, 0x03, - 0x07, 0xce, 0x3c, 0x01, 0x07, 0x0e, 0x3c, 0x42, 0x8f, 0x15, 0x27, 0x4e, 0x08, 0x25, 0x07, 0x5e, - 0x03, 0xc5, 0xbb, 0xf9, 0x53, 0x9d, 0x80, 0x72, 0xf2, 0xce, 0xce, 0x7c, 0xdf, 0x7c, 0xe3, 0x6f, - 0xb4, 0x78, 0x23, 0xe8, 0x06, 0x9d, 0x54, 0x70, 0xc9, 0x7d, 0xde, 0x76, 0xda, 0x0c, 0x24, 0x4b, - 0x42, 0x47, 0x76, 0xec, 0xfc, 0xce, 0x28, 0x4f, 0xa6, 0x6d, 0x9d, 0x36, 0x6f, 0xfa, 0x1c, 0x62, - 0x0e, 0x5e, 0x9e, 0x70, 0x54, 0xa0, 0x00, 0xe6, 0x0d, 0x15, 0x39, 0x31, 0x84, 0xce, 0xe9, 0xdd, - 0xc1, 0x47, 0x27, 0xca, 0x21, 0x0f, 0xb9, 0x02, 0x0c, 0x4e, 0xfa, 0x76, 0x77, 0xaa, 0x3d, 0x64, - 0x2d, 0xe2, 0xfb, 0x3c, 0x4b, 0x24, 0x4c, 0x9c, 0x75, 0xe9, 0xad, 0x42, 0xa5, 0x29, 0x11, 0x24, - 0xd6, 0xcd, 0xab, 0x1f, 0x10, 0x2e, 0x37, 0x20, 0x6c, 0x52, 0xd9, 0x20, 0xe2, 0x84, 0x4a, 0x78, - 0x4e, 0x44, 0x70, 0x44, 0x52, 0xe3, 0x01, 0x5e, 0x21, 0x99, 0x8c, 0xb8, 0x60, 0xb2, 0x5b, 0x41, - 0x5b, 0x68, 0x67, 0xa5, 0x5e, 0xf9, 0xf1, 0x6d, 0xbf, 0xac, 0xa5, 0x3f, 0x09, 0x02, 0x41, 0x01, - 0x9a, 0x52, 0xb0, 0x24, 0x74, 0xc7, 0xa5, 0x86, 0x83, 0xcb, 0x11, 0x11, 0x81, 0xe7, 0x93, 0xd4, - 0x7b, 0xcb, 0x85, 0x17, 0x2b, 0xda, 0xca, 0xa5, 0x2d, 0xb4, 0xb3, 0xea, 0xae, 0x45, 0x8a, 0xfe, - 0x19, 0x17, 0xba, 0xdf, 0xe1, 0xb5, 0x77, 0x7f, 0xbe, 0xee, 0x8d, 0x09, 0xaa, 0x16, 0x5e, 0x2f, - 0x12, 0xe4, 0x52, 0x48, 0x79, 0x02, 0xb4, 0xfa, 0x19, 0xe1, 0x8d, 0x06, 0x84, 0x47, 0x82, 0x12, - 0x49, 0x55, 0xcd, 0x31, 0x15, 0x31, 0x03, 0x60, 0x3c, 0x69, 0x53, 0x00, 0xe3, 0x3a, 0x5e, 0x96, - 0xcc, 0x3f, 0xa1, 0x42, 0xe9, 0x76, 0x75, 0x64, 0xbc, 0xc4, 0xab, 0xe3, 0x5f, 0xe4, 0xb1, 0x20, - 0xd7, 0x74, 0xa5, 0x76, 0xc7, 0x9e, 0x72, 0x6c, 0xe2, 0x8f, 0xda, 0xcd, 0xd1, 0xf9, 0x45, 0xe0, - 0x5e, 0x85, 0x89, 0xe8, 0xd0, 0x18, 0xc8, 0x9e, 0xe6, 0xab, 0x6e, 0xe3, 0xdb, 0x73, 0x95, 0x8d, - 0x66, 0xf8, 0x8e, 0xf0, 0xa6, 0x1a, 0xf2, 0x95, 0x32, 0xe5, 0x35, 0xc9, 0xda, 0xf2, 0x29, 0x4d, - 0x39, 0x30, 0x79, 0x9c, 0xfb, 0xb3, 0xb0, 0x01, 0x0d, 0xbc, 0xac, 0x1c, 0xd6, 0xe3, 0x39, 0x76, - 0xd1, 0x42, 0xda, 0x33, 0x1b, 0xd7, 0x2f, 0x9f, 0xfd, 0xda, 0x2c, 0xb9, 0x9a, 0xe4, 0x82, 0x3d, - 0xbb, 0x78, 0xfb, 0x1f, 0xca, 0x87, 0x53, 0xd6, 0xbe, 0x2c, 0xe1, 0xa5, 0x06, 0x84, 0x06, 0xe0, - 0xb5, 0x8b, 0xfb, 0xb5, 0x57, 0x2c, 0xab, 0xc8, 0x7a, 0xb3, 0xf6, 0xff, 0xb5, 0xc3, 0xe6, 0xc6, - 0x7b, 0x84, 0xcd, 0x39, 0x3b, 0x72, 0x30, 0x93, 0x72, 0x36, 0xc8, 0x7c, 0xb4, 0x00, 0x68, 0x24, - 0xe8, 0x13, 0xc2, 0xeb, 0x73, 0x0d, 0xbf, 0x3f, 0x6f, 0xca, 0x99, 0x30, 0xf3, 0xf1, 0x42, 0xb0, - 0xa1, 0xac, 0x7a, 0xf3, 0xac, 0x67, 0xa1, 0xf3, 0x9e, 0x85, 0x7e, 0xf7, 0x2c, 0xf4, 0xb1, 0x6f, - 0x95, 0xce, 0xfb, 0x56, 0xe9, 0x67, 0xdf, 0x2a, 0xbd, 0x79, 0x18, 0x32, 0x19, 0x65, 0x2d, 0xdb, - 0xe7, 0xb1, 0x33, 0xf5, 0x90, 0x9c, 0xde, 0xdb, 0xf7, 0x23, 0xc2, 0x12, 0x67, 0x74, 0xd3, 0x19, - 0x3f, 0x83, 0xdd, 0x94, 0x42, 0x6b, 0x39, 0xcf, 0x1c, 0xfc, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xfa, - 0xd7, 0x13, 0x8c, 0x2b, 0x05, 0x00, 0x00, + // 607 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x3f, 0x6f, 0xd3, 0x40, + 0x14, 0xcf, 0x41, 0x55, 0xa9, 0xd7, 0x06, 0xa9, 0x56, 0x04, 0xc1, 0x6a, 0x9d, 0x36, 0x12, 0xb4, + 0x8d, 0xa8, 0x2d, 0x52, 0x40, 0x50, 0x84, 0x04, 0x09, 0x42, 0x44, 0x60, 0x29, 0x72, 0x80, 0x81, + 0x25, 0xba, 0xd8, 0x87, 0x63, 0xd5, 0xf6, 0x59, 0xf7, 0xce, 0x55, 0xb2, 0xf2, 0x01, 0x28, 0x03, + 0x03, 0x0b, 0xdf, 0x81, 0x81, 0x81, 0x99, 0xa9, 0x63, 0xc5, 0xc4, 0x84, 0x50, 0x32, 0xf0, 0x35, + 0x50, 0x62, 0xc7, 0x49, 0x94, 0x7f, 0x28, 0x93, 0xef, 0xfd, 0xf9, 0xbd, 0xf7, 0x7b, 0xf7, 0x7b, + 0xb6, 0xf1, 0xb6, 0xd5, 0xb6, 0x5a, 0x01, 0x67, 0x82, 0x99, 0xcc, 0xd5, 0x5c, 0x07, 0x84, 0xe3, + 0xdb, 0x9a, 0x68, 0xa9, 0x7d, 0x9f, 0x94, 0x19, 0x0d, 0xab, 0x71, 0x58, 0xbe, 0x6e, 0x32, 0xf0, + 0x18, 0xd4, 0xfb, 0x01, 0x2d, 0x32, 0x22, 0x80, 0x7c, 0x2d, 0xb2, 0x34, 0x0f, 0x6c, 0xed, 0xf4, + 0x76, 0xef, 0x11, 0x07, 0x32, 0x36, 0xb3, 0x59, 0x04, 0xe8, 0x9d, 0x62, 0xef, 0xc1, 0x58, 0x7b, + 0x08, 0x1b, 0xc4, 0x34, 0x59, 0xe8, 0x0b, 0x18, 0x39, 0xc7, 0xa9, 0xbb, 0x53, 0x99, 0x06, 0x84, + 0x13, 0x2f, 0x6e, 0x9e, 0x3f, 0x43, 0x38, 0xa3, 0x83, 0x5d, 0xa3, 0x42, 0x27, 0xfc, 0x84, 0x0a, + 0x78, 0x4e, 0xb8, 0x55, 0x26, 0x81, 0x74, 0x0f, 0xaf, 0x91, 0x50, 0x34, 0x19, 0x77, 0x44, 0x3b, + 0x8b, 0x76, 0xd0, 0xfe, 0x5a, 0x29, 0xfb, 0xf3, 0xdb, 0x61, 0x26, 0xa6, 0xfe, 0xc4, 0xb2, 0x38, + 0x05, 0xa8, 0x09, 0xee, 0xf8, 0xb6, 0x31, 0x4c, 0x95, 0x34, 0x9c, 0x69, 0x12, 0x6e, 0xd5, 0x4d, + 0x12, 0xd4, 0xdf, 0x31, 0x5e, 0xf7, 0xa2, 0xb2, 0xd9, 0x4b, 0x3b, 0x68, 0x3f, 0x6d, 0x6c, 0x36, + 0xa3, 0xf2, 0xcf, 0x18, 0x8f, 0xfb, 0x1d, 0x5f, 0x79, 0xff, 0xf7, 0x6b, 0x61, 0x58, 0x20, 0xaf, + 0xe0, 0xad, 0x69, 0x84, 0x0c, 0x0a, 0x01, 0xf3, 0x81, 0xe6, 0x3f, 0x23, 0xbc, 0xad, 0x83, 0x5d, + 0xe6, 0x94, 0x08, 0x1a, 0xe5, 0x54, 0x29, 0xf7, 0x1c, 0x00, 0x87, 0xf9, 0x2e, 0x05, 0x90, 0xae, + 0xe2, 0x55, 0xe1, 0x98, 0x27, 0x94, 0x47, 0xbc, 0x8d, 0xd8, 0x92, 0x5e, 0xe0, 0xf4, 0xf0, 0x8a, + 0xea, 0x8e, 0xd5, 0xe7, 0xb4, 0x5e, 0xbc, 0xa9, 0x8e, 0x29, 0x36, 0x72, 0xa3, 0x6a, 0x2d, 0x39, + 0x57, 0x2c, 0x63, 0x03, 0x46, 0xac, 0x63, 0xa9, 0x47, 0x7b, 0xbc, 0x5e, 0x7e, 0x0f, 0xdf, 0x98, + 0xcb, 0x2c, 0x99, 0xe1, 0x3b, 0xc2, 0xb9, 0x68, 0xc8, 0x97, 0x91, 0x28, 0x6f, 0x48, 0xe8, 0x8a, + 0xa7, 0x34, 0x60, 0xe0, 0x88, 0x6a, 0x5f, 0x9f, 0xa5, 0x05, 0xd0, 0xf1, 0x6a, 0xa4, 0x70, 0x3c, + 0x9e, 0xa6, 0x4e, 0x5b, 0x48, 0x75, 0x66, 0xe3, 0xd2, 0xca, 0xf9, 0xef, 0x5c, 0xca, 0x88, 0x8b, + 0x4c, 0xc8, 0x73, 0x80, 0xf7, 0x16, 0x30, 0x4f, 0xa6, 0x3c, 0x43, 0x38, 0xaf, 0x83, 0xfd, 0x3a, + 0xb0, 0x39, 0xb1, 0x68, 0x05, 0x98, 0x4b, 0x04, 0xb5, 0xaa, 0x94, 0x07, 0x54, 0x84, 0xc4, 0x7d, + 0xc5, 0xca, 0x9c, 0xc1, 0xf2, 0x83, 0xee, 0xe2, 0x8d, 0x60, 0x50, 0x6b, 0xa0, 0x66, 0xda, 0x58, + 0x4f, 0x7c, 0x15, 0x6b, 0x82, 0xfc, 0x2d, 0x5c, 0x58, 0x4c, 0x68, 0xc0, 0xbf, 0xf8, 0x63, 0x05, + 0x5f, 0xd6, 0xc1, 0x96, 0x00, 0x6f, 0x4e, 0xbe, 0x1f, 0x85, 0xe9, 0xd7, 0x3a, 0x6d, 0x75, 0xe5, + 0xe2, 0xff, 0xe7, 0x0e, 0x9a, 0x4b, 0x1f, 0x10, 0x96, 0xe7, 0xec, 0xf8, 0xd1, 0xcc, 0x92, 0xb3, + 0x41, 0xf2, 0xc3, 0x25, 0x40, 0x09, 0xa1, 0x4f, 0x08, 0x6f, 0xcd, 0x5d, 0xd8, 0xbb, 0xf3, 0xa6, + 0x9c, 0x09, 0x93, 0x1f, 0x2d, 0x05, 0x4b, 0x68, 0x7d, 0x41, 0x38, 0xb7, 0x68, 0xc3, 0xee, 0xcf, + 0x6c, 0xb1, 0x00, 0x29, 0x3f, 0x5e, 0x16, 0x39, 0xe0, 0x57, 0xaa, 0x9d, 0x77, 0x14, 0x74, 0xd1, + 0x51, 0xd0, 0x9f, 0x8e, 0x82, 0x3e, 0x76, 0x95, 0xd4, 0x45, 0x57, 0x49, 0xfd, 0xea, 0x2a, 0xa9, + 0xb7, 0x0f, 0x6c, 0x47, 0x34, 0xc3, 0x86, 0x6a, 0x32, 0x4f, 0x1b, 0xfb, 0x50, 0x9f, 0xde, 0x39, + 0x34, 0x9b, 0xc4, 0xf1, 0xb5, 0xc4, 0xd3, 0x1a, 0xfe, 0x66, 0xda, 0x01, 0x85, 0xc6, 0x6a, 0x3f, + 0x72, 0xf4, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x92, 0xf4, 0x1f, 0x1d, 0x8b, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -379,6 +482,9 @@ type MsgClient interface { CreateMarketPermissionless(ctx context.Context, in *MsgCreateMarketPermissionless, opts ...grpc.CallOption) (*MsgCreateMarketPermissionlessResponse, error) // SetListingVaultDepositParams sets PML megavault deposit params SetListingVaultDepositParams(ctx context.Context, in *MsgSetListingVaultDepositParams, opts ...grpc.CallOption) (*MsgSetListingVaultDepositParamsResponse, error) + // UpgradeIsolatedPerpetualToCross upgrades a perpetual from isolated to cross + // margin + UpgradeIsolatedPerpetualToCross(ctx context.Context, in *MsgUpgradeIsolatedPerpetualToCross, opts ...grpc.CallOption) (*MsgUpgradeIsolatedPerpetualToCrossResponse, error) } type msgClient struct { @@ -416,6 +522,15 @@ func (c *msgClient) SetListingVaultDepositParams(ctx context.Context, in *MsgSet return out, nil } +func (c *msgClient) UpgradeIsolatedPerpetualToCross(ctx context.Context, in *MsgUpgradeIsolatedPerpetualToCross, opts ...grpc.CallOption) (*MsgUpgradeIsolatedPerpetualToCrossResponse, error) { + out := new(MsgUpgradeIsolatedPerpetualToCrossResponse) + err := c.cc.Invoke(ctx, "/dydxprotocol.listing.Msg/UpgradeIsolatedPerpetualToCross", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { // SetMarketsHardCap sets a hard cap on the number of markets listed @@ -424,6 +539,9 @@ type MsgServer interface { CreateMarketPermissionless(context.Context, *MsgCreateMarketPermissionless) (*MsgCreateMarketPermissionlessResponse, error) // SetListingVaultDepositParams sets PML megavault deposit params SetListingVaultDepositParams(context.Context, *MsgSetListingVaultDepositParams) (*MsgSetListingVaultDepositParamsResponse, error) + // UpgradeIsolatedPerpetualToCross upgrades a perpetual from isolated to cross + // margin + UpgradeIsolatedPerpetualToCross(context.Context, *MsgUpgradeIsolatedPerpetualToCross) (*MsgUpgradeIsolatedPerpetualToCrossResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -439,6 +557,9 @@ func (*UnimplementedMsgServer) CreateMarketPermissionless(ctx context.Context, r func (*UnimplementedMsgServer) SetListingVaultDepositParams(ctx context.Context, req *MsgSetListingVaultDepositParams) (*MsgSetListingVaultDepositParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SetListingVaultDepositParams not implemented") } +func (*UnimplementedMsgServer) UpgradeIsolatedPerpetualToCross(ctx context.Context, req *MsgUpgradeIsolatedPerpetualToCross) (*MsgUpgradeIsolatedPerpetualToCrossResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpgradeIsolatedPerpetualToCross not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -498,6 +619,24 @@ func _Msg_SetListingVaultDepositParams_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } +func _Msg_UpgradeIsolatedPerpetualToCross_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpgradeIsolatedPerpetualToCross) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpgradeIsolatedPerpetualToCross(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dydxprotocol.listing.Msg/UpgradeIsolatedPerpetualToCross", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpgradeIsolatedPerpetualToCross(ctx, req.(*MsgUpgradeIsolatedPerpetualToCross)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "dydxprotocol.listing.Msg", HandlerType: (*MsgServer)(nil), @@ -514,6 +653,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "SetListingVaultDepositParams", Handler: _Msg_SetListingVaultDepositParams_Handler, }, + { + MethodName: "UpgradeIsolatedPerpetualToCross", + Handler: _Msg_UpgradeIsolatedPerpetualToCross_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "dydxprotocol/listing/tx.proto", @@ -705,6 +848,64 @@ func (m *MsgSetListingVaultDepositParamsResponse) MarshalToSizedBuffer(dAtA []by return len(dAtA) - i, nil } +func (m *MsgUpgradeIsolatedPerpetualToCross) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpgradeIsolatedPerpetualToCross) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpgradeIsolatedPerpetualToCross) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.PerpetualId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PerpetualId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -791,6 +992,31 @@ func (m *MsgSetListingVaultDepositParamsResponse) Size() (n int) { return n } +func (m *MsgUpgradeIsolatedPerpetualToCross) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PerpetualId != 0 { + n += 1 + sovTx(uint64(m.PerpetualId)) + } + return n +} + +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1281,6 +1507,157 @@ func (m *MsgSetListingVaultDepositParamsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgUpgradeIsolatedPerpetualToCross) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpgradeIsolatedPerpetualToCross: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpgradeIsolatedPerpetualToCross: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PerpetualId", wireType) + } + m.PerpetualId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PerpetualId |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpgradeIsolatedPerpetualToCrossResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpgradeIsolatedPerpetualToCrossResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpgradeIsolatedPerpetualToCrossResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/protocol/x/perpetuals/keeper/perpetual.go b/protocol/x/perpetuals/keeper/perpetual.go index 834f67e96a..b97c359426 100644 --- a/protocol/x/perpetuals/keeper/perpetual.go +++ b/protocol/x/perpetuals/keeper/perpetual.go @@ -197,10 +197,11 @@ func (k Keeper) SetPerpetualMarketType( return perpetual, err } - if perpetual.Params.MarketType != types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_UNSPECIFIED { + if perpetual.Params.MarketType == types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS { return types.Perpetual{}, errorsmod.Wrap( types.ErrInvalidMarketType, - fmt.Sprintf("perpetual %d already has market type %v", perpetualId, perpetual.Params.MarketType), + fmt.Sprintf("perpetual %d already has market type %v and cannot be changed", + perpetualId, types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS), ) } diff --git a/protocol/x/perpetuals/keeper/perpetual_test.go b/protocol/x/perpetuals/keeper/perpetual_test.go index 30cce2fa32..08e859de1d 100644 --- a/protocol/x/perpetuals/keeper/perpetual_test.go +++ b/protocol/x/perpetuals/keeper/perpetual_test.go @@ -323,11 +323,16 @@ func TestSetPerpetualMarketType(t *testing.T) { errorExpected bool expectedError error }{ - "success": { + "success - set unspecified to cross": { currType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_UNSPECIFIED, newType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS, errorExpected: false, }, + "success - set isolated to cross": { + currType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED, + newType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS, + errorExpected: false, + }, "failure - setting to unspecified": { currType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS, newType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_UNSPECIFIED, @@ -340,16 +345,16 @@ func TestSetPerpetualMarketType(t *testing.T) { ), ), }, - "failure - market type already set": { - currType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED, - newType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS, + "failure - market type already set to cross": { + currType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS, + newType: types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED, errorExpected: true, expectedError: errorsmod.Wrap( types.ErrInvalidMarketType, fmt.Sprintf( - "perpetual %d already has market type %v", + "perpetual %d already has market type %v and cannot be changed", 0, - types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED, + types.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS, ), ), }, diff --git a/protocol/x/prices/keeper/market_price.go b/protocol/x/prices/keeper/market_price.go index 3cb0fdd278..78490b0670 100644 --- a/protocol/x/prices/keeper/market_price.go +++ b/protocol/x/prices/keeper/market_price.go @@ -193,3 +193,26 @@ func (k Keeper) GetMarketIdToValidIndexPrice( } return ret } + +// GetStreamPriceUpdate returns a stream price update from its id. +func (k Keeper) GetStreamPriceUpdate( + ctx sdk.Context, + id uint32, + snapshot bool, +) ( + val types.StreamPriceUpdate, +) { + price, err := k.GetMarketPrice(ctx, id) + if err != nil { + k.Logger(ctx).Error( + "failed to get market price for streaming", + "market id", id, + "error", err, + ) + } + return types.StreamPriceUpdate{ + MarketId: id, + Price: price, + Snapshot: snapshot, + } +} diff --git a/protocol/x/prices/types/streaming.pb.go b/protocol/x/prices/types/streaming.pb.go new file mode 100644 index 0000000000..64dedb5aee --- /dev/null +++ b/protocol/x/prices/types/streaming.pb.go @@ -0,0 +1,405 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dydxprotocol/prices/streaming.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// StreamPriceUpdate provides information on a price update. +type StreamPriceUpdate struct { + // The `Id` of the `Market`. + MarketId uint32 `protobuf:"varint,1,opt,name=market_id,json=marketId,proto3" json:"market_id,omitempty"` + // The updated price. + Price MarketPrice `protobuf:"bytes,2,opt,name=price,proto3" json:"price"` + // Snapshot indicates if the response is from a snapshot of the price. + Snapshot bool `protobuf:"varint,3,opt,name=snapshot,proto3" json:"snapshot,omitempty"` +} + +func (m *StreamPriceUpdate) Reset() { *m = StreamPriceUpdate{} } +func (m *StreamPriceUpdate) String() string { return proto.CompactTextString(m) } +func (*StreamPriceUpdate) ProtoMessage() {} +func (*StreamPriceUpdate) Descriptor() ([]byte, []int) { + return fileDescriptor_4061dbad169b98fa, []int{0} +} +func (m *StreamPriceUpdate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StreamPriceUpdate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StreamPriceUpdate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StreamPriceUpdate) XXX_Merge(src proto.Message) { + xxx_messageInfo_StreamPriceUpdate.Merge(m, src) +} +func (m *StreamPriceUpdate) XXX_Size() int { + return m.Size() +} +func (m *StreamPriceUpdate) XXX_DiscardUnknown() { + xxx_messageInfo_StreamPriceUpdate.DiscardUnknown(m) +} + +var xxx_messageInfo_StreamPriceUpdate proto.InternalMessageInfo + +func (m *StreamPriceUpdate) GetMarketId() uint32 { + if m != nil { + return m.MarketId + } + return 0 +} + +func (m *StreamPriceUpdate) GetPrice() MarketPrice { + if m != nil { + return m.Price + } + return MarketPrice{} +} + +func (m *StreamPriceUpdate) GetSnapshot() bool { + if m != nil { + return m.Snapshot + } + return false +} + +func init() { + proto.RegisterType((*StreamPriceUpdate)(nil), "dydxprotocol.prices.StreamPriceUpdate") +} + +func init() { + proto.RegisterFile("dydxprotocol/prices/streaming.proto", fileDescriptor_4061dbad169b98fa) +} + +var fileDescriptor_4061dbad169b98fa = []byte{ + // 250 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4e, 0xa9, 0x4c, 0xa9, + 0x28, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0x2f, 0x28, 0xca, 0x4c, 0x4e, 0x2d, 0xd6, + 0x2f, 0x2e, 0x29, 0x4a, 0x4d, 0xcc, 0xcd, 0xcc, 0x4b, 0xd7, 0x03, 0xcb, 0x08, 0x09, 0x23, 0x2b, + 0xd2, 0x83, 0x28, 0x92, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x0b, 0xea, 0x83, 0x58, 0x10, 0xa5, + 0x52, 0x6a, 0xd8, 0xcc, 0xcb, 0x4d, 0x2c, 0xca, 0x4e, 0x2d, 0x89, 0x07, 0xf3, 0x20, 0xea, 0x94, + 0xba, 0x18, 0xb9, 0x04, 0x83, 0xc1, 0xd6, 0x04, 0x80, 0x44, 0x43, 0x0b, 0x52, 0x12, 0x4b, 0x52, + 0x85, 0xa4, 0xb9, 0x38, 0xa1, 0x6a, 0x33, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x83, 0x38, + 0x20, 0x02, 0x9e, 0x29, 0x42, 0x36, 0x5c, 0xac, 0x60, 0x13, 0x24, 0x98, 0x14, 0x18, 0x35, 0xb8, + 0x8d, 0x14, 0xf4, 0xb0, 0xb8, 0x4a, 0xcf, 0x17, 0xac, 0x1a, 0x6c, 0xa6, 0x13, 0xcb, 0x89, 0x7b, + 0xf2, 0x0c, 0x41, 0x10, 0x4d, 0x42, 0x52, 0x5c, 0x1c, 0xc5, 0x79, 0x89, 0x05, 0xc5, 0x19, 0xf9, + 0x25, 0x12, 0xcc, 0x0a, 0x8c, 0x1a, 0x1c, 0x41, 0x70, 0xbe, 0x53, 0xd0, 0x89, 0x47, 0x72, 0x8c, + 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, + 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x59, 0xa4, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, + 0xe7, 0xea, 0xa3, 0xf8, 0xac, 0xcc, 0x44, 0x37, 0x39, 0x23, 0x31, 0x33, 0x4f, 0x1f, 0x2e, 0x52, + 0x01, 0xf3, 0x6d, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0x58, 0xc2, 0x18, 0x10, 0x00, 0x00, + 0xff, 0xff, 0xc4, 0xc9, 0xfb, 0xd0, 0x61, 0x01, 0x00, 0x00, +} + +func (m *StreamPriceUpdate) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StreamPriceUpdate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StreamPriceUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Snapshot { + i-- + if m.Snapshot { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + { + size, err := m.Price.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintStreaming(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.MarketId != 0 { + i = encodeVarintStreaming(dAtA, i, uint64(m.MarketId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintStreaming(dAtA []byte, offset int, v uint64) int { + offset -= sovStreaming(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *StreamPriceUpdate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MarketId != 0 { + n += 1 + sovStreaming(uint64(m.MarketId)) + } + l = m.Price.Size() + n += 1 + l + sovStreaming(uint64(l)) + if m.Snapshot { + n += 2 + } + return n +} + +func sovStreaming(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozStreaming(x uint64) (n int) { + return sovStreaming(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *StreamPriceUpdate) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStreaming + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StreamPriceUpdate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StreamPriceUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MarketId", wireType) + } + m.MarketId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStreaming + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MarketId |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStreaming + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStreaming + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthStreaming + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Snapshot", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStreaming + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Snapshot = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipStreaming(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthStreaming + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipStreaming(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStreaming + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStreaming + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStreaming + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthStreaming + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupStreaming + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthStreaming + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthStreaming = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowStreaming = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupStreaming = fmt.Errorf("proto: unexpected end of group") +) diff --git a/protocol/x/subaccounts/keeper/subaccount.go b/protocol/x/subaccounts/keeper/subaccount.go index a047d9e2c9..f195e2dbf3 100644 --- a/protocol/x/subaccounts/keeper/subaccount.go +++ b/protocol/x/subaccounts/keeper/subaccount.go @@ -8,6 +8,7 @@ import ( "time" streamingtypes "github.com/dydxprotocol/v4-chain/protocol/streaming/types" + assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -825,3 +826,40 @@ func (k Keeper) GetAllRelevantPerpetuals( func (k Keeper) GetFullNodeStreamingManager() streamingtypes.FullNodeStreamingManager { return k.streamingManager } + +// GetInsuranceFundBalance returns the current balance of the specific insurance fund based on the +// perpetual (in quote quantums). +// This calls the Bank Keeper’s GetBalance() function for the Module Address of the insurance fund. +func (k Keeper) GetInsuranceFundBalance(ctx sdk.Context, perpetualId uint32) (balance *big.Int) { + usdcAsset, exists := k.assetsKeeper.GetAsset(ctx, assettypes.AssetUsdc.Id) + if !exists { + panic("GetInsuranceFundBalance: Usdc asset not found in state") + } + insuranceFundAddr, err := k.perpetualsKeeper.GetInsuranceFundModuleAddress(ctx, perpetualId) + if err != nil { + return nil + } + insuranceFundBalance := k.bankKeeper.GetBalance( + ctx, + insuranceFundAddr, + usdcAsset.Denom, + ) + + // Return as big.Int. + return insuranceFundBalance.Amount.BigInt() +} + +func (k Keeper) GetCrossInsuranceFundBalance(ctx sdk.Context) (balance *big.Int) { + usdcAsset, exists := k.assetsKeeper.GetAsset(ctx, assettypes.AssetUsdc.Id) + if !exists { + panic("GetCrossInsuranceFundBalance: Usdc asset not found in state") + } + insuranceFundBalance := k.bankKeeper.GetBalance( + ctx, + perptypes.InsuranceFundModuleAddress, + usdcAsset.Denom, + ) + + // Return as big.Int. + return insuranceFundBalance.Amount.BigInt() +} diff --git a/protocol/x/subaccounts/keeper/subaccount_test.go b/protocol/x/subaccounts/keeper/subaccount_test.go index 1eb7141fda..0c28eafd95 100644 --- a/protocol/x/subaccounts/keeper/subaccount_test.go +++ b/protocol/x/subaccounts/keeper/subaccount_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "errors" "math" "math/big" "strconv" @@ -6131,3 +6132,129 @@ func TestGetAllRelevantPerpetuals_Deterministic(t *testing.T) { }) } } + +func TestGetInsuranceFundBalance(t *testing.T) { + tests := map[string]struct { + // Setup + assets []asstypes.Asset + insuranceFundBalance *big.Int + perpetualId uint32 + perpetual *perptypes.Perpetual + + // Expectations. + expectedInsuranceFundBalance *big.Int + expectedError error + }{ + "can get zero balance": { + assets: []asstypes.Asset{ + *constants.Usdc, + }, + perpetualId: 0, + insuranceFundBalance: new(big.Int), + expectedInsuranceFundBalance: big.NewInt(0), + }, + "can get positive balance": { + assets: []asstypes.Asset{ + *constants.Usdc, + }, + perpetualId: 0, + insuranceFundBalance: big.NewInt(100), + expectedInsuranceFundBalance: big.NewInt(100), + }, + "can get greater than MaxUint64 balance": { + assets: []asstypes.Asset{ + *constants.Usdc, + }, + perpetualId: 0, + insuranceFundBalance: new(big.Int).Add( + new(big.Int).SetUint64(math.MaxUint64), + new(big.Int).SetUint64(math.MaxUint64), + ), + expectedInsuranceFundBalance: new(big.Int).Add( + new(big.Int).SetUint64(math.MaxUint64), + new(big.Int).SetUint64(math.MaxUint64), + ), + }, + "can get zero balance - isolated market": { + assets: []asstypes.Asset{ + *constants.Usdc, + }, + perpetualId: 3, // Isolated market. + insuranceFundBalance: new(big.Int), + expectedInsuranceFundBalance: big.NewInt(0), + }, + "can get positive balance - isolated market": { + assets: []asstypes.Asset{ + *constants.Usdc, + }, + perpetualId: 3, // Isolated market. + insuranceFundBalance: big.NewInt(100), + expectedInsuranceFundBalance: big.NewInt(100), + }, + "panics when asset not found in state": { + assets: []asstypes.Asset{}, + perpetualId: 0, + expectedError: errors.New("GetInsuranceFundBalance: Usdc asset not found in state"), + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + // Setup keeper state. + ctx, keeper, pricesKeeper, perpetualsKeeper, _, bankKeeper, assetsKeeper, _, _, _, _ := + keepertest.SubaccountsKeepers(t, true) + + // Create the default markets. + keepertest.CreateTestMarkets(t, ctx, pricesKeeper) + + // Create liquidity tiers. + keepertest.CreateTestLiquidityTiers(t, ctx, perpetualsKeeper) + + keepertest.CreateTestPerpetuals(t, ctx, perpetualsKeeper) + + for _, a := range tc.assets { + _, err := assetsKeeper.CreateAsset( + ctx, + a.Id, + a.Symbol, + a.Denom, + a.DenomExponent, + a.HasMarket, + a.MarketId, + a.AtomicResolution, + ) + require.NoError(t, err) + } + + insuranceFundAddr, err := perpetualsKeeper.GetInsuranceFundModuleAddress(ctx, tc.perpetualId) + require.NoError(t, err) + if tc.insuranceFundBalance != nil && tc.insuranceFundBalance.Cmp(big.NewInt(0)) != 0 { + err := bank_testutil.FundAccount( + ctx, + insuranceFundAddr, + sdk.Coins{ + sdk.NewCoin(asstypes.AssetUsdc.Denom, sdkmath.NewIntFromBigInt(tc.insuranceFundBalance)), + }, + *bankKeeper, + ) + require.NoError(t, err) + } + + if tc.expectedError != nil { + require.PanicsWithValue( + t, + tc.expectedError.Error(), + func() { + keeper.GetInsuranceFundBalance(ctx, tc.perpetualId) + }, + ) + } else { + require.Equal( + t, + tc.expectedInsuranceFundBalance, + keeper.GetInsuranceFundBalance(ctx, tc.perpetualId), + ) + } + }) + } +} diff --git a/protocol/x/subaccounts/keeper/transfer.go b/protocol/x/subaccounts/keeper/transfer.go index 52ffedce14..5271d06454 100644 --- a/protocol/x/subaccounts/keeper/transfer.go +++ b/protocol/x/subaccounts/keeper/transfer.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "math/big" errorsmod "cosmossdk.io/errors" @@ -11,6 +12,7 @@ import ( "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" revsharetypes "github.com/dydxprotocol/v4-chain/protocol/x/revshare/types" "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" ) @@ -503,3 +505,89 @@ func (k Keeper) TransferFundsFromSubaccountToSubaccount( types.Transfer, ) } + +// TransferIsolatedInsuranceFundToCross transfers funds from an isolated perpetual's +// insurance fund to the cross-perpetual insurance fund. +// Note: This uses the `x/bank` keeper and modifies `x/bank` state. +func (k Keeper) TransferIsolatedInsuranceFundToCross(ctx sdk.Context, perpetualId uint32) error { + // Validate perpetual exists + if _, err := k.perpetualsKeeper.GetPerpetual(ctx, perpetualId); err != nil { + return err + } + + isolatedInsuranceFundBalance := k.GetInsuranceFundBalance(ctx, perpetualId) + + // Skip if balance is zero + if isolatedInsuranceFundBalance.Sign() == 0 { + return nil + } + + _, exists := k.assetsKeeper.GetAsset(ctx, assettypes.AssetUsdc.Id) + if !exists { + return fmt.Errorf("USDC asset not found in state") + } + + _, coinToTransfer, err := k.assetsKeeper.ConvertAssetToCoin( + ctx, + assettypes.AssetUsdc.Id, + isolatedInsuranceFundBalance, + ) + if err != nil { + return err + } + + isolatedInsuranceFundAddr, err := k.perpetualsKeeper.GetInsuranceFundModuleAddress(ctx, perpetualId) + if err != nil { + return err + } + + crossInsuranceFundAddr := perptypes.InsuranceFundModuleAddress + + return k.bankKeeper.SendCoins( + ctx, + isolatedInsuranceFundAddr, + crossInsuranceFundAddr, + []sdk.Coin{coinToTransfer}, + ) +} + +// TransferIsolatedCollateralToCross transfers the collateral balance from an isolated perpetual's +// collateral pool to the cross-margin collateral pool. This is used during the upgrade process +// from isolated perpetuals to cross-margin. +// Note: This uses the `x/bank` keeper and modifies `x/bank` state. +func (k Keeper) TransferIsolatedCollateralToCross(ctx sdk.Context, perpetualId uint32) error { + // Validate perpetual exists + if _, err := k.perpetualsKeeper.GetPerpetual(ctx, perpetualId); err != nil { + return err + } + + isolatedCollateralPoolAddr, err := k.GetCollateralPoolFromPerpetualId(ctx, perpetualId) + if err != nil { + return err + } + + crossCollateralPoolAddr := types.ModuleAddress + + usdcAsset, exists := k.assetsKeeper.GetAsset(ctx, assettypes.AssetUsdc.Id) + if !exists { + panic("TransferIsolatedCollateralToCross: Usdc asset not found in state") + } + + isolatedCollateralPoolBalance := k.bankKeeper.GetBalance( + ctx, + isolatedCollateralPoolAddr, + usdcAsset.Denom, + ) + + // Skip if balance is zero + if isolatedCollateralPoolBalance.IsZero() { + return nil + } + + return k.bankKeeper.SendCoins( + ctx, + isolatedCollateralPoolAddr, + crossCollateralPoolAddr, + []sdk.Coin{isolatedCollateralPoolBalance}, + ) +} diff --git a/protocol/x/subaccounts/types/expected_keepers.go b/protocol/x/subaccounts/types/expected_keepers.go index a9e3f88f94..1a4a97ced3 100644 --- a/protocol/x/subaccounts/types/expected_keepers.go +++ b/protocol/x/subaccounts/types/expected_keepers.go @@ -6,6 +6,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" blocktimetypes "github.com/dydxprotocol/v4-chain/protocol/x/blocktime/types" perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types" pricestypes "github.com/dydxprotocol/v4-chain/protocol/x/prices/types" @@ -28,6 +29,13 @@ type AssetsKeeper interface { coin sdk.Coin, err error, ) + GetAsset( + ctx sdk.Context, + id uint32, + ) ( + val assettypes.Asset, + exists bool, + ) } type PerpetualsKeeper interface { @@ -91,6 +99,7 @@ type BankKeeper interface { ) error SendCoinsFromModuleToModule(ctx context.Context, senderModule, recipientModule string, amt sdk.Coins) error SendCoins(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error + GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin } type BlocktimeKeeper interface { diff --git a/protocol/x/vault/keeper/withdraw.go b/protocol/x/vault/keeper/withdraw.go index 436effd9d6..5c63a01547 100644 --- a/protocol/x/vault/keeper/withdraw.go +++ b/protocol/x/vault/keeper/withdraw.go @@ -290,7 +290,7 @@ func (k Keeper) RedeemFromMainAndSubVaults( _, perpetual, marketParam, marketPrice, err := k.GetVaultClobPerpAndMarket(ctx, *vaultId) if err != nil { - if simulate { + if !simulate { log.DebugLog( ctx, "Megavault withdrawal: failed to get perpetual and market. Skipping this vault", @@ -299,20 +299,12 @@ func (k Keeper) RedeemFromMainAndSubVaults( "Error", err, ) - } else { - log.ErrorLogWithError( - ctx, - "Megavault withdrawal: error when getting perpetual and market. Skipping this vault", - err, - "Vault ID", - vaultId, - ) } continue } leverage, equity, err := k.GetVaultLeverageAndEquity(ctx, *vaultId, &perpetual, &marketPrice) if err != nil { - if simulate { + if !simulate { log.DebugLog( ctx, "Megavault withdrawal: failed to get vault leverage and equity. Skipping this vault", @@ -321,14 +313,6 @@ func (k Keeper) RedeemFromMainAndSubVaults( "Error", err, ) - } else { - log.ErrorLogWithError( - ctx, - "Megavault withdrawal: error when getting vault leverage and equity. Skipping this vault", - err, - "Vault ID", - vaultId, - ) } continue } @@ -343,7 +327,7 @@ func (k Keeper) RedeemFromMainAndSubVaults( &marketParam, ) if err != nil { - if simulate { + if !simulate { log.DebugLog( ctx, "Megavault withdrawal: failed to get vault withdrawal slippage. Skipping this vault", @@ -352,14 +336,6 @@ func (k Keeper) RedeemFromMainAndSubVaults( "Error", err, ) - } else { - log.ErrorLogWithError( - ctx, - "Megavault withdrawal: error when getting vault withdrawal slippage. Skipping this vault", - err, - "Vault ID", - vaultId, - ) } continue } @@ -371,7 +347,7 @@ func (k Keeper) RedeemFromMainAndSubVaults( quantumsToTransfer := new(big.Int).Quo(redeemedFromSubVault.Num(), redeemedFromSubVault.Denom()) if quantumsToTransfer.Sign() <= 0 || !quantumsToTransfer.IsUint64() { - if simulate { + if !simulate { log.DebugLog( ctx, "Megavault withdrawal: quantums to transfer is invalid. Skipping this vault", @@ -380,15 +356,6 @@ func (k Keeper) RedeemFromMainAndSubVaults( "Quantums", quantumsToTransfer, ) - } else { - log.ErrorLog( - ctx, - "Megavault withdrawal: quantums to transfer is invalid. Skipping this vault", - "Vault ID", - vaultId, - "Quantums", - quantumsToTransfer, - ) } continue }